Sunday, 9 June 2013

HTML5 and MVC4 Board Game (Uckers)

Initial Thoughts

I was asked some time ago if I could make a game for some old Royal Naval friends. Uckers is a popular board across many services but appears to be more popular in the Naval Services around he would. Although the origins are somewhat unknown, it is thought to be based on an old Indian game called Patrisi. Essentially it's a pumped up game of Ludo, but the fun in playing the game is not just the game, it's the interaction of the people.
Initially I created the game in Flash as a single player version, using some very simple AI. Now it's time to look at a multiplayer version using HTML5 Canvas. Again building in stages and using C# MVC and updates via JSON. The reason for using C# web service is to separate the game engine from the presentation layer, allowing a more complex AI for single player usage later on, removing the requirement for one user to run their game as a server, opening sockets so client can connect.

Building the Game


Setting up the frameworks

First things first, I want to make sure that this goes as smoothly as possible so I opted for VS2010 and MVC 4.  Although I was thinking of installing Html5 Boilerplate, I opted to just use the standard Html5 and use the latest JQuery (at the time was 2.0).

Setting up the initial connectivity to social media is already part of the framework, but I did make a few enhancements with thanks to Pranav Rastogi blog post
Integrate OpenAuth/OpenID with your existing ASP.NET application using Universal Providers

Unit testing was done using NUnit and Rhino Mocks.

Board Layout

I like the use of JavaScript Closure but there is no reason why you can't just write this out in a script. This is not a live or commercial version, just demo code.

  
var Uckers = Uckers || {};
Uckers.Gameboard = Uckers.Gameboard || {};
Uckers.Gameboard.Common = $.extend(Uckers.Gameboard.Common || {}, function () {

....

    return {
        Initialise: initialise
    };
} ());  

  
Defining the co-ordinate system which will be used throughout the code was an important first step.

       var coordinate = function (x, y) {
        this.x = x;
        this.y = y;
    };  
Next was to define what a ucker was, although this will change in the next few parts we can still define the basic structure.


      var ucker = function (coord, target, radius, color) {
        this.x = coord.x;
        this.y = coord.y;
        this.targetx = target.x;
        this.targety = target.y;
        this.radius = radius;
        this.color = color[0];
        this.shadow = color[1];
        this.colors = color;
    };  

I also wanted to define the start locations for each of the uckers, the colours and it's shadows


   var uckers = [];

    var uckerRadius = 15;


 
    //Colour - Shadow colour

    var green = ['#397D02', '#45623C'];
    var blue = ['#42C0FB', '#35586C'];
    var red = ['#F08080', '#6F4242'];
    var yellow = ['#FCB514', '#8E6B23'];

    var uckerColours = [green, blue, red, yellow];
    //Ucker Starting Positions  

    var greenStart = [new coordinate(90, 100), new coordinate(90, 165), new coordinate(165, 100), new coordinate(165, 165)];  

    var blueStart = [new coordinate(445, 445), new coordinate(445, 515), new coordinate(515, 445), new coordinate(515, 515)];  

    var redStart = [new coordinate(90, 445), new coordinate(90, 515), new coordinate(165, 445), new coordinate(165, 515)];  

    var yellowStart = [new coordinate(445, 100), new coordinate(445, 165), new coordinate(515, 100), new coordinate(515, 165)];  


    var uckerStart = [greenStart, blueStart, redStart, yellowStart];  
 

 
 
 
By using arrays we can then loop through and create the complete set of uckers and store them in a new array.


 
  var uckerSetup = function () {  
         for (var j = 0; j < uckerStart.length; j++) {  
             for (var i = 0; i < uckerStart[j].length; i++) {  
                 uckers.push(new ucker(uckerStart[j][i], uckerStart[j][i], uckerRadius, uckerColours[j]));  
             }  
         }  
     };  

 
 
When laying out the board we can then draw the uckers using their own object information.


  for (var i = 0; i < uckers.length; i++) {  
    drawUckers(context, uckers[i]);  
 }  
  
