Friday, 3 May 2013

Backgammon with SignalR – Part Three – Client Side SignalR

This is the last of a three part series of posts on BackgammonR – an online Backgammon game built with SignalR. If you haven’t read it already, please see Part 1 – Game Engine and Part 2 – Server Side SignalR

The first bit of JavaScript to note is not actually something you write, rather what SignalR generates in order for it to allow for the messages to be passed between client and server and vice versa. It’s at /signalr/hubs/ and if you view it you’ll can see how the methods defined on the server-side hub are exposed to the client.

The script I have written though lives in /public/site/backgammon.js and whilst it consists of a number of methods it can be considered in three main sections.

Data Binding

Before getting into the client-side SignalR code it’s worth flagging up the other libraries I’ve used here. Jquery of course. But also knockout, which provides a nice separation between the intricacies of the UI and the details of the client-side model manipulated in code. It provides a means of automatically data-binding updates to the model – so for example when a new player is added the list displaying those users will be automatically refreshed.

This is all managed in the set of functions under the “Data Binding” comment. A client-side view model is set-up and maintained via helper methods to store details of what is displayed via the browser – i.e. the list of players, games and details of the selected game the user might be playing.

Persistent Connection

Beneath the “Persistent Connection” lies the SignalR related code, primarily in the initPersistentConnection() method. The first thing that occurs is a reference is stored to the SignalR hub:

    var hub = $.connection.gameNotificationHub;

You’ll see here the name of the hub is the same as that defined for the class on the server. The next lines of code define the client-side methods that are called from the server. Going back to the method described in the previous post form when a player joins, there were two client side notifications made – one to the caller and one to all users of the site. These two functions are wired up as below:

        hub.client.joined = function (player, connectionId) {
            addPlayer(player);
            if ($.connection.hub.id != connectionId) {
                notify(player.Name + " has joined.", "message", true);
            }
        };

        hub.client.callerJoined = function (name) {            
            viewModel.name(name);
        };

callerJoined is the one that is sent to just the caller – all we do here is update the view model to set the name and have knockout bind it to the UI. joined is a notification to all players, to update the list of players held on the view model. It also uses the connectionId that’s exposed client as well as server side to display a notification message to all players other than the caller.

The final lines of code in this function are held within the callback of the $.connection.hub.start().done() method. This is where some initialisation calls to the hub are made, and jquery is used to link up various events with the UI. For example against each available player in the list is a link to challenge them; when clicked the name of the player is pulled from the DOM and a SignalR call to the hub’s Challenge method is made.

            $(document).on("click", "#player-list a.challenge", function () {
                var challengedPlayer = $(this).prevAll("span.player-name").text();
                hub.server.challenge(challengedPlayer);
                return false;
            });

Game Canvas

The functions under the comment “Game canvas” are all involved with the drawing of the game board and counters. I decided to use HTML canvas for this as although it would likely have been feasible with pure CSS – and in fact would probably have been better should I want to introduce drag-drop of the pieces rather than the rather clunky form interface I have at the moment – it was again something I was keen to play around with.

Apart from the one function to draw the counters which was one of those write once and hope you don’t have to come back to it events, it’s mostly fairly straightforward. The idea is to get a reference to the canvas and then to the 2D context within it. Once that’s obtained the drawImage method is used to draw the board and the counters in the right places.

And that’s that... so far anyway. There’s still a bit to do – in particularly the end game and making the whole thing look a bit nicer. But that’s mostly details… as far as the SignalR parts are concerned that’s all in place and can say it’s been a fun little side project to work on.

Play the game

View the code

No comments:

Post a Comment