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.