var drawUckers = function (ctx, u) { // draw circle function  
         ctx.fillStyle = u.color;  
         ctx.shadowOffsetX = 5;  
         ctx.shadowOffsetY = 5;  
         ctx.shadowBlur = 4;  
         ctx.shadowColor = u.shadow;
         ctx.beginPath();  
         ctx.arc(u.x, u.y, u.radius, 0, Math.PI * 2, true);  
         ctx.closePath();  
         ctx.fill();  
     };  

The background is a little simpler, we just add an image of an uckers board.


     var boardImage = new Image();  
     var bgReady = false;  

 
     boardImage.onload = function () {  
         bgReady = true;  
     };  

 
     boardImage.src = "/Images/uckersboard.png";  


     var loadBoard = function () {  
         theCanvas = $("#gameboard").get(0);  
         var context = theCanvas.getContext("2d");
        if (bgReady) {
            context.drawImage(boardImage, 5, 5); 
        } 
   }; 
 

Facebook, Twitter, Google+ and Microsoft Authentication.

Using MVC 4 makes this a lot simpler than it used to be.  But to ensure that it goes smoothly we need to make some simple changes.  The default MVC4 EF5 setup means that when we first run the program several files are used to initialise the database.  We can change this later using the package manager, but initially I created a blank database and changed the connection string.



Old


connectionstring="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-Uckers-20130606091131;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-Jannersoft.Demos.Uckers-20130606091131.mdf" name="DefaultConnection" providername="System.Data.SqlClient"

New

connectionstring="Data Source=.\sqlexpress;Initial Catalog=Uckers-Dev;Integrated Security=True" name="DefaultConnection" providername="System.Data.SqlClient"



The next stage is to add our keys to the Facebook auth config. In App_Start edit the AuthConfig.cs file and enable the FAcebook OAuth.


            OAuthWebSecurity.RegisterFacebookClient(
                            appId: "169767096406585",
                            appSecret: "c180be059c784d8cba0eb44379b34c11");

A large amount of creating an initial database and creating the new tables is done by the InitializeSimpleMembershipAttribute.cs class in the filters folder, with the AccountController.cs taking a lead role in handling the authentication either via site registration or via facebook.

It is also worthwhile before doing anything to have a look at the AccountModel.cs file.  This is where the UserContext is initialised and the stucture of the UserProfile.  It is worthwhile noting that changing the UserProfile class will have no effect on the table.  It will not add any extra colums nor will it work correctly if altered.  It is tied directly into the InitializeSimpleMembershipAttribute.cs file.  We will cover how to change this file later, but it involves playing with the package migration manager and adding code to the seed method.

Run this now and trying to login via facebook will fail, we need to tell facebook to allow the url we will be using.  I am using iis8 express, so I have changed the properties of the program.


Once you login via facebook new tables are created in the database.

Later on we are going to do more with the social media connection, but for now I want to concentrate on the game.  

The next stage would be to store details of the games and the players, to do this we are going to use the Code First approach to creating the tables.

Models And Enums


   [Table("Games")]  
   public class GameModel  
   {  
     [Key]  
     [DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]  
     public Guid GameId { get; set; }  
     public List<Player> Players { get; set; }  
     public DateTime StartDate { get; set; }  
     public DateTime? EndDate { get; set; }  
   }  
   [Table("Players")]  
   public class Player  
   {  
     [Key]  
     [DatabaseGenerated(DatabaseGeneratedOption.None)]  
     public Guid PlayerId { get; set; }  
     public UserProfile User { get; set; }  
     #region EF4 method of Enum Handling  
     //public int PlayerSelectedColourEnumValue { get; set; }  
     //public SelectedColorEnum PlayerSelectedColor  
     //{  
     //  get { return (SelectedColorEnum)PlayerSelectedColourEnumValue; }  
     //  set { PlayerSelectedColourEnumValue = (int)value; }  
     //}  
     #endregion  
     public SelectedColorEnum PlayerSelectedColor { get; set; }  
   }  

