2013-02-26

Basics of creating a multiplayer web based game with jQuery and SignalR

In this article, I’m going to show how to use jQuery to move an object on web page and how we can use SignalR to notify all the connected clients about the movement and replicate that movement on each client.

The basic rule of a multiplayer web based game is, you have to reflect the changes done in a one player machine on other players machines, real-time. The challenge is how you are going to do this in real time. If you are using some polling mechanism, then some movements will get missed or slower to replicate in other players machine. Use with SignalR, multiplayer web based games are much easier to develop.

Let’s have a look at how to accomplish the basic rules of a multiplayer game, i.e. reflecting the changes real time in other clients, in an ASP.NET application with the help of SignalR.

Before we begin, following is a screen shot of the sample application. As you can see, I’m running the same application on two different browsers and I’m expecting the same movement of Scooby on both web pages without browser refresh.

Untitled

First of all, we have to add the reference to SignalR client and server libraries. Easiest way to do this is by NuGet packages. Right click on your project and click on Manage NuGet Packages…. Then type SignalR on the search box and click Install. Now you have SignalR in your application. I’m going to use some animation in my game, so let’s also install the jQuery UI from NuGet Packages.

Now we are ready to develop our application.

First, I’m going to add the Hub routing in my Global.asax file as shown below

protected void Application_Start(object sender, EventArgs e)
{
    RouteTable.Routes.MapHubs();
}

Then, I’m going to add the page where I’m going to develop the game. In there, I’m referencing to the jQuery latest version, jQuery UI library, SignalR client library. SignalR Hubs which will dynamically be created on the fly.

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js" charset="utf-8">
</script>
<script src="Scripts/jquery-ui-1.10.0.js"></script>
<script src="Scripts/jquery.signalR-1.0.0.js"></script>
<script src="/signalr/hubs"></script>

Next I’m going to develop my game using the jQuery/JavaScripts. Following is the code for that

<script type="text/javascript">
       $(function () {
           var moveScooby = $.connection.moveScoobyHub;

           moveScooby.client.runScoobyForward = function () {
               $("#scooby").animate({
                   marginLeft: '+=1'
               }, 0);
           }

           moveScooby.client.runScoobyBackward = function () {
               $("#scooby").animate({
                   marginLeft: '-=1'
               }, 0);
           }

           moveScooby.client.runScoobyUpward = function () {
               $("#scooby").animate({
                   marginTop: '-=30'
               }, 500, 'easeOutCubic', function () {
                   $("#scooby").animate({
                       marginTop: '+=30'
                   }, 500, 'easeInExpo');
               });
           }

           $.connection.hub.start().done(function () {
               $(document).keydown(function (e) {
                   var audio = document.getElementById("snd");
                   switch (e.which) {
                       case 32:
                           $("#scooby").animate({
                               marginTop: '-=30'
                           }, 500, 'easeOutCubic', function () {
                               $("#scooby").animate({
                                   marginTop: '+=30'
                               }, 500, 'easeInExpo');
                           });
                           moveScooby.server.moveScoobyUpward();
                           break;
                       case 37:
                           $("#scooby").animate({
                               marginLeft: '-=1'
                           }, 0);
                           moveScooby.server.moveScoobyBackward();
                           break;
                       case 39:
                           $("#scooby").animate({
                               marginLeft: '+=1'
                           }, 0);
                           moveScooby.server.moveScoobyForward();
                           break;
                   }
               });
           }
           );
       });
   </script>

Here, I will be using a Scooby-doo image and I will move it on the web page as we press arrow keys. Scooby will jump when you press the space bar.

My hub class name is MoveScoobyHub.cs. In SignalR, we must use lower case camel notation in order to access the server properties/methods. So I access my hub like below

var moveScooby = $.connection.moveScoobyHub;

Note the “m” in “moveScoobyHub” is simple even though the class name has capital “M”.

Next I’ve declared 3 methods to move the Scooby on all the client machines.

moveScooby.client.runScoobyForward = function () {
    $("#scooby").animate({
        marginLeft: '+=1'
    }, 0);
}

moveScooby.client.runScoobyBackward = function () {
    $("#scooby").animate({
        marginLeft: '-=1'
    }, 0);
}

moveScooby.client.runScoobyUpward = function () {
    $("#scooby").animate({
        marginTop: '-=30'
    }, 500, 'easeOutCubic', function () {
        $("#scooby").animate({
            marginTop: '+=30'
        }, 500, 'easeInExpo');
    });
}

First method will take care of moving the Scooby forward. It will add 1 unit to the margin left of the scooby object. I’m using jQuery animate() method to add the motion to the object. To make the movement to a normal speed, I’m setting the duration of the animation to 0. You can make the movement slow by increasing the duration. Same as in runScoobyForward function, I’ve written the runScoobyBackward function to move the Scooby backward. There I’m deducting a one unit from the left margin so the object will move backward.

