Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Sunday, April 19, 2009

Save scores from your JavaScript game in your database

This is a request from a friend of mine. So I thought since I have no time to write my blog, since I am always helping people, maybe I should just write their help in a blog format. It is a great system as it ensures I will have at least one guaranteed reader. (Hello Gabriel.)

Anyways this is my first real blog, and I am not sure how to format everything correctly. Bear with me folks.

First off I had to write a JavaScript game in which to store the result for my test. Since I did not want to spend a lot of time doing the prototype I made it a simple guess the number from 1-100 game.

I am using prototype here, if you can not tell, and of course it get's it's own file.
guessing_game.js

var num_guesses = 0;
var magic_num = 0;

function playGame() {
  $('guess_count').value = 0;
  $('guess_count_display').innerHTML = "0";
  magic_num = newRandomNum();
}

function testForWin() {
  num_guesses++;
  $('guess_count').value = num_guesses;
  $('guess_count_display').innerHTML = num_guesses;
  guess = parseInt($('guess').value)
  if( guess <> 100 )
    $('flash_area').innerHTML = 'You are guessing out of range... Pick a number 1-100.';
  else if(magic_num > guess )
    $('flash_area').innerHTML = "Nope. Guess higher than " + guess + ".";
  else if(magic_num < guess )
    $('flash_area').innerHTML = "Nope. Guess lower than " + guess + ".";
  else if(magic_num == guess)
    $('flash_area').innerHTML = 'You won in only ' + num_guesses + ' guesses!';
  else
    $('flash_area').innerHTML = 'I am confused how you got to this place :).';
}

function newRandomNum() {
  return Math.floor(Math.random()*100) + 1;
}

magic_num = newRandomNum();

I made the random number after load so that the answer is not in the source code. That is important if you want no cheaters. :)

The Guessing game HTML is very simple also:
guessing_game.html.erb

<script type="text/javascript" src="/javascripts/guessing_game.js"></script>
<h1>Generic Guessing Game</h1>
guess a number 1-100
<div id="flash_area"></div>

<div id="game_form">
<%= hidden_field_tag "player_id", @player_id %>
<%= hidden_field_tag "guess_count", 0 %>
Number of Guesses so far: <span id="guess_count_display">0</span><br/>
Guess: <%= text_field_tag "guess", "", :size => 4 %>
</div>

<input type="button" value="Guess" onclick="testForWin();"/>

Not too much fancy in this code either. Just a div with form elements. including my javascript file. I have a hidden field named guess count (this is the score), and I am storing the player_id in an hidden field to make it easy to find the player when I save the game result.

So now we have a working, although rather boring, guessing game. (you would get an error of course if you do not set the @player_id variable.)

So let's set up the controller.
game_controller.rb

class GameController < ApplicationController

  def guessing_game
    # Get your player_id from Player or User Model etc.
    # Just using 100 for now.
    @player_id = 100
  end

  def save_guessing_game_result
    if params[:player_id] && params[:guess_count] && params[:guess_count].to_i > 0
      GameResult.create(:player_id => params[:player_id], :score => params[:guess_count].to_i)
      render :text => "Saved Game Result. Player ID: #{params[:player_id]}; guesses: #{params[:guess_count]}"
    else
      render :text => "Error Saving Results"
    end
  end

end

Hopefully you had a GameResult model. This example assumes that much. Now our game has the tools to save. We just have to tell it when and how to save. That will mean having a couple changes in the JavaScript file.

We have to change the method checkForWin(), and I am adding my AJAX call in a second method to make it easy to read and understand.
guessing_game.js (changes)

...
function testForWin() {
  num_guesses++;
  $('guess_count').value = num_guesses;
  $('guess_count_display').innerHTML = num_guesses;
  guess = parseInt($('guess').value)
  if( guess < 1 || guess > 100 )
    $('flash_area').innerHTML = 'You are guessing out of range... Pick a number 1-100.';
  else if(magic_num > guess )
    $('flash_area').innerHTML = "Nope. Guess higher than " + guess + ".";
  else if(magic_num < guess )
    $('flash_area').innerHTML = "Nope. Guess lower than " + guess + ".";
  else if(magic_num == guess) {
    $('flash_area').innerHTML = 'You won! sending result to the server.';
    sendResultsToServer(); // this is where I call it (after a win)
  }
  else
    $('flash_area').innerHTML = 'I am confused how you got to this place :).';
}

// This is the new method to save the results
function sendResultsToServer() {
  new Ajax.Updater('flash_area', '/game/save_guessing_game_result', {asynchronous:true, evalScripts:true, parameters:Form.serialize('game_form')});
}
...

Do not forget to add the {twiddles} since the else if statement is multi-line now, in the testForWin() function. Let me explain the sendResultsToServer() function a little better.

sendResultsToServer() indepth

// 'flash_area' is where your response will be displayed (our message box)
// you can use '' also to not show any response, but I decided the user might
// want to know, in this example.

// '/game/save_guessing_game_result' is where the JavaScript is sending the message.
// i.e. out game controller and the save_guessing_game_result action.

// next is the properties hash
// Just ignore asynchronous:true, evalScripts:true for now.
// I should find out exactly what they do in the future and will let you know.
// They are just always used for me.

// last item in the properties hash is the parameters:
// Form.serialize('game_form')
// this is a great way to turn any div into a form (as far as the server cares)
// 'game_form' is the div with all my data in it.
// And will come to me in the params hash.

function sendResultsToServer() {
  new Ajax.Updater('flash_area', '/game/save_guessing_game_result', {asynchronous:true, evalScripts:true, parameters:Form.serialize('game_form')});
}


And we are done... Well we should be done. But if you are using Rails 2, we are not done yet. You would get an error: ActionController::InvalidAuthenticityToken. My quick work around was to just turn off the check in my AJAX action.

game_controller.rb (changes)

class GameController < ApplicationController
  protect_from_forgery :except => ["save_guessing_game_result"]
...


And now we have a JavaScript game that saves the results to the server upon completed games. Congratulations.

Wow, my first real blog. Seemed like a simple subject. I hope to get some more blog posts going soon.

Sunday, July 27, 2008

welcome to Cowboy on Rails

Cowboy on Rails is a new blog. My goal is to write one article a week about Ruby on Rails, AJAX, JavaScript and other Web 2.0 related subjects.

A little about me to get started.

I am first a husband and father. If I miss a week, we will just assume that is the reason.

I am a cowboy. I have broken many bones on many bulls. And my code is a little more cowboy-ish also. It is a little hardcore and stepping to and past limits. I am not afraid of trying new things, and love to learn new languages. My code is also compact, and effient, I like to write with the idea of speed in mind always.

I am a Ruby on Rails developer. I think that is my official job title, anyways. I have been a Ruby on Rails developer for over 2 years now. April 2006 was when I got my first taste. I work at RedPine Services. At RedPine Services we have created a business service that makes chiropractic offices more effient.

I am also a new Google AppEngine coder. Since I am new to Python also, there will be some Python and AppEngine posts on this blog also.

I am much more, but we are not here to learn about me, we are here to discover more about web 2.0 technologies.