PongR part 3: client side

Standard

Heads up!

The blog has moved!
If you are interested in reading new posts, the new URL to bookmark is http://blog.valeriogheri.com/

 

In part 1 of “PongR – my first experience with HTML5 multiplayer gaming” , I talked about the spirit of this project, the system architecture, technologies used and the design of the game (remember the server authoritative model?)

In part 2 I talked about the server side code and the server loops

This is part 3 and I will talk about the client side code, the client loops and how we draw basic (no sprites, only basic shapes) images on a canvas.

Code and Demo

As always, the code is fully published on github [https://github.com/vgheri/PongR] and a (boring!) demo is available at http://pongr-1.apphb.com . If you don’t have anyone to play with, just open two tabs and enjoy!

Project structure and technologies used

As a quick recap, this project has been realised using Asp.Net MVC, HTML5 (Canvas), Javascript, C#, SignalR for client/server real-time communication and qUnit for javascript unit testing.

PongR is a multiplayer HTML5 game, and this means that the client itself is doing a good amount of work.
The engine is replicated both on the server and on the client, as we have seen in the first part of this article when I talked about the server authoritative model + client side prediction that force us to add logic onto the client.
In the server this logic is built into a class named “Engine” and later on we will go into more details.
In the client this logic is built into a javascript module named PongR.

Javascript  code structure and unit testing

Most of the Javascript client side code is contained into a folder called Js, whose structure is shown below:



the module PongR is inside the file PongR.js. This module exports a public prototype with two public functions needed to setup an instance of the game and to connect to the server.

pongR.PublicPrototype.createInstance = function (width, height, username) { … }
pongR.PublicPrototype.connect = function () { … }

Furthermore the public prototype exports also a set of functions that have been unit tested using qUnit [www.qunitjs.com].
qUnit is very easy to use and the way I set it up is very neat: you can find all the details in this awesome article http://freshbrewedcode.com/jonathancreamer/2011/12/08/qunit-layout-for-javascript-testing-in-asp-net-mvc3/
Basically what you get is an easy way to share certain pieces of the tests layout in an ASP.net MVC3 application, with the possibility to have all the links to start your different tests grouped into one HTML page, being able to start them with just one click.
The downside of doing things this way is that the functions we want to unit test need to be visible from outside the module. In order not to pollute the public prototype too much, the module exports a UnitTestPrototype object, which will contain the references to the functions that I want to unit test.

var pongR = {
    PublicPrototype: { UnitTestPrototype: {} }
};

All the unit tests are contained into PongR_test.js.
A quick example:

And when runned, this is what you get:

Finally, I’m going to talk about RequestAnimationFrameShim.js later in the article, when I’ll focus on the Canvas element.

PongR

Other than what we already saw, this module defines several View Model, related to objects that needs to be simulated. Below we can see a basic diagram of the objects and their connections:

The main object here is clearly Game, as it contains the whole state of a match.
Settings is another interesting enough object, it holds a few configuration variables that are mostly used for client prediction and interpolation (I will cover this topic later on in the post).
These models are widely used by the client logic: for example the physics update loop directly modifies these models at every simulation step.
And this leads us to discuss about the client side update loops.

Client side update loops


Let’s restart the flow and let’s see more in detail what is happening:
when a client enters its username and posts the form, the system redirects the client to the page where the actual game will be displayed. This page will load all the necessary javascript libraries and modules, as well as PongR, and will then perform this piece of code on the document onready event:

createInstance sets up the basic configuration of the game and creates the variable that will host the SignalR object, pongR.pongRHub, and all related callbacks.
Once the SignalR object has been correctly populated, we can invoke the .connect() function on PongR, that will start the SignalR connection and on success we invoke the joined() function, which will be where the server will process the client.
We need to have something after start() because in the server side handler the round trip state is not yet available.
When 2 players are connected and waiting, the server sends an init message to both clients that is handled by the client by the following callback:

https://gist.github.com/4369339

This code initiliases a new Game, the canvas on which the game will be drawn on, an empty list of server updates that will be received throughout the game and the default delta time set to 0.015 ms that corresponds to 66 fps, a keyboard object, which is a slightly modified version of the THREEx keyboard library that I edited to serve my purposes here, and draws the initial scene (the field, the players and the ball).
After completing initialisation, we can perform a 3 seconds countdown so that the match doesn’t start all of a sudden and the players are not yet ready.
At the end of the countdown the startGame function is invoked.
This function is very important because it starts the two client loops responsible of handling the game inputs and rendering.

function startGame() {
    startPhysicsLoop();
    startUpdateLoop();
}

Client side loops

Client physics update loop

Exactly as the server was running a physics update loop, the client is also running a similar loop.
This loops interacts with and modifies directly the View Models that I described earlier.

function startPhysicsLoop() {
    physicsLoopId = window.setInterval(updatePhysics, 15);
};

This loop runs every 15msec and is responsible for

  • updating at each round the delta time, used to compute the movements of the players
  • updating the position of the client
  • updating the position of the ball
  • checking for possible collisions between the ball and the objects of the game, players and ball. If a collision is detected, than the position and the direction of the ball are updated as well.


https://gist.github.com/4369350

Despite the fact that the source I used to create this project puts the collision-checking code into the client update loop, I moved it inside the physics update loop for simplicity. This is obviously not an ideal solution if you want to play sounds on collisions, for example, given that the sound should be played by the update loop.

Client update loop

This loop, unlike the physics loop, is scheduled using a function recently introduced into modern browsers, RequestAnimationFrame.

function startAnimation() {
    requestAnimationFrameRequestId = window.requestAnimationFrame(startUpdateLoop);
};

You can read in detail about this function here  and more here  .
Basically instead of using setTimeout or setInterval, we tell the browser that we wish to perform an animation and requests that the browser schedule a repaint of the window for the next animation frame. Reasons why RequestAnimationFrame is better than old style setTimeout and setInterval for drawing purposes are clearly stated in the above link, but I think it’s important to quote them here:

The browser can optimize concurrent animations together into a single reflow and repaint cycle, leading to higher fidelity animation. For example, JS-based animations synchronized with CSS transitions or SVG SMIL. Plus, if you’re running the animation loop in a tab that’s not visible, the browser won’t keep it running, which means less CPU, GPU, and memory usage, leading to much longer battery life.

Because this function has been recently introuced, it may happen that some browser still don’t support it and that’s the reason of that RequestAnimationFrameShim.js file that we saw at the beginning. It’s a piece of code found on Paul Irish’s blog aticle mentioned above, so credits go to him.
Let’s see the code:

Initially I check that we are not in a post-goal condition, because after a goal a 3 seconds countdown will be performed and we don’t want to update any of our internal data structures during this time.
If we are not, then we can simulate a new step of the game

At every step the canvas must be redrawn, therefore I can safely clear it.
As this game is fairly simple it won’t impact our performances, otherwise it could have been better to have multiple specialised overlapping canvas, where for example we could use one to draw the background that never changes, and therefore needs not to be cleared & redrawn at each step, and so forth…
Furthermore, I need to process client inputs (if any) and accordingly update a meta-structure that contains a list of commands (“up”/”down”). This meta-structure will then be used by the client physics loop and converted in movements.
Every input processed at each loop is stored in a list of commands (pongR.me.inputs) and assigned a sequence number that will be used when the server will acknowledge already processed inputs. For example, if the server acknowledges input 15, then we can safely remove from the buffer all inputs with sequence number equal to or lower than 15, and reapply all non yet acknowledged inputs (remember the client side prediction model?).
Every input is packed and immediately sent to the server to be processed.

if (!pongR.settings.naive_approach) {
    interpolateClientMovements(pongR.other);
}

function interpolateClientMovements is a bit tricky and you can read the code by yourself for a better understanding (or even better you can check the blog article where I took this from), but basically it is trying to interpolate the different positions of the opponent in time so that at each redraw its movements will result more continuous and natural to the eyes of the player.
Imagine that the opponent is currently at position (50,50) and then finally we receive its new position at (50,100), if we naively assign this new position to the opponent, what we will see on the screen is a big leap from last frame and it’s obviously something we don’t want.
I have to say that my implementation is not working that well at the moment, but the idea is there.
Finally, after having handled all inputs, I can draw the new frame by drawing each object on the screen.

Server authoritative model in practice


Each time the server runs its own update loop, the clients receive an update packet.
Each client is then responsible for processing it and updating its internal structures so that the next time the update loops will run, they will see an updated snapshot of the game as dictated by the server.
The function responsible to handle all of this is the SignalR callback updateGame.
Let’s see it in detail:

As I mentioned in part 1 of this blog article, it’s the server responsibility to simulate game state changing events, and a goal event is one of this kind!
This should clarify the meaning of the first lines of code: the client only knows that a goal happened because the score changed!
Then, based on this condition, we need to perform two different tasks:

  1. If one of the two players scored, we need to update the scores (both internally and on the screen), reset the positions of all the objects drawn on the screen, reset the state of the keyboard object (we don’t care of all the keystroke pressed after a goal!) and finally perform a countdown that will start the match once again.
  2. Otherwise
    1. We need to apply client side prediction to update our client position, re-processing all those inputs which have not been acked by the server yet
    2. If we are not using a naive approach we do not directly update the other player position, but we simply update some of its internal properties and then we push the just received update packet into the updates buffer, so that it will be used in the update loop for interpolation
    3. We update the information related to the ball  object


It is interesting to note that the updates buffer is not infinite and we limit it to cover 1 seconds of server updates.

Final considerations and next step

This was my first attempt at creating a game and adding multiplayer didn’t make the task easier for sure!
The graphic is really basic, the game itself is not that entartaining, the network lag is clearly affecting the user experience mostly due to a not optimised networking code and to the impossibility of using WebSockets (AppHarbor doesn’t support them yet), but nevertheless it was very funny and I learned plenty of stuff while working on this project.
I have to say that offering the clients a seamless game over the wire has probably been the hardest part of it, and I’m sure there are things which are not working like they should in my code.
Also I think that Asp.Net MVC doesn’t offer the best in class experience to realise this sort of web app (as expected), whereas I see much more fitting Node.Js because of its event-driven nature: if you think about it, almost everything happening in a game can be seen as an event.
Last but not least, using a single codebase and a single language can greatly help to speed up the process.
I couldn’t cover everything I wanted to in these three posts, they are already monster size, so I encourage you to clone the repository and dig into the code to find everything out (like for example delta-time implementation and time synchronisation).
In the near future I would like to rewrite this project entirely in Javascript using Node.Js and, enhancing the user experience ameliorating the graphics using sprites, making the game funnier (e.g. possibility to use bonuses), adding sounds, upgrading SignalR to 1.0 etc…

References

That’s all about PongR, I hope this can help someone

Valerio

Architecting a MVC web application with Knockout

Standard

Heads up!

The blog has moved!
If you are interested in reading new posts, the new URL to bookmark is http://blog.valeriogheri.com/

 

One of the most recurring questions I see on StackOverflow (for example here) and the likes is about best practices for architecting MVC web applications and about integration with “this” or “that” javascript framework without messing up the whole design.
So I decided to share my thoughts on this, because I know how confusing and hard it can be, especially for beginners, to put all the pieces of the puzzle together.
I chose to take Knockout as an example because I like its MVVM approach and the learning curve is not so steep.
Finally, as always, the foundations of this article lie in my own personal experience mixed with all the books and articles I read, therefore this article might be quite simplicistic or naive to someone with much more experience than me, or maybe someone else will just disagree.
In every case, feel free to express what you think!

MVC

Asp.Net MVC and similar frameworks are cool and powerful, they often offer nice and easy predefined project structures and convetions, so why bothering making things more complex?
Well, conventions are surely great, but when it comes to projects that have more than a few classes, views or controllers, or projects that relies on other teams work, or simply projects that want to adopt a more structured architecture, the basic project template just isn’t flexible enough.
MVC is an architectural pattern about the Presentation layer and how it connects to the Application layer, but what about the rest of the application? How do we further logically divide the software? And how do we connect these logical parts?

Architecture

The standard solution to the questions mentioned above is to use a layered architecture, few and fairly standard in their definition. To enforce well known principles like high coesion, do not repeat yourself etc, each of these layer specialises in a particular aspect of the software.
Each layer speaks a language, usually (with some exceptions, as we will see later) the language of the domain the software is related to, and uses layers beneath to fulfill some task.
The general diagram for the architecture I will talk about is the following:

Architecture

Architecture

The focus of this article is on the Presentation Layer, its integration with Knockout and the connection between the Presentation and the Application layer.

View Model

By definition, the M in MVC stands for Model, but what is exactly the Model we are talking about? The Asp.Net MVC doesn’t constraint the developer to define what M stands for, it could be a Domain Model object (using any kind of pattern, Active-Record, Entity, Value etc…) or it could be something else.
In the solution proposed in this article, the M stands for View Model.
This View Model is not to be confused with the Domain Model, that is the core language of the real world problem our application is trying to solve.
It is instead the language of the Presentation layer, used by Views (our HTML pages) and the Controllers (can be code-behind or Controller objects).
The MVC default project structure that we find in Visual Studio, for example, with its “Model” folder can easily mislead us on this, leading us to mix both worlds not even being aware of that!

What a View Model is

A View Model object is crafter around a specific View and should contain only the elements the View needs to display and optionally validation rules.
Every View should be strongly typed to a View Model object, so that you don’t have to mess up with loose strings or similar, being able instead to work with the MVC scaffolding engine, strongly typed variables and all the HTML helpers while building up your View.
I think it is a good practice to name the View Model object after the View and the specific action, for instance EditCustomerViewModel or CreateCustomoreViewModel, so that it’s easy to do the association between the View and the View Model object.
View Model objects often aggregate Domain Model objects or viceversa may map to only a subset of a Domain model object’s properties, and they may also contain View specific validation rules (for example Asp.Net MVC 3 comes with lots of built-in Data Annotation attributes that we can use to decorate classes or properties to express requirements about fields, data format etc…).
Let’s take as an example a page where the user can Create a new customer: we won’t display a field for customer ID whereas in the corresponding Edit page we may display it as a read only field.
This difference is well expressed using two distinct Views and two distinct View Models, each with different properties and attributes that adapt to the page.
It may seem like a lot of additional work to write two different Views and View Models, but it will pay you back in terms of ease of maintenance and clarity of intents when sharing the work with other people.
Furthermore by following this approach our Views contains no logic to handle different cases like “Edit” and “Create”, they just worry about data visualization like they should.

Views

Lots of javascript framework that help developers delivering a dynamic and interactive user experience are available these days, automating the task of writing repetitive javascript code to hook up DOM objects and events handlers, at the cost of the initial learning curve and the additional code to setup it.
I chose Knockout, which brings the MVVM pattern to the web, because the declarative bindings. are easy to understand and use, it’s easy to extend, it’s very well documentend, the website is full of useful examples and the additional amount of code to setup the framework is not too much.
Knockout requires the developer to write a javascript View Model (from now on referred as Knockout View Model) per each View we want to use it in and the declarative data bindings on each DOM element we want to observe. Once this is done, Knockout can keep track of the state of the controls displayed in the page. Whenever the user will change the state of whatever “observed” control in the page, the underlying Knockout View Model will automatically update itself.
This feature is killer for example if you’re writing a Single Page Application: one full load when the user requests the page for the first time, and every other interaction is an Ajax call where we already have the page state ready for use in javascript.
At this point you may ask: another view model? Didn’t we already have a Domain Model and a View Model?
Yes, that’s true, but every model has its own scope, and the Knockout View Model scope is to contain the presentation display logic and the state of the observed controls.
The View Model is used by the Controller Action that is responsible for loading the View the first time: it will databind the View to the View Model, so that the page is initialized quickly without the need to perform Ajax calls to load data from the server.
If the View is smartly initialised with data coming from the View Model, for example pre-ticked checkboxes, pre-filled textboxes , pre selected item in select list etc… our Knockout View Model won’t know about them unless we explicitely assign every initial values.
One way to do it is by Json encoding the bounded View Model and then assigning each pre-defined value to the Knockout View Model variable containing the observable value.
For example:

var boundedViewModel = @Html.Raw(Json.Encode(Model));
var viewModel = {
selectedCity: ko.observable(boundedViewModel.DefaultCity);
…
}

The Application Layer

Also known as middle tier, it works with Domain Model objects, the Repository and other Foundation services, to work out Presentation layer requests.
To be able to communicate, the Application and Presentation layer share the same language, the View Model objects.
If they were part of the Presentation layer, as suggested by the “Model” folder that we find in the default Asp.Net MVC project, the Application would need to have a reference to it to manipulate them, thus creating a circular reference!
To avoid such a problem we create a separate dll containing View Models, referenced by both the Presentation and the Application layer.
It is then the Application layer responsibility to translate from View Model to Domain Model objects and viceversa.
For this task it is possible and strongly suggested to use automated tools to do the mapping for us, such as AutoMapper for .Net (it is also available on NuGet).
By delegating this task to the Application, the Presentation layer is free from any mapping logic and from any reference that is not directly involved in its core business.

Closing thoughts

In this article we have seen a flexible solution to architect a MVC web application by
introducing a new object Model, the View Model, and its rules that together create an ad-hoc language for the Presentation layer that will help us in the task of building elegant front-ends and to an easier integration with javascript frameworks such as Knockout.

References

Lots of inspiration for this article comes from the following articles:

  1. http://msdn.microsoft.com/en-us/magazine/hh456393.aspx , where you’ll be able to find also more info on the Domain Model and the Repository layer.
  2. http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/
  3. http://www.methodsandtools.com/archive/archive.php?id=97