Third method is for make the Scooby jump. I’m setting the top margin of the scooby object to –30px so the object will move upwards. To make the jumping looks real, I’m adding easeOutCubic to the animation. Once the animation is done, I’m calling the animate() method once again to move the Scooby to the ground (He can’t jump and stay forever in the air!). To do that, I’m adding 30px for the scooby object and I’m using easeInExpo for the animation so it looks more realistic with the gravity effect. So now the Scooby will back in the ground (-30px + 30px = 0)

Now those are the three methods I’m using to to do the movement of Scooby.

$.connection.hub.start().done(function () {
    $(document).keydown(function (e) {
        switch (e.which) {
            case 32:
                moveScooby.server.moveScoobyUpward();
                break;
            case 37:
                moveScooby.server.moveScoobyBackward();
                break;
            case 39:
                moveScooby.server.moveScoobyForward();
                break;
        }
    });
}
);

Once the connection to hub starts, I’m adding a function to keydown event of the web page. In that function I’m getting the keycode of the key pressed. If it’s the space bar (keycode=32), I’m calling the moveScoobyUpward method in the server. It looks like below

public void moveScoobyUpward()
{
    Clients.All.runScoobyUpward();
}

As you can see, it will in return call the runScoobyUpward() function on all the clients.

If it’s the left arrow (keycode=37), I’m calling the moveScoobyBackward method in the server. It looks like below

public void moveScoobyBackward()
{
    Clients.All.runScoobyBackward();
}

As you can see, it will in return call the runScoobyBackward() function on all the clients.

If it’s the right arrow (keycode=39), I’m calling the moveScoobyForward method in the server. It looks like below

public void moveScoobyForward()
{
    Clients.All.runScoobyForward();
}

As you can see, it will in return call the runScoobyForward() function on all the clients.

So that’s it! As for my markup, I’m simply using an image inside a div. I’ve set a background image for the div.

<body>
    <div style="background-image: url('Images/scooby01.jpg'); background-repeat: no-repeat; height: 438px; width: 584px">
        <img src="Images/aniscooby.gif" id="scooby" width="100" height="100" style="margin-top: 340px;" />
    </div>
</body>

Altogether, following is the complete aspx page markup. Of course there are no code behind code for that. You can surely copy paste this to a simple HTML page and it will work.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="UI.aspx.cs" Inherits="SignalRUIChange.UI" %>

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript"
        src="
http://code.jquery.com/jquery-latest.js" charset="utf-8">
    </script>
    <script src="Scripts/jquery-ui-1.10.0.js"></script>
    <script src="Scripts/jquery.signalR-1.0.0.js"></script>
    <script src="/signalr/hubs"></script>
    <script type="text/javascript">
        $(function () {
            var moveScooby = $.connection.moveScoobyHub;

            moveScooby.client.runScoobyForward = function () {
                $("#scooby").animate({
                    marginLeft: '+=1'
                }, 0);
            }

            moveScooby.client.runScoobyBackward = function () {
                $("#scooby").animate({
                    marginLeft: '-=1'
                }, 0);
            }

            moveScooby.client.runScoobyUpward = function () {
                $("#scooby").animate({
                    marginTop: '-=30'
                }, 500, 'easeOutCubic', function () {
                    $("#scooby").animate({
                        marginTop: '+=30'
                    }, 500, 'easeInExpo');
                });
            }

            $.connection.hub.start().done(function () {
                $(document).keydown(function (e) {
                    switch (e.which) {
                        case 32:
                            moveScooby.server.moveScoobyUpward();
                            break;
                        case 37:
                            moveScooby.server.moveScoobyBackward();
                            break;
                        case 39:
                            moveScooby.server.moveScoobyForward();
                            break;
                    }
                });
            }
            );
        });
    </script>
</head>
<body>
    <div style="background-image: url('Images/scooby01.jpg'); background-repeat: no-repeat; height: 438px; width: 584px">
        <img src="Images/aniscooby.gif" id="scooby" width="100" height="100" style="margin-top: 340px;" />
    </div>
</body>
</html>

And following is the server side code for the Hub. Note that I’m inheriting it from the SignalR Hub class in order to make it a hub.

using Microsoft.AspNet.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SignalRUIChange
{
    public class MoveScoobyHub: Hub
    {
        public void moveScoobyForward()
        {
            Clients.All.runScoobyForward();
        }

        public void moveScoobyBackward()
        {
            Clients.All.runScoobyBackward();
        }

        public void moveScoobyUpward()
        {
            Clients.All.runScoobyUpward();
        }
    }
}

4 comments:

smartsuite said...

Thanks for such social platform which give us variety of idea to explore ourself technically .This exposure give benefits to everyone to fit or to survive in global market which is very essential in the global era.
Time Attendance System

Anonymous said...

Hi,

Thanks of sharing such new concept.

Can you please share the source code, to grab the things easily.


Thanks & Regards,
Qureshi

Ruchira Gamage said...

Hi,

You can get the link to source codes from here

Anonymous said...


Thanx Ruchira

Regards,
Qureshi