How to save score game with node.js




 

After some posts which talked about node.js, we need to replace in the video game context with a simple case : save user score game from mysql, and node.js user library posts.


 

To do before

mysql server installed;
– know what is node.js (see post Comprendre node.js);
node.js installed (see post Installer node.js sous Windows);
– read post mysql access from node.js (update 04/20/2014);
– read post How to create node.js library;
– read post node.js socket.io par l’exemple.

 

The main

Imagine that you had made a video game (no matter what video game) and you want to save the player best score game.

From an url with player parameters in json format, that calls a node.js script.
This script checks if the specified player in parameter was created in database.

If it was, it compare score in database with received score. If received score is better than score in database, it update player score. In other case, the script does nothing.

If it wasn’t, it creates it with received score.

Just email, score date and score are saved, anything else.

For example and to post email and score, you need to use a gui with button and two input text : first for email player, second for score player.

You need for this example :
– a mysql database to save score and mysql library; (see in post How to create node.jslibrary;
socket.io library to call node.js script;
– and node.js express library to set a simple http server to expose url access to gui to post email and score.

 

mysql database

You must create a database with table for players score.

In command line, connect to your mysql server : replace server, user and password by your own :

mysql -hserver -uuser -ppassword

Create a new database named game :

create database game;

Before to create the table to save all scores, use the database created above :

use game;

And create table in database :

CREATE TABLE IF NOT EXISTS `scores` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(128) NOT NULL,
  `score` int(11) NOT NULL,
  `date` date NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

This table has an unique id, email player, score and date.

 

The project initiliatization

Where you want, create a new folder scoreGame dedicated to the project.

In command line, go to the project folder and execute next command to install mysql node.js library :

npm install mysql

You must see like this :

npm http GET https://registry.npmjs.org/mysql
npm http 304 https://registry.npmjs.org/mysql
npm http GET https://registry.npmjs.org/require-all/0.0.3
npm http GET https://registry.npmjs.org/bignumber.js/1.0.1
npm http GET https://registry.npmjs.org/readable-stream
npm http 304 https://registry.npmjs.org/require-all/0.0.3
npm http 304 https://registry.npmjs.org/bignumber.js/1.0.1
npm http 304 https://registry.npmjs.org/readable-stream
npm http GET https://registry.npmjs.org/string_decoder
npm http GET https://registry.npmjs.org/core-util-is
npm http GET https://registry.npmjs.org/debuglog/0.0.2
npm http 304 https://registry.npmjs.org/core-util-is
npm http 304 https://registry.npmjs.org/string_decoder
npm http 304 https://registry.npmjs.org/debuglog/0.0.2
mysql@2.1.0 node_modules\mysql
├── require-all@0.0.3
├── readable-stream@1.1.11 (debuglog@0.0.2, string_decoder@0.10.25-1, core-util-is@1.0.1)
└── bignumber.js@1.0.1

At the project folder, execute next commandto install socket.io library :

npm install socket.io

You must see like this :

npm http GET https://registry.npmjs.org/socket.io
npm http 200 https://registry.npmjs.org/socket.io
npm http GET https://registry.npmjs.org/socket.io/-/socket.io-1.0.6.tgz
npm http 200 https://registry.npmjs.org/socket.io/-/socket.io-1.0.6.tgz
npm http GET https://registry.npmjs.org/has-binary-data
npm http GET https://registry.npmjs.org/socket.io-adapter
npm http GET https://registry.npmjs.org/debug
npm http GET https://registry.npmjs.org/socket.io-client
npm http GET https://registry.npmjs.org/engine.io
npm http GET https://registry.npmjs.org/socket.io-parser
npm http 200 https://registry.npmjs.org/debug
npm http GET https://registry.npmjs.org/debug/-/debug-0.7.4.tgz
....
socket.io@1.0.6 node_modules\socket.io
├── debug@0.7.4
├── has-binary-data@0.1.1 (isarray@0.0.1)
├── socket.io-adapter@0.2.0 (socket.io-parser@2.1.2)
├── socket.io-parser@2.2.0 (isarray@0.0.1, emitter@1.0.1, json3@3.2.6)
├── engine.io@1.3.1 (base64id@0.1.0, debug@0.6.0, engine.io-parser@1.0.6, ws@0.4.31)
└── socket.io-client@1.0.6 (to-array@0.1.3, indexof@0.0.1, component-bind@1.0.0,
 object-component@0.0.3, component-emitter@1.1.2, parseuri@0.0.2, engine.io-client@1.3.1)

Like above to install express library :

npm install express

And you must see like this :

npm http GET https://registry.npmjs.org/express
npm http 200 https://registry.npmjs.org/express
npm http GET https://registry.npmjs.org/express/-/express-4.4.5.tgz
npm http 200 https://registry.npmjs.org/express/-/express-4.4.5.tgz
npm http GET https://registry.npmjs.org/methods
npm http GET https://registry.npmjs.org/accepts
npm http GET https://registry.npmjs.org/range-parser
npm http GET https://registry.npmjs.org/escape-html
npm http GET https://registry.npmjs.org/serve-static
npm http GET https://registry.npmjs.org/fresh
npm http GET https://registry.npmjs.org/cookie-signature
npm http GET https://registry.npmjs.org/vary
npm http GET https://registry.npmjs.org/proxy-addr
npm http GET https://registry.npmjs.org/parseurl
npm http GET https://registry.npmjs.org/buffer-crc32
npm http GET https://registry.npmjs.org/utils-merge
npm http GET https://registry.npmjs.org/qs
npm http GET https://registry.npmjs.org/merge-descriptors
...
express@4.4.5 node_modules\express
├── parseurl@1.0.1
├── utils-merge@1.0.0
├── cookie@0.1.2
├── merge-descriptors@0.0.2
├── cookie-signature@1.0.4
├── vary@0.1.0
├── fresh@0.2.2
├── qs@0.6.6
├── escape-html@1.0.1
├── range-parser@1.0.0
├── methods@1.0.1
├── serve-static@1.2.3
├── buffer-crc32@0.2.3
├── path-to-regexp@0.1.2
├── debug@1.0.2 (ms@0.6.2)
├── proxy-addr@1.0.1 (ipaddr.js@0.1.2)
├── accepts@1.0.6 (negotiator@0.4.7, mime-types
├── type-is@1.2.1 (mime-types@1.0.0)
└── send@0.4.3 (mime@1.2.11, finished@1.2.2)

 

Gui to post email and score

In the scoreGame folder, create a new file named scoreGame.html. Html code to add to this file is very simple :

<html>
 <body>
  SAVE SCORE WITH NODE.JS AND SOCKET.IO<br>
  <input type="text" id="email"><br>
  <input type="text" id="score"><br>
  <input type="button" id="saveScoreButton" value="Save Score">
 </body>
</html>

Now, you can add javascript code to submit email and score.

You need to declare 3 variables ihm from gui object : button and 2 input text.
You must initialize on page loading by javascript load event :

  var email;
  var score;
  var saveScoreButton;
 
  window.addEventListener("load", function() {
    email = document.getElementById("email");
    score = document.getElementById("score");
    saveScoreButton= document.getElementById("saveScoreButton");
  });

All of these factors, for triggering an action on click button you must use javascript click event.

The assigned action send data (email and score) with a socket message using node.js socket.io library.

The message is named saveScore. This name is very important because it wil be used to capture sended data.

All of this are in an autoexecute function to park created code to existing code in html page.

 ( function() {
   var email;
   var score;
   var saveScoreButton;
 
   var sendMessage = function() {
     var socket = io.connect('http://localhost:9090');
     socket.emit('saveScore',{'email':email.value,'score':score.value});
   };
 
   window.addEventListener("load", function() {
     email = document.getElementById("email");
     score = document.getElementById("score");
     saveScoreButton= document.getElementById("saveScoreButton");
     saveScoreButton.addEventListener("click", sendMessage );
   });
 })();

This is not enough to run gui : it misses library import of socket.io.

<script src="http://node_js_server_address:9090/socket.io/socket.io.js"></script>

The used port (9090) in url is the target port to run request. The choice of this port is wanted and it’s on server.

 

node.js script to save the scores

You need the db.js library created ine the post How to create node.js library.

Add to this library 2 new methods :
– the first for adding data in database (case when the player doesn’t exist);
– the second for updating data in database (case when the player exists).

All this using node.js mysql library.

method to add data :

executeInsertQuery : function( insertQuery ) {
  this.mySqlClient.query(
    insertQuery,
    function result(error, info) {
      if (error) {
        db.close();
        return error;
      }
      return info.insertId;
    }
  );
}

method to update :

executeUpdateQuery : function( updateQuery ) {
  this.mySqlClient.query(
    updateQuery,
    function result(error) {
      if (error) {
        db.close();
        return error;
      }
      return;
    }
  );
}

The script for saving makes 2 tasks :
– make gui to public by nodes.js express library way;
– wait messages on 9090 port.

 

expose gui

It’s enough to create an express object to :
– listen on port 80 for http request;
– serve gui files : scoreGame.html on the same port.

var express = require('express');

// serveur html
var server= express();
server.listen(80);
server.get('/scoreGame.html', function(request, response) {
 response.sendfile('./scoreGame.html');
});

When /scoreGame.html is calling, the scoreGame.html file is sended to http client.

You can send another file of /scoreGame.html : the sendfile method do this. Choose le file you want to send.

 

Accept socket.io messages

The save work begins here : save score if the email doesn’t exist add the score, in other case update it.

On message reception, you must verify if the email exists and depending on the case add or update score.

The first thing to do is to instanciate a socket.io object to listen on port 9090 :

var io = require("socket.io");
var sockets = io.listen(9090);

The second thing to do is to make a server responding on message saveScore sended by gui :

// serveur socket.io
sockets.on('connection', function (socket) {
  socket.on('saveScore', function (data) {
    // actions executed when a message is received
  });
});

For more details on node.js socket.io library, go to the post node.js socket.io par l’exemple.

All that remains for you now is to verify if the email exists in database by using db.js library: you must intanciate db.js object like this :

var db = require('./db.js');

With this object, you can connect to database, run the sql query to verify email and in last run the sql query to add or update score.

The sql query to search email in database :

select id,email,score from scores where email='email réceptionné par le socket'

The sql query for adding score in database :

insert into scores (email,score,date) values('email from the socket','score réceptionné par le socket',NOW())

The sql query to update score in database :

update scores set score=score_réceptionné_par_le_socket,date=NOW() where email='email réceptionné par le socket' 

On message accepting, you must :
– connect to database;
– run sql query for searching;
– run exécuter selon les cas, sql query to add or update.

Add or update run by a callback function specified in the executeSelectQuery method parameter of db object. Here the callback function is saveScore.

Call this function saveScore :

// serveur socket.io
sockets.on('connection', function (socket) {
  socket.on('saveScore', function (data) {
    db.connect('mysql_host','mysql_user','mysql_password','game');
    var sqlSelect = "select id,email,score from scores where email='" + data.email + "'";
    db.executeSelectQuery(sqlSelect, saveScore);
  });
});

Now, you need to implement this function : add or update score.

This function must :
– insert player data if the email doesn’t exist;
– update data player if received score is better than score in database.

This function shall have :
– the existing data (from results);
– the received data (from data).

This function needs 2 parameters :
– the existing data (from results);
– the received data (from data).

var saveScore = function(results, data) {
  if ( empty(results)  ) {
    var sqlInsert = "insert into scores (email,score,date) values('" + data.email + "'," + data.score + ",NOW()) ";
    db.executeInsertQuery(sqlInsert);
  } else {
    if ( results[0].score < data.score ) {
      var sqlUpdate = "update scores set score=" + data.score + ",date=NOW() where email='" + data.email + "' ";
      db.executeUpdateQuery(sqlUpdate);    
    }
  }
  db.close();
}

You can see a used new function : empty that test a data structure is empty.

var empty = function empty(object) {
  for (var i in object) 
    if (object.hasOwnProperty(i))
      return false;
 
  return true;
}

Call the function saveScore needs to have the existing data ans the received data.

You must modify the call of executeSelectQuery, from :

db.executeSelectQuery(sqlSelect, enregistrerScore);

to

db.executeSelectQuery(sqlSelect, enregistrerScore, data);

You must modify too executeSelectQuery implementation in db.js library :

executeSelectQuery : function( selectQuery, callbackResultFunction, data ) {
  this.mySqlClient.query(
    selectQuery, function( error, results ) {
      if ( error ) {
        db.close();
        return error;
      } else {
	  callbackResultFunction(results, data);
      }
    }
  );
},

Now, it’s time to test.

 

Test

In command line, run scoreGame.js script from project folder :

node scoreGame.js

Go to http://localhost/scoreGame.html for viewing gui :

nodejsSaveScore

You can donwload source code at : scoreGame.zip.

 

Comments, improvement, idea : let me know. If this post has been helpful, make comments on your favorite social networks.

 

Posté dans html5, node.jsTaggé mysql, node.js, socket.io  |  Laisser un commentaire

Répondre

*