Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
17. July 2012

 

One of the catches with a web application is finding a place to host it.  If you just have a couple static pages this is pretty simple, there area  few thousand different hosting companies that will serve your pages for a few dollars a month.  However, once you start talking about server side programmability, things get much more complicated.  In this case you generally need a dedicated server or at least, a shared server.  However, the recent move towards cloud computing gives you another option.

 

Such as Heroku.

 

We are now going to look at uploading our cocos2D JavaScript web application to Heroku.  First things first, you need to sign up.  Don’t worry, you don’t need to pay nor give them a credit card, the entry tier is free.

 

Now that you are signed up, we need to make a couple really small alterations to our project, don’t worry, both are pretty minor.  First create a file named package.json

{
    "name": "firstthis",
    "version": "0.0.1",
    "dependencies": {
        "express": "2.5.x"
    },
    "engines": {
        "node": "0.8.x",
        "npm":  "1.1.x"
    }
}

Package.json is a JSON format config file that tells Node what dependencies you have.  You need to tell it what libraries you need ( generally all the things you  “require”ed in code).  The second section is also very important, as it tells what version of Node you want to use.  This is very important with Heroku as if you do not specify a version, you will get Node 0.4.x, which isn’t compatible with our project.  When you run your Heroku app, package.json will determine what is installed.

 

You also need to create a file called Procfile ( with no extension ), like this:

web: node server.js

Think of this like a BAT or SH file that is run on Heroku’s servers when you run it.  You will see this in action shortly. 

 

Now that our application is configured and ready for Heroku, lets get the tools installed.  Head on over to the Heroku toolbelt page and install the version that is right for you.  They have a Windows, Linux and Mac version, all of which should follow basically the same instructions.  For this tutorial I will be using the Windows version, but you should be able to follow along without issue no matter what OS you run.

 

image

 

 

After install completes, open a command prompt ( or terminal… ) and type:

heroku login

Log in using the email address and password you signed up with. If prompted to create an SSH key, allow it.  If you need to generate an SSH key manually, you can do so with the following command:

ssh-keygen –t rsa –C [email protected]

You can then tell heroku to use this key with the command:

heroku keys:add

Now it’s time to set up a git repository, which is how we deploy to Heroku.  Don’t worry, its not all that scary.  Again, at the same command line, switch to your application directory ( this part is very important, make sure you cd to your application code directory ) and enter:

git init

git add .

git commit –m “This is a commit comment, put whatever you want”

This combination of commands creates a git repository, adds everything from the current directory and below to it, then commits the changes.  If you look in your directory, you will now notice a .git folder. 

 

Now lets create and deploy our app to heroku. First enter:

heroku create

git push heroku master

If prompted for a security question about trusting heroku, type yes.  These two lines essentially created the app on heroku’s servers, then pushed our git archive to heroku.  At this point, your code is now deployed to Heroku’s servers… almost there!

Now we fire up a copy of our app on their server.  This is where the Procfile we defined earlier comes in.  Essentially you are going to run the command you defined in web: in your Procfile, do this with the command:

heroku ps:scale web=1

Finally, since we are using express, we need to set an environment variable:

heroku config:add NODE_ENV=production

 

And your app is now deployed and live.

 

So… um… where is it?  Ah yeah… type:

heroku apps

image

These are your app server names.  In your case you will have just a single one right now.  Simply take this name and add .herokuapp.com to it.

 

For example, when you open http://radiant-planet-8015.herokuapp.com you see:

image

 

At this point we are running a cocos2D app, served by Node, hosted on Heroku!

 

You can try it out yourself, but I make no promises the server will still be running, so do not consider that URL permanent.  At this point you should be able to deploy your own app to Heroku.

 

The next part is now live.  In this section we will add the ability to populate our application with data.

General


13. July 2012

 

This is the first part of my adventure creating a simple game for my daughter

 

One of the catches with a JavaScript game, as you saw from this earlier tutorial, to take full advantage you need a client and a server.  However, once you want the server to start doing “stuff”, you want as much control over it as possible.  The advice “write your own!” is normally remarkably stupid, but with Node, it actually isn’t!  In fact, you can create a fully functioning server in only a couple lines of code.  If you are looking for a way to deploy an advanced JavaScript application, read on.

 