Generating the Table (Code First)


This provided a basic initial setup, with a tweak or two, and it does build the tables

   public class GameDbContextInitializer : DropCreateDatabaseIfModelChanges<GamesContext>  
   {  
     protected override void Seed(GamesContext context)  
     {  
       var db = new UsersContext();  
       var userProfile = db.UserProfiles.FirstOrDefault();  
       var players = new List<Player>{ new Player{  
          PlayerSelectedColor = SelectedColorEnum.Blue, PlayerUser = userProfile}};  
       var games = new List<GameModel>  
       {  
         new GameModel{ StartDate = DateTime.UtcNow,  
            GameUser = userProfile, Players = players}  
       };  
       players.ForEach(p => context.Players.Add(p));  
       games.ForEach(g=> context.Games.Add(g));  
       context.SaveChanges();  
     }  
   }  

This does work if you are only using a single context that doesnt have complex joins to other databases.  In his example we are using the defaultConnnection to set up the database for UserProfile.

To get this to work on a single context just put the following code in the Glbal.asax Application_Start;

       Database.SetInitializer<GamesContext>(new GameDbContextInitializer());  

Using Package Manager Migration - Cleaner and recommended

http://msdn.microsoft.com/en-us/data/jj193542.aspx
Open the Package Manager Console.


run > Enable-Migrations -ContextTypeName Jannersoft.Demos.Uckers.Models.GamesContext.

This creates a new file configuration and folder migration.  This forms the basic structure required to allow the migration code and the update.  It also aids in the moving of the database from dev to prod.

run > Add-Migration InitialGameTables

Creates a migration class, which we need to make a few changes. Firstly, we need to remove the UserProfile table creattion as this has alread been created when we did the facebook part.

       CreateTable(  
         "dbo.Games",  
         c => new  
           {  
             GameId = c.Int(nullable: false, identity: true),  
             StartDate = c.DateTime(nullable: false),  
             EndDate = c.DateTime(),  
             GameUser_UserId = c.Int(),  
           })  
         .PrimaryKey(t => t.GameId)  
         .ForeignKey("dbo.UserProfile", t => t.GameUser_UserId)  
         .Index(t => t.GameUser_UserId);  
      // CreateTable(  
      //   "dbo.UserProfile",  
      //   c => new  
      //     {  
      //       UserId = c.Int(nullable: false, identity: true),  
      //       UserName = c.String(),  
      //     })  
      //   .PrimaryKey(t => t.UserId);  
       CreateTable(  
         "dbo.Players",  
         c => new  
           {  
             PlayerId = c.Int(nullable: false, identity: true),  
             PlayerSelectedColor = c.Int(nullable: false),  
             PlayerUser_UserId = c.Int(),  
             GameModel_GameId = c.Int(),  
           })  
         .PrimaryKey(t => t.PlayerId)  
         .ForeignKey("dbo.UserProfile", t => t.PlayerUser_UserId)  
         .ForeignKey("dbo.Games", t => t.GameModel_GameId)  
         .Index(t => t.PlayerUser_UserId)  
         .Index(t => t.GameModel_GameId);  

run > Update-Database

Then check the database for the tables.

Now that we have been able to generate the tables we can make changes to increase the usefulness of the UserProfile object..

Add new columns to the UserProfile object then run > Add-Migration UserProfileUpdate

  [Table("UserProfile")]  
   public class UserProfile  
   {  
     [Key]  
     [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]  
     public int UserId { get; set; }  
     public string UserName { get; set; }  
     public string FirstName { get; set; }  
     public string Surname { get; set; }  
     public string Email { get; set; }  
   }  
   public class RegisterExternalLoginModel  
   {  
     [Required]  
     [Display(Name = "User name")]  
     public string UserName { get; set; }  
     public string ExternalLoginData { get; set; }  
     public string FirstName { get; set; }  
     public string Surname { get; set; }  
     public string Email { get; set; }  
   }  


Making a dice

Making and handling the dice can be carried out with a separate JavaScript file, this separation allows later re-usage of the dice.

One of the important parts of this is understanding the business logic surrounding it.  The dice will become part of the canvas animation and as such the animation should take care of the final number to display.  the dice should only care about its own properties, dimensions and the number it should display.

It is also worthwhile noting that the click, and mouse are not events but true or false returns, perhaps I need to rename these.  With HTML5 the event is handled by the canvas.

 var Uckers = Uckers || {};  
 Uckers.Gameboard = Uckers.Gameboard || {};  
 Uckers.Gameboard.Dice = $.extend(Uckers.Gameboard.Dice || {}, function () {  
   var dx;  
   var dy;  
   var diceArray = [];  
   var horizontalLayout;  
   var diceGap = 100;  
   var radius;  
   var dheight;  
   var dwidth;  
   var dcanvas;  
   var faceStyle;  
   var die = function (posx, posy, num) {  
     this.dicex = posx;  
     this.dicey = posy;  
     this.num = num;  
   };  
   // posx = 630 posy = 50 height = 60 dotradius = 5 width = 60 face = #009966  
   var loadDice = function (canvas, posx, posy, width, height, dotradius, face, dieCount) {  
     for (var i = 0; i < dieCount; i++) {  
       diceArray.push(new die(posx, posy, 1));  
     }  
     radius = dotradius;  
     dheight = height;  
     dwidth = width;  
     dcanvas = canvas;  
     faceStyle = face;  
     setLayout(true);  
     drawDice();  
   };  
   var setLayout = function(isHorizontal) {  
     horizontalLayout = isHorizontal;  
   };  
   var drawface = function (n) {  
     var ctx = dcanvas.getContext("2d");  
     ctx.lineWidth = 5;  
     ctx.clearRect(dx, dy, dwidth, dheight);  
     ctx.strokeRect(dx, dy, dwidth, dheight);  
     ctx.fillStyle = faceStyle;  
     switch (n) {  
       case 1:  
         draw1(ctx);  
         break;  
       case 2:  
         draw2(ctx);  
         break;  
       case 3:  
         draw2(ctx);  
         draw1(ctx);  
         break;  
       case 4:  
         draw4(ctx);  
         break;  
       case 5:  
         draw4(ctx);  
         draw1(ctx);  
         break;  
       case 6:  
         draw4(ctx);  
         draw2Mid(ctx);  
         break;  
     }  
   };  
   var drawDice = function () {  
     for (var i = 0; i < diceArray.length; i++) {  
       //Get random dice number  
       diceArray[i].num = 1 + Math.floor(Math.random() * 6);  
       //check if vertical or horizontal layout  
       if (horizontalLayout) {  
         dx = diceArray[i].dicex + (diceGap * i);  
         dy = diceArray[i].dicey;  
       } else {  
         dx = diceArray[i].dicex;  
         dy = diceArray[i].dicey + (diceGap * i);  
       }  
       drawface(diceArray[i].num);  
     }  
     return diceArray;  
   };  
   var isMouseOnDice = function(e) {  
     var mouseX = e.offsetX || 0;  
     var mouseY = e.offsetY || 0;  
     for (var i = 0; i < diceArray.length; i++) {  
       if (mouseX > diceArray[i].minX && mouseX < diceArray[i].maxX && mouseY > diceArray[i].minY && mouseY < diceArray[i].maxY) {  
         return true;  
       }  
     }  
     return false;  
   };  
   var draw1 = function (ctx) {  
     var dotx;  
     var doty;  
     ctx.beginPath();  
     dotx = dx + .5 * dwidth;  
     doty = dy + .5 * dheight;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   };  
   var draw2 = function (ctx) {  
     var dotx;  
     var doty;  
     ctx.beginPath();  
     dotx = dx + 3 * radius;  
     doty = dy + 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     dotx = dx + dwidth - 3 * radius;  
     doty = dy + dheight - 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   };  
   var draw4 = function (ctx) {  
     var dotx;  
     var doty;  
     ctx.beginPath();  
     dotx = dx + 3 * radius;  
     doty = dy + 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     dotx = dx + dwidth - 3 * radius;  
     doty = dy + dheight - 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
     ctx.beginPath();  
     dotx = dx + 3 * radius;  
     doty = dy + dheight - 3 * radius; //no change  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     dotx = dx + dwidth - 3 * radius;  
     doty = dy + 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   };  
   var draw2Mid = function (ctx) {  
     var dotx;  
     var doty;  
     ctx.beginPath();  
     dotx = dx + 3 * radius;  
     doty = dy + .5 * dheight;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     dotx = dx + dwidth - 3 * radius;  
     doty = dy + .5 * dheight; //no change  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   };  
   return {  
     Initialize: loadDice,  
     Roll: drawDice,  
     DiceGap: diceGap,  
     IsHorizontalLayout: setLayout,  
     Click: isMouseOnDice,  
     MouseOver: isMouseOnDice,  
     MouseDown: isMouseOnDice,  
     MouseUp: isMouseOnDice,  
     Dice:diceArray  
   };  
 }());  

calling a dice

dice = Uckers.Gameboard.Dice;
        dice.Initialize(theCanvas, 630, 50, 60, 60, 4, '#009966', 2);

Adding a Dice Button

We could easily set up a small area to test for a mouse event but to be able to extend this button we can be a little more adventurous.

 Uckers.Gameboard.CanvasButton = $.extend(Uckers.Gameboard.Button || {}, function() {  
   var ctx;  
   var minX;  
   var minY;  
   var boxX;  
   var boxY;  
   var text;  
   var textColor;  
   var fillColor;  
   var lineColor;  
   var lineWidth;  
   var font;  
   var width;  
   var height;  
   var btn = function() {  
     this.canvas = arguments[0].canvas || $("canvas").get(0);  
     this.ctx = arguments[0].ctx || this.canvas.getContext("2d");  
     this.text = arguments[0].text || "Submit";  
     this.textColor = arguments[0].color || "#5E5E5E";  
     this.fontSize = arguments[0].fontSize || 18;  
     this.fontTypeFace = arguments[0].fontTypeFace || "sans-serif";  
     this.font = arguments[0].font || this.fontSize + "px " + this.fontface;  
     this.ctx.font = this.font;  
     this.width = arguments[0].width || this.ctx.measureText(this.text).width;  
     this.height = arguments[0].height || this.fontSize;  
     this.minX = arguments[0].posx || this.canvas.width;  
     // this.maxX = this.minX + this.width ;  
     this.minY = arguments[0].posy || this.canvas.height;  
     // this.maxY = this.minY + this.height ;  
     this.id = arguments[0].id || "undefined";  
     this.active = true;  
     this.lineColor = arguments[0].linecolor || "#FFFF00";  
     this.lineWidth = arguments[0].linewidth || 1;  
     this.fillColor = arguments[0].fillcolor || "00FFFF";  
     this.borderWidth = arguments[0].boarderwidth || 2;      
     ctx = this.ctx;  
     minX = this.minX;  
     minY = this.minY;  
     text = this.text;  
     textColor = this.textColor;  
     fillColor = this.fillColor;  
     lineColor = this.lineColor;  
     lineWidth = this.lineWidth;  
     font = this.font;  
     width = this.width + 15;  
     height = this.height + 4;  
     drawLabel();  
     this.click = function(e) {  
       var mouseX = e.offsetX || 0;  
       var mouseY = e.offsetY || 0;  
       return mouseX > boxX && mouseX < (boxX + width) && mouseY > boxY && mouseY < (boxY + height) && this.active;  
     };  
   };  
   var settext = function() {  
     text = arguments[0].text || "Submit";  
     textColor = arguments[0].color || "#5E5E5E";  
     this.fontSize = arguments[0].fontSize || 18;  
     this.fontTypeFace = arguments[0].fontTypeFace || "sans-serif";  
     font = arguments[0].font || this.fontSize + "px " + this.fontface;  
     ctx.font = font;  
     width = (arguments[0].width || ctx.measureText(this.text).width) + 15;  
     height = (arguments[0].height || this.fontSize) + 4;  
     drawLabel();  
   };  
   var drawLabel = function() {  
     ctx.lineWidth = 2;  
     boxX = minX - 5;  
     boxY = minY - 15;  
     ctx.clearRect(boxX, boxY, width, height);  
     ctx.strokeRect(boxX,boxY, width, height);  
     ctx.fillStyle = fillColor;  
     ctx.lineWidth = lineWidth;  
     ctx.fillStyle = textColor;  
     ctx.lineStyle = lineColor;  
     //calculate the center position for the text  
     // width of the box minus the width of the text divide by two then add to the posx  
     var textPos = (width - ctx.measureText(text).width) / 2;  
     ctx.fillText(text, minX + textPos, minY);  
   };  
   return {  
     Button: btn,  
     Text : settext  
   };  
 }());  

Setup the button

diceButton = new Uckers.Gameboard.CanvasButton.Button({ ctx: context, posx: 660, posy: 135, text: "Stop!" });

Placing the Uckers

The initail placement of the uckers is a two stage process.  Trying to keep this to the client model update and instantiate the uckers from the javascript.  We could make a call to the server and request the locations and update from a Json response, but we need to think about the number of server calls during the initial setup.  We could lso make it part of the model and load this onto the page, but again it come to decide on where the balance of saving this information is kept.  In this case we are going to save this as part of the javascript and do all the work in a single hit.

  var uckers = [];  
   var uckerRadius = 15;  
   //Colour - Shadow colour  
   var green = ['#397D02', '#45623C', "green"];  
   var blue = ['#42C0FB', '#35586C', "blue"];  
   var red = ['#F08080', '#6F4242', "red"];  
   var yellow = ['#FCB514', '#8E6B23', "yellow"];  
   var uckerColours = [green, blue, red, yellow];  

In the section above we layout the basic information about an ucker, we then send this to an ucker object and save this in an array of uckers.
   var ucker = function (coord, target, radius, color, name) {  
     this.uckerId = 0;  
     this.name = name;  
     this.x = coord.x;  
     this.y = coord.y;  
     //target [4,1] target A = [0,0] = x, [0,1] = y, Target B = [1,0] = x, [1,1] = y  
     this.target = target;  
     this.selectedtargetx;  
     this.selectedtargety;  
     this.radius = radius;  
     this.color = color[0];  
     this.shadow = color[1];  
     this.colors = color;  
     this.boardPosition = 0;  
     this.IsActive = false;  
   };  

We use a couple of extra object in this, but one of the things that spring out is the Target.  This is a set of co-ordinates for this ucker.  As there are two dice, an ucker could have the potential to move to either.  Once an ucker is selected (after the dice is selected) the it is moved to the selected target.

Here is the JavaScript in it's full.

 var Uckers = Uckers || {};  
 Uckers.Gameboard = Uckers.Gameboard || {};  
   
 Uckers.Gameboard.Ucker = $.extend(Uckers.Gameboard.Ucker || {}, function () {  
   
   var coordinate = function (x, y) {  
     this.x = x;  
     this.y = y;  
   };  
   
   //Ucker Starting Positions  
   var greenStart = [new coordinate(90, 100), new coordinate(90, 165), new coordinate(165, 100), new coordinate(165, 165)];  
   var blueStart = [new coordinate(445, 445), new coordinate(445, 515), new coordinate(515, 445), new coordinate(515, 515)];  
   var redStart = [new coordinate(90, 445), new coordinate(90, 515), new coordinate(165, 445), new coordinate(165, 515)];  
   var yellowStart = [new coordinate(445, 100), new coordinate(445, 165), new coordinate(515, 100), new coordinate(515, 165)];  
   
   //Colour - Shadow colour  
   var green = ['#397D02', '#45623C', "green"];  
   var blue = ['#42C0FB', '#35586C', "blue"];  
   var red = ['#F08080', '#6F4242', "red"];  
   var yellow = ['#FCB514', '#8E6B23', "yellow"];  
   
   var uckerStart = [greenStart, blueStart, redStart, yellowStart];  
   
   var uckerRadius = 15;  
   
   var uckers = [];  
   
   var ucker = function (coord, target, radius, color) {  
     this.uckerId = 0;  
   
     this.radius = radius;  
     this.x = coord.x;  
     this.y = coord.y;  
   
     this.boardPosition = 0;  
     //target [4,1] target A = [0,0] = x, [0,1] = y, Target B = [1,0] = x, [1,1] = y  
     this.target = target;  
     this.selectedtargetx;  
     this.selectedtargety;  
   
     this.colors = color;  
     this.color = color[0];  
     this.shadow = color[1];  
     this.name = color[2];  
   
     this.IsActive = false;  
   };  
   
   var uckerSetup = function () {  
     for (var j = 0; j < uckerStart.length; j++) {  
       for (var i = 0; i < uckerStart[j].length; i++) {  
         uckers.push(new ucker(uckerStart[j][i], uckerStart[j][i], uckerRadius, uckerColours[j]));  
       }  
     }  
   };  
   
   var drawUckers = function (ctx, u) { // draw circle function  
     ctx.fillStyle = u.color;  
     ctx.shadowOffsetX = 5;  
     ctx.shadowOffsetY = 5;  
     ctx.shadowBlur = 4;  
     ctx.shadowColor = u.shadow;  
     ctx.beginPath();  
     ctx.arc(u.x, u.y, u.radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   
     //reset shaddows so it doesnt affect teh background  
     ctx.shadowOffsetX = 0;  
     ctx.shadowOffsetY = 0;  
     ctx.shadowBlur = 0;  
   };  
   
   var getUckerColor = function (c) {  
     for (var i = 0; i < uckerColours.length; i++) {  
       if (uckerColours[i][2] == c) {  
         return uckerColours[i];  
       }  
     }  
     return null;  
   };  
   
   var uckerEvent = function (mouseX, mouseY) {  
     for (var j = 0; j < Ucker.uckers.length; j++) { // checking through all circles - are mouse down inside circle or not  
       var uckerX = Ucker.uckers[j].x;  
       var uckerY = uckers[j].y;  
       var radius = uckers[j].radius;  
       if (Math.pow(mouseX - uckerX, 2) + Math.pow(mouseY - uckerY, 2) < Math.pow(radius, 2) && uckers[j].IsActive) {  
         //Check to see if the selected ucker is home  
   
         var coord = new coordinate(uckerX, uckerY);  
         uckers[j] = new ucker(coord, target, radius, uckers[j].colors);  
         break;  
       }  
     }  
   };  
   
   var getAllUckers = function () {  
     return uckers;  
   };  
   
   var drawUckers = function (ctx) {  
     for (var i = 0; i < uckers.length; i++) {  
       drawUckers(ctx, uckers[i]);  
     }  
   };  
   
   var initialise = function () {  
     uckerSetup();  
   };  
   
   return {  
     Initailize: initialise,  
     GetUckerColor: getUckerColor,  
     Uckers: getAllUckers,  
     DrawUckers: drawUckers,  
     Ucker: ucker,  
     UckerEvent: uckerEvent  
   }  
   
 }());  


In Part two we will be doing a lot more with the following:

Setting up Players

Sending JSON

Responding to JSON

Storing Data

End of Turn


No comments:

Post a Comment