If you’ve never experienced Node before, basically it is a server side implementation of Google’s V8 Javascript engine, and a whole TON of plugins to do just about everything.  Perhaps the biggest selling point is, it allows you to work in both Javascript on the client and server.  It is also easy to deploy, massively asynchronous, scalable and frankly, kinda cool.  The first thing you are going to need to do is install it on your computer.  The install process is remarkably simple, although when you are done I would suggest adding node to your PATH environment variable if you are working on Windows.

 

Now that you have Node installed, let’s create a simple server.  Create a file called server.js like this:

 

var express = require('express'), server = express.createServer(); server.use('/cocos2d', express.static(__dirname + '/cocos2d') ); server.use('/cocosDenshion', express.static(__dirname + '/cocosDenshion') ); server.use('/classes', express.static(__dirname + '/classes') ); server.use('/resources', express.static(__dirname + '/resources') ); server.get('/', function(req,res){ res.sendfile('index.html'); console.log('Sent index.html'); }); server.get('/api/hello', function(req,res){ res.send('Hello Cruel World'); }); server.listen(process.env.PORT || 3000);

 

And… that’s it, a fully functioning web server.

 

That first line is the key, where we require(‘express’).  Express is the module that is doing the heavy lifting on the server side.

 

There is however a small amount of configuration you need to do.  You need to tell node to install the express module.  This is pretty simply done though, open a command prompt and navigate to your project directory, then type:

npm install express

 

npm is the node package manager, and it will download and configure your project to work with express.  Now that we are configured, lets get back to code.

 

The next four lines are defining a series of static routes.  Essentially, if a web request comes in to any of these paths  ( for example  http://localhost/cocos2d ), node will simply serve the files back to the requesting browser, just like IIS or Apache would.  These four lines will result in /cocos2d, /cocosDenshion, /classes and /resources folders having their files served, so when your HTML file requests /classes/cocos2d.js, the file will be returned.  This is how we will allow our user to download our scripts and resources.  In this particular, I am porting the class from this tutorial to run from Node, which is why we require a resources and cocosDenshion folder.

 

Next is a GET request handler for “/”.  In HTTP, there are two kinds of requests, GET ( urls ) and POST ( form submissions ).  In this line we are saying if someone requests our web root, our function is called, which simply sends the file index.html back.

 

A moment later, we set up another GET handler for the route (URL) /api/hello, which simply returns the string “Hello Cruel World”.  This is a very simple web service, and we will see it in action shortly.

 

Finally we start our server listening on port 3000, or whatever port the running environment forces us on, in case our host has such limitations.  At this point, we have a fully functioning web server. 

 

However, I made a few alterations to the last tutorial’s file layout to better be served by Node.  Our folder structure now looks like:

image

 

Don’t worry if you are missing a few folders ( .git and .idea for example ) or files ( package.json or Procfile ), we will covers those later.

 

I altered all the paths in cocos.js and MyFourthApp.js because cocos2d was moved to the classes folder.  Otherwise the code is pretty much unchanged from the last tutorial.  You can download the full source at the end of this post if you want to see the complete changes.

 

I did make a few small alterations though, beyond changing paths.  I added a reference to jQuery in index.html, like this:

<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script src="classes/cocos2d.js"></script>

 

I also added the following line to cocos2d.js:

else { cc.setup("gameCanvas"); jQuery.get("/api/hello", function(data,textStatus,jqXHR){ cc.Log(data); });

 

So what exactly is this line of code doing?

 

Remember earlier in server.js where we added a route handler for /api/hello?  Well this is about as simple a REST based web request as you can make.  This uses jQuery to make an AJAX call to our server, which returns the string “Hello Cruel World”, which we log to the console.   

 

Why?  Well, absolutely no reason… yet.  But this is a very primitive example of something we are going to do in more complexity later on.  We can do processing on our node based server, and handle it in our cocos2D client.  Through this mechanism we can make up for the limitations of client side Javascript, or enable server side functionality.  You can easily request data from a server without having to reload your page.

 

 

Now you can run your server.  Open a command prompt, navigate to your project directory and type node server.js.  If all went well, there should be no error messages.  Now open up a web browser and navigate to http://localhost:3000 like this:

image

 

Here is your cocos2D application hosted in a custom Node server viewed in a browser, and if you look at the JavaScript console, you will see the “Hello Cruel World” message logged by cocos, but returned asynchronously from the server.  To shut down your server, simply press CTRL + C.

 

 

At this point we have a working web server, capable of hosting a cocos2D application ( and replacing the need for WAMP completely ), making successful, if simple, web services calls between the client and server.

 

You can download the full project right here.

 

Next up, we will look into a problem many web developers face… where the heck am I going to put this thing???

 

EDIT:  Next part is now up.

Programming


13. July 2012

I have a bit of a project I need to undertake in real life, that overlaps nicely with this site, so I am documenting the process here.

 

 

The nutshell version, I have a toddler and she is having trouble with transitions.  People have suggestion a This Then board, in terms of “Do This” “Then that” will happen.  Its remarkably simple over all, it is pretty much two pieces of velcro on a piece of cardboard and a bunch of pictures that we can stick to it.  I was about to have to print off a ton of pictures, scale them down, stick velcro to them and it dawned on me… this calls for an App!

 

 

See, I have a ton of devices around this place…  PCs, a Mac, a Galaxy Note, S3, Transformer, Playbook, iPhone, iPod and even an iPad that my daughter has pretty much claimed as her own.  So it only makes sense to implement this an application.  That said, supporting all of these platforms would be a pretty epic pain in the butt.  Also, I have very little desire to pay Apple 99$ a year just to put this app on her iPad, and I don’t want to be bothered with jailbreaking.

 

This is where my recent playing with HTML5 comes in extremely handy.  I am going to create it using a variety of technologies, include cocos2D, node/express and heroku.  The application itself is very simple, but the process is stuff that almost any moderately advanced web application is going to face.

 

First off, HTML5 is wonderful, but it has some serious limitations.  One such limitation is only having minimal local storage.  This is where your server comes in, and Node delivers in spades.  Another problem almost all web apps face is… where do I put this thing?  We will cover that as well.  Possibly at the end I will also covering delivering to device ( PhoneGap? Appcelerator? ), that’s a wait and see thing.

 

This isn’t exactly a tutorial series; this is something I have to accomplish, so I’ve decided to document the process as I go.  I wont always go into as much detail as I normally do with tutorials and I promise you, unless you have a toddler yourself, the end result wont be that exciting of a game.  However, you will see how to quickly make an HTML5 game in cocos2D, hosted in Node.js, developed quickly.  Hope you enjoy.

 

In fact, the first post is up.  This one covers hosting a cocos2D app ( our last tutorial on menus and music ) in a custom Node.js based server.

General


22. June 2012

 

In this tutorial we are now going to implement a web app end to end using YUI and hosted in Node.  It isn’t actually going to do anything much, but it will illustrate everything you need to create a client and server in JavaScript using YUI App and Node.  Over time we will add more bells and whistles, but there is actually everything you need here to create a full functioning web application.

 

After looking in to it a little closer, YUI is incredibly well documented, but actually implementing YUI App Framework in a real world environment there are gaps of information missing.  Generally all you are going to find is samples with a gigantic HTML files where all of the script is located in a single file, which obviously isn’t good form nor very maintainable.  Unfortunately, when you actually set about splitting your YUI App into separate files and templates, you are completely on your own!  In fact, this tutorial may in fact be the first one on the subject on the internet, I certainly couldn’t find one. 

 

That said, there are still some great resources I referred to over and over well figuring this stuff out.  First and foremost, was the App Framework link I posted earlier.  It effectively illustrates using models and views, just not how to organize them across files in a complex project.  The GitHub contributor app was another great sample, but it again, was effectively one giant HTML file.  Finally there is the photosnear.me application’s source code up on GitHub.  It is a full YUI App/NodeJS sample and is certainly worth reading, but as an example for people learning it is frankly a bit too clever.  Plus it renders templates out using Node, something I wanted to avoid.

 

Alright, lets do a quick overview of how program flow works, don’t worry, it’s actually a lot less complicated than it looks. It is initially over-engineered for what it ends up accomplishing.  However, in the end you basically have the bones of everything you need to create a larger more complex application and a code structure that will scale with your complexity.

 

image

This ( in the image to the left ) is the file hierarchy that we are about to create.  In our root directory are two files, server.js which is our primary NodeJS application, while index.html is the heart of our web application, and where the YUI object is created.

 

Additionally, in a folder named scripts we create a pair of directories models and views.  Models are essentially your applications data, while Views are used to display your data.  Finally within the views folder we have another folder templates which is where our handlebar templates reside.  If you have done any PHP or ASP coding, templates are probably familiar to you already.  Essentially they are used to dynamically insert data into HTML, it will make more sense shortly.

 

We are going to implement one model, person.js, which stores simple information about a Person, and one view person.View.js which is responsible for displaying the Person’s information in the browser, and does so using the person.Template.

 

Now lets actually take a look at how it all works, in the order it is executed.

 

First we need our Node based server, that is going to serve the HTML to the browser ( and do much much more in the future ).  Create a new file named server.js

var express = require('express'), server = express.createServer(); server.use('/scripts', express.static(__dirname + '/scripts')); server.get('/', function (req, res) { res.sendfile('index.html'); }); server.get('*', function (req, res) { res.redirect('/#' + req.url, 302); }); server.listen(process.env.PORT || 3000);

 

Essentially we are creating an express powered server.  The server.use() call enables our server to serve static ( non-dynamic ) files that are located in the /scripts folder and below.  This is where we serve all of our javascript and template files from, if we didn’t add this call, we would either need to manually map each file or you will get a 404 when you attempt to access one of these files on server.  Next set our server up to handle two particular requests.  If you request the root of the website ( / ), we return our index.html file, otherwise we redirect back all other requests back to the root with the url appended after a hash tag.  For more details, read this, although truth is we wont really make much use of it.  Finally we start our server to listen on port 3000 ( or process.env.PORT if hosted ). Amazingly enough, these 9 lines of code provide a full functioning if somewhat basic web server.  At this point, you can open a browser and browse to http://localhost:3000, well, that is, once you start your server.

 

Starting the server is as simple as running node server.js from your command line.  This assumes you have installed NodeJS and added it’s directory to your PATH environment variable, something I highly recommend you do.  Now that we have our working server, lets go about creating our root webpage index.html.

<!DOCTYPE html> <html> <head> <title>GameFromScratch example YUI Framework/NodeJS application</title> </head> <body> <script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script> <script src="/scripts/models/person.js"></script> <script src="/scripts/views/person.View.js"></script> <script> YUI().use('app','personModel','personView', function (Y) { var app = new Y.App({ views: { personView: {type: 'PersonView'} } }); app.route('/', function () { var person = new Y.Person(); this.showView('personView',{model:person}); }); app.render().dispatch(); }); </script> </body> </html>

 

The most important line here is the yui seed call, where we pulling in the yui-min.js, at this point we have access to the YUI libraries.  Next we link in our model and view, we will see shortly.  Ideally you would move these to a separate config file at some point in the future as you add more and more scripts.  These three lines cause all of our javascripts to be included in the project.

 

The YUI().use call is the unique way YUI works, you pass in what parts of YUI library you want to access, and it creates an object with *JUST* that stuff included, in the for of the Y object.  In this case, we want the YUI App class ( and only it! ) from the YUI framework, as well as our two classes personModel and personView, which we will see in a bit more detail shortly.  If you use additional YUI functionality, you need to add them in the use() call.

 

We create our app and configure it to have a single view named personView of type PersonView.  Then we set up our first ( and only route ), for dealing with the URL /.  As you add more functionality you will add more routes.  In the event a user requests the web root, we create a person model.  Next we show the personView and pass it the person model we just created.  This is how you connect data and views together using the YUI app framework.  We then render our app and call dispatch(), which causes our app url to be routed ( which ultimately causes our person model and view to be created. If you aren’t used to Javascript and are used to programming languages that run top down, this might seem a bit alien to you at first.  Don’t worry, you get used to it eventually… mostly).

 

Now lets take a look at our model person.js

YUI.add('personModel',function(Y){ Y.Person = Y.Base.create('person', Y.Model, [],{ getName:function(){ return this.get('name'); } },{ ATTRS:{ name: { value: 'Mike' }, height: { value: 6 }, age: { value:35 } } } ); }, '0.0.1', { requires: ['model']});

 

Remember in index.html in the YUI.use() call where we specified personModel and personView, this is how we made those classes accessible.  By calling YUI.add() we add our class into the YUI namespace, so you can use YUI.use() to included them when needed, like we did in index.html.

 

Next we create our new class, by deriving from Y.Model using Y.Base.create(),  you can find more details here.  We declare a single function getName(), then a series of three attributes, name, height and age.  We set our version level to ‘0.0.1’ chosen completely at random.  When inside a YUI.add() call, we specify our YUI libraries as a array named requires instead of in the YUI.use call.  Otherwise, it works the same as a .use() call, creating a customized Y object consisting of just the classes you need.

 

Now lets take a look at the view, person.View.js

 

YUI.add('personView',function(Y){ Y.PersonView = Y.Base.create('personView', Y.View, [], { initializer:function(){ var that=this, request = Y.io('/scripts/views/templates/person.Template',{ on:{ complete:function(id,response){ var template = Y.Handlebars.compile(response.responseText); that.get('container').setHTML(template(that.get('model').getAttrs(['name','age','height']))); } } }); }, render:function(){ return this; } }); }, '0.0.1', { requires: ['view','io-base','personModel','handlebars']});

 

Like person.js, we use YUI.add() to add personView to YUI for availability elsewhere.  Again we used Y.Base.create(), this time to extend a Y.View.  The rest that follows is all pretty horrifically hacky, but sadly I couldn’t find a better way to do things that way I want. The first horrible hack is that:this, which is simply taking a copy of PersonView’s this pointer, as later during the callback, this will actually represent something completely different.  The next hack was dealing with including Handlebar templates, something no sites that I could findon the web illustrate, because they are using a single HTML file (which makes the task of including a template trivial).

 

The problem is, I wanted to load in a Handlebars template( we will see it in a moment ) in the client  and there are a few existing options, none of which I wanted to deal with.  One option is to create your template programmatically using JavaScript, which seemed even more hacky ( and IMHO, beats the entire point of templating in the first place! ).  You can also precompile your templates, which I will probably do later, but during development this just seemed like an annoyance. The photosnear.me site includes them on the server side using Node, something I wanted to avoid ( it’s a more complex process over all, and doesn’t lend itself well to a tutorial ).  So in the end, I loaded them using Y.io. Y.io allows you to make asynchronous networking requests, which we use to read in our template file person.Template.   Y.io provides a series of callbacks, of which we implement the complete function, read the results as our template, “compile” it using Y.Handlebars, we then “run” the template using template(), passing it the data it will populate itself with.  In our case, our name, age and height attributes from our personModel.  template() after executing contains our fully populated html, which we set to our views container using the setHTML() method.

 

Finally, lets take a look at person.Template, our simple Handlebars template:

<div align=right> <img src="https://www.gamefromscratch.com/image.axd?picture=HTML-5-RPG_thumb_1.png" alt="GameFromScratch HTML5 RPG logo" /> </div> <p><hr /></p> <div> <h2>About {{name}}:</h2> <ul> <li>{{name}} is {{height}} feet tall and {{age}} years of age.</li> </ul> </div>

 

As you can see, Handlebar templates are pretty much just straight HTML files, with small variations to support templating.  As you can see, the values {{name}}, {{height}} and {{age}} are the values that are populated with data.  They will look at the data passed in during the template() call and attempt to find matching values.  This is a very basic example of what Handlebars can do, you can find more details here.

 

Now, if you haven’t done so, run your server using the command node server.js, if you have set node in your PATH.

 

Then, open a web browser and navigate to http://localhost:3000, and if all went well you should see:

 

image

 

 

Granted, not very exciting application, but what you are seeing here is a fully working client/server application with a model, view and templating .  There is one thing that I should point out at this point… in the traditional sense, this isn’t really an MVC application, there is no C(ontroller), or to a certain extent, you could look at the template as the view, and the view as the controller!  But don’t do that, it’s really quite confusing! Smile  Just know, we have accomplished the same goals, our data layer is reusable and testable, our view is disconnected from the logic and data.  Don’t worry, the benefits of all of this work will become clear as we progress, and certainly, once we start adding more complexity.

 

In the near future, we will turn it into a bit more of an application.

 

 

You can download the project source code here.

Programming


15. May 2012

 

In Part 1 we covered creating and displaying our UI.  Now we are going to do something with it.  We are going to cover quite a bit of different material in this tutorial.  First and foremost we are going to need a server to talk to, lucky enough, I already have one!

 

 

That tutorial series was about creating a high score server using Node, then consuming it from a C++ SFML app.  We are going to reuse the server logic from that tutorial.  If you have zero experience with Node, I recommend you read it, just ignore the C++ bits, we will cover them here.  If you don’t care about Node at all, simply download and save server.js as well as HighScores.txt.

 

Then all you need to do is download and extract node, once extracted at a command line run change to the node directory and run node.exe c:\path\to\where\you\save\server.js, and your server is up and running, like such:

 

image

 

Press CTRL + C to exit.

 

Let’s take a quick look at Server.js

 

var dgram = require('dgram'), fileSystem = require('fs'), highScores, server; //Load high scores from file fileSystem.readFile("HighScores.txt", 'utf8', function(err,data){ if(err){ //Error occurred loading file, spit out error message then die console.log("Error occurred loading file"); process.exit(); } console.log("Loading high scores from file"); try{ // use JSON to turn file contents back into a Javascript array object highScores = JSON.parse(data); }catch(e) { // Exception occurred parsing file contents as JSON, error out and die. console.log("Exception occured parsing data"); process.exit(); } // Now sort the high scores by score, high to low highScores.Scores.sort(function(a,b){ return b.Score - a.Score; }); // Display the sorted high scores to the console console.log(highScores); }); //Create a UDP socket server = dgram.createSocket('udp4'); console.log("Socket created"); // Add a handler for incoming traffic on the socket. This will be called each time something connects to the socket server.on("message",function (msg,rinfo) { //console.log(parseInt(msg).toString()); console.log(rinfo); // SFML sends two packets, one with the size of the following packet ( as a 4 byte number ) // We don't need it, so as a crude-hack, we ignore any 4 byte packets if(rinfo.size != 4) { console.log("Received message:" + msg.toString()); // Socket data comes in as a JSON encoded array of objects, turn back into a JS object var jsonData,i; try{ jsonData = JSON.parse(msg); } catch( exception ) { console.log("Invalid JSON request received"); return; // Non lethal error, just stop processing packet } // The action parameter determines what you should do with this packet switch(jsonData.action) { // action==AddScore, add the score to the highscore array if it's higher than an existing score case "AddScore": console.log("AddScore called\n"); // Make sure highscore has been initialized... order can be a weird thing in node if(highScores != undefined){ // Loop through current highScores ( which should be sorted ) // and insert score if a lower match found for(i=0;i < highScores.Scores.length;++i) { if(highScores.Scores[i].Score < jsonData.score){ highScores.Scores.splice(i,0,{"Name" : jsonData.name, "Score" : jsonData.score}); console.log("Inserted highscore by: " + jsonData.name); break; // match found, stop looping } } } // Display newly created highscore array console.log(highScores.Scores); break; case "GetScores": console.log("Get Scores called"); // Turn highscores back into a JSON encoded string var highScoreAsString = JSON.stringify(highScores); // Create a buffer to hold that string var responseBuffer = new Buffer(highScoreAsString.length); // Write the string to the buffer responseBuffer.write(highScoreAsString); // Send it back to the client, using the addressing information passed in via rinfo server.send(responseBuffer,0,responseBuffer.length,rinfo.port,rinfo.address, function(err, sent){ if(err) console.log("Error sending response"); else console.log("Responded to client at " + rinfo.address + ":" + rinfo.port ); }); break; } } // // }); // Called when socket starts listening for packets. besides logging, currently serves no purpose server.on("listening", function () { var address = server.address(); console.log("server listening " + address.address + ":" + address.port); }); // Finally, bind the server to port 1000. 1000 was randomly chosen. Think of this as saying GO! // Now we are listening for UDP connections on port 1000 server.bind(1000); // Now, lets show off a bit, with the worlds simplest web server. // Dynamically creates webpage showing current high scores. var webServer = require('http'); webServer.createServer(function(req,res){ res.writeHead(200, {'Content-Type': 'text/html'}); res.write("<html><body><h1>High Scores</h1><ul>"); for(i=0;i < highScores.Scores.length;++i) { res.write(highScores.Scores[i].Name + "&nbsp;&nbsp;" + highScores.Scores[i].Score + "<br />"); } res.write("</ul></body></html>"); res.end(); }).listen(80);

 

The code is pretty well commented as to what it does.  For more details, read all three parts of the prior tutorial.

 

 

Now that we have our server up and running, we need to communicate with it.  As you may have noticed, the server made heavy use of JSON, which is a simple Javascript based data markup format.  This is the format we are going to send and receive our data in.

 

Here for example, is the simple JSON we are going to create for a Add High Score request:

 

{ "action":"AddScore", "name":"Mike","score":90210}

 

Normally there is a JSON serializer bundled with the .NET framework, unfortunately it hasn’t been included in the PlayStation Suite SDK, so we need one.  Fortunately there is a very simple one available, the aptly named simple-json.  We actually only need to download a single file, SimpleJson.cs.  Download that file and save it somewhere.

 

We could simply add the cs file to our project, but I find it a bit cleaner to put it into a library of it’s own, so that is what we are going to do.  In PlayStation Suite, right click your solution and select Add->Add New Project:

 

image

 

In the resulting dialog, on the left hand panel select C#->PlayStation Suite, then in the middle pane select PlayStation Suite Library Project, finally name it and click OK.  I went with the name JSON.

 

image

 

Make certain you select a PS Suite library project, an ordinary library will not work!

 

Now that we have our newly created library, we need to add the SimpleJson.cs file we downloaded.  Simply right click your JSON project, select Add Files, and select SimpleJson.cs.  Now that the file has been added, right click the JSON project and choose Build JSON.  It should compile without error.

 

We now need to add a reference to the JSON project to our Networking project.  Expand Networking, right click References and select “Edit References…”

 

In the resulting dialog, switch to the Projects tab then click the checkbox next to JSON, finally click the OK button.

 

image

 

Our project can now access the SimpleJson class.  Now we have to wire-up our app so the UI actually does something.  Open up MainWindow.cs and change it as follows:

 

using System; using System.Collections.Generic; using Sce.Pss.Core; using Sce.Pss.Core.Imaging; using Sce.Pss.Core.Environment; using Sce.Pss.HighLevel.UI; using System.Net; using System.Net.Sockets; namespace HighScoreApp { public partial class MainWindow : Scene { public class ScoreEntry { public string Name; public int Score; } public class ScoreArray { public IList<ScoreEntry> Scores { get; set; } } public MainWindow() { InitializeWidget(); buttonAddScore.ButtonAction += delegate(object sender, TouchEventArgs e) { Dictionary<string,object> jsonRequest = new Dictionary<string, object>(); jsonRequest["action"] = "AddScore"; jsonRequest["name"] = textBoxName.Text; jsonRequest["score"] = Int32.Parse(textBoxScore.Text); // No error handling, will blow up easily, use tryparse string jsonObj = SimpleJson.SimpleJson.SerializeObject(jsonRequest); labelResults.Text = jsonObj; using(Socket sock = CreateOpenSocket()){ sock.Send(System.Text.Encoding.UTF8.GetBytes(jsonObj)); sock.Shutdown(SocketShutdown.Both); sock.Close(); } }; buttonGetScores.ButtonAction += delegate(object sender, TouchEventArgs e) { var jsonRequest = new Dictionary<string, object>(); jsonRequest["action"] = "GetScores"; jsonRequest["name"] = ""; jsonRequest["score"] = 0; string jsonString = SimpleJson.SimpleJson.SerializeObject(jsonRequest); using(var sock = CreateOpenSocket()) { sock.Send(System.Text.Encoding.UTF8.GetBytes(jsonString)); byte[] buffer = new byte[1024]; sock.Receive(buffer); string responseJSON = System.Text.UnicodeEncoding.ASCII.GetString(buffer); var results = SimpleJson.SimpleJson.DeserializeObject<ScoreArray>(responseJSON); foreach(var score in results.Scores) { labelResults.Text += score.Name + " " + score.Score.ToString() + "\r\n"; } sock.Shutdown(SocketShutdown.Both); sock.Close(); } }; } private Socket CreateOpenSocket() { String client_name = Dns.GetHostName(); IPHostEntry client_host = Dns.GetHostEntry(client_name); IPAddress client_ip = client_host.AddressList[0]; IPEndPoint endpoint = new IPEndPoint(client_ip, 1000); var sock = new System.Net.Sockets.Socket( System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp); sock.Connect(endpoint); return sock; } } }

 

The first thing we added was the System.Net and System.Net.Sockets using statements, we need these for the networking calls we are going to perform.  Next we declare a pair of really simple classes, ScoreEntry and ScoreArray.  Although JSON is passed around as strings, it needs to be mapped back to usable C# objects.  Our network call is going to return an array of Scores, so we need to have a corresponding C# datatype for SimpleJson to deserialize to.

 

Next up is our constructor, its very critical that you keep InitializeWidget() where it is.  This method is what causes the generated code in MainWindow.designer.cs to execute, and this is where all of our various buttons, labels and text boxes are defined.  Be sure to call InitializeWidgets before you use any of those widgets!

 

Now we want to wire up our two buttons to actually do something when clicked.  You could use an ON_click style method, but I instead went inline with an anonymous method.  First we create a Dictionary object that is going to be translated into our JSON request string.  It’s merely a set of name value/pairs representing the name, high score as well as the action we want to perform.  As you can see, we get the values from our two EditableText widgets, and if you named them differently in designer, you need to update the variable name here accordingly.  Notice in this example I have ZERO hardening, so if you pass invalid values, things will go horribly wrong.

 

Now that we have created our Dictionary of key/value pairs, we pass it to SimpleJson.SerializeObject, which then turns it into an JSON string.  Just for debugging purposes, we display the resulting string to our labelResults.  Now we actually make the network request.  To simplify things a bit, and make the code reusable we created the CreateOpenSocket method, which creates an socket and connects to it.  We will see this method in a moment, again notice the lack of error handling, bad me!

 

Once our socket is created, we convert our string to raw bytes and send them across the socket.  At this point, we are done with it, so we shut it down and close it.  It’s pretty easy to leak ports, so be careful about shutting down your sockets when you are done with them.   At this point, you can now send high score requests to the server, like such:

 

image

 

Fill in a value for name and score, then click Add Score, if everything went right, you should see the JSON string that we passed across the network displayed below our form.  Additionally, if you tab over to your node command window, you should see:

 

image

 

This shows that your score was received, sorted and added to the high score list on the server.  Now lets look at the code behind the GetScores button, you will see that much of it is identical.  Again we start by making a Dictionary for our JSON request object, the format is identical, but in this case the action is GetScores, and the name and score values don’t matter ( although they need to be there ).  Again we serialize to a JSON string and create a UDP socket using CreateOpenSocket().

 

This time though, we are waiting for a reply.  We send our socket just like before, but this time we call Receive() after.  Again, there is no error handling and receive will block your thread preventing execution until finished, in a production environment, you would make things much more tolerant.

 

Receive takes a byte buffer into which to copy the data that it is received.  When you run the Simulator, you may get a firewall prompt, make sure you allow it, or you will never get a response here even though you are connecting on the local machine.  The contents of that buffer are actually just an ASCII string of JSON code, so we simply decode it back to a string.

 

We then take that JSON string and deserialize it, this is where we make use of those two simple classes we defined before, they are the format SimpleJson will deserialize the string into.  After running DeserializeObject, results will contain a ScoreArray, which is simply a List<> of ScoreEntry.  We simply loop through the ScoreEntrys and display the name and score out to our labelResults.  Finally, just like before, we clean up after ourselves and shutdown the socket.

 

Now if you run the code and click the GetScores button, the high scores list will display, including any scores you added using the AddScore button.  These scores will last until you shut down server.js.

 

image

 

And if you flip over to node, you will see:

 

image

 

Finally, we look at the CreateOpenSocket() method.  This is straight .NET code and has nothing at all to do with PS SDK.  First we need the DNS value of the server we are connecting to.  Generally it would be something like “someserver.com”, but since we are running client and server on the same machine, we want our own host name.  We then take that host name and DNS resolve it to an IP address, which is a two step process.  Then we take the resulting IPAddress entry and create an IPEndPoint.  The 1000 value is the port to connect on.  This value was hard coded in the server.js file.  If for some reason you want to connect on a different port, you need to change this line:

server.bind(1000);

 

in server.js.  Next we create our actual socket, in this case UDP.  Why did we use UDP instead of TCP?  No reason really.  TCP is more reliable but a bit slower, but guarantees in order response. None of this matters to use here, so I used UDP.  You can change to TCP by changing a single line here and in server.js.  Finally we connect to our socket and return it.  It is the responsibility of the caller to close the open socket down.

 

 

Now, you have a fully functional networked GUI based highscore client and server.

 

You can download the complete sources here.  That archive includes the Node scripts, so all you need is to download Node in order to run it.

Programming


GFS On YouTube

See More Tutorials on DevGa.me!

Month List