HTML5 Game Development for Windows 8 #2: Adding a player

image

Hi, and welcome back to the HTML5 game programming tutorial series. In this tutorial we will continue on the previous tutorial, so if you havent done so yet, now is the time! 🙂

Note: This was written on the plane to Las Vegas in a tired condition. Will fix typos at a later stage.

Last time, we got the main menu up and running. Now we are going to make the main menu screen wait for a touch input, and when that happens, it will start the game and a player is rendered.

The first thing we need is a boolean that tells if we are going to show the main menu or not.

Define the newGame global variable:

   1: var canvas, context;

   2: var gameStage;

   3: var preload;

   4:  

   5: var logoScreenImage, logoScreenBitmap;

   6:  

   7: var newGame = true;

The newGame variable will be used to let our stage know what elements it should display. When we are in the main menu, we hide the game elements and only show the main menu screen.

This will be handled in the update() function (remeber, this is where the game logic is handled). You can use the visible-property of the Bitmap you want to control to make it visible or invisible:

   1: function update() {

   2:     if (newGame) {

   3:         logoScreenBitmap.visible = true;

   4:     }

   5:     else {

   6:         logoScreenBitmap.visible = false;

   7:     }

   8: }

New, the last thing we need in order to acctually change the scene is to wait for the user to touch the screen so the game can start:

In the initialize() function, after the context = canvas.getContext(“2d”); line of code, add the following line:

   1: canvas.addEventListener("MSPointerUp", pointerUp, false);

This function creates an event listener that will trigger when the user lifts up his finger (or release the mouse pointer). When this triggers, the function pointerUp is executed.

Let’s take a look at the pointerUp function:

   1: function pointerUp(event) {

   2:     if (newGame) {

   3:         newGame = false;

   4:     }

   5:     else {

   6:     }

   7: }

This function sets the newGame boolean to false when it triggers a new release of the funger/mouse pointer.

Now it’s time to add the player character and the ghost house floor. To do this, we need a few global variables and a class that contains the player logic.

Add the following global variables:

   1: var player;

   2:  

   3: var floorImage, floorBitmap;

   4: var playerIdleImage, playerIdleBitmap;

We also need a variable that will help us keep track of scaling. When the game is deployed to various devices, it’s important that we scale the playfield to make sure it works on all devices.

All the games GFX is made with the 1366 x 768 resolution as the basis. If the resolution changes, we also want to make sure to scale everything. To do this we create two variables :

   1: var scaleW = window.innerWidth / 1366;

   2: var scaleH = window.innerHeight / 768;

 

Now, let’s make sure that the main menu screen scales.

Add the lines with the scale properties to your loadContent() function, where you define and load the mainMenuBitmap:

   1: logoScreenBitmap.scaleX = scaleW;

   2: logoScreenBitmap.scaleY = scaleH;

Also, load the floor texture and the playerIdle texture:

   1: logoScreenImage = preload.getResult("logoScreen").result;

   2: logoScreenBitmap = new createjs.Bitmap(logoScreenImage);

   3: logoScreenBitmap.scaleX = scaleW;

   4: logoScreenBitmap.scaleY = scaleH;

   5: gameStage.addChild(logoScreenBitmap);

   6:  

   7: floorImage = preload.getResult("floor").result;

   8: floorBitmap = new createjs.Bitmap(floorImage);

   9: floorBitmap.visible = false;

  10: floorBitmap.scaleX = scaleW;

  11: floorBitmap.scaleY = scaleH;

  12: gameStage.addChild(floorBitmap);

  13:  

  14: playerIdleImage = preload.getResult("playerIdle").result;

  15: playerIdleBitmap = new createjs.Bitmap(playerIdleImage);

  16: playerIdleBitmap.visible = false;

  17: playerIdleBitmap.scaleX = scaleW;

  18: playerIdleBitmap.scaleY = scaleH;

  19: gameStage.addChild(playerIdleBitmap);

 

We load the needed graphics, and also set the visibility properties to invisible, making sure we don’t draw them on the main menu.

Also, update the update() function so it hides/shows player and floor:

   1: function update() {

   2:     if (newGame) {

   3:         logoScreenBitmap.visible = true;

   4:         playerIdleBitmap.visible = false;

   5:         floorBitmap.visible = false;

   6:     }

   7:     else {

   8:         logoScreenBitmap.visible = false;

   9:         playerIdleBitmap.visible = true;

  10:         floorBitmap.visible = true;

  11:     }

  12: }

 

If you run the game now, you will see the main screen showing. Tapping this will make the main screen go away and you will get in to the playfield.

The player needs a position where it will be rendered, and a target to where he is heading. Also, we need to keep track of the bitmap size in order to calculate collision detection later:

   1: // The player class

   2: function Player() {

   3:     this.positionX = window.innerWidth / 2;

   4:     this.positionY = window.innerHeight / 2;

   5:  

   6:     this.targetX = this.positionX;

   7:     this.targetY = this.positionY;

   8:  

   9:     this.width = playerIdleBitmap.image.width * scaleW;

  10:     this.height = playerIdleBitmap.image.height * scaleH;

  11: }

Let’s make sure we can move our guy. We want to make him move to the last location the user eiter touched or moved the finger (mousepointer).

In the prepareStage function we create a new instance of the player, add this line above the Ticker.setInterval line of code:
player = new Player();

To make the player move you could either create a function in the player class that moves it based on his target, or put the logic in the update function. I will do both, the player class will get updated directly in the update() function, and the ghosts will be moved with a function on the ghost class level.

At every frame, we check if we should move our guy. It his position is different than the target, move it towards the target. One way to do this is to use a vector, or by directly checking the X and Y values of the position. I will do the latter:

   1: function update() {

   2:     if (newGame) {

   3:         logoScreenBitmap.visible = true;

   4:         playerIdleBitmap.visible = false;

   5:         floorBitmap.visible = false;

   6:     }

   7:     else {

   8:         logoScreenBitmap.visible = false;

   9:         playerIdleBitmap.visible = true;

  10:         floorBitmap.visible = true;

  11:  

  12:         if (player.targetX > player.positionX) {

  13:             player.positionX += 3;

  14:         }

  15:         if (player.targetX < player.positionX) {

  16:             player.positionX -= 3;

  17:         }

  18:         if (player.targetY > player.positionY) {

  19:             player.positionY += 3;

  20:         }

  21:         if (player.targetY < player.positionY) {

  22:             player.positionY -= 3;

  23:         }

  24:     }

  25: }

 

Now, we add a few more event listeners that will make our character move:

   1: function initialize() {

   2:     canvas = document.getElementById("gameCanvas");

   3:     canvas.width = window.innerWidth;

   4:     canvas.height = window.innerHeight;

   5:     context = canvas.getContext("2d");

   6:  

   7:     canvas.addEventListener("MSPointerUp", pointerUp, false);

   8:     canvas.addEventListener("MSPointerMove", pointerMove, false);

   9:     canvas.addEventListener("MSPointerDown", pointerDown, false);

  10:  

  11:     gameStage = new createjs.Stage(canvas);

  12:  

  13:     loadContent();

  14: }

 

Let’s start by updating the pointerUp function. We need it to take in a parameter that will contain the touch position, and set the players target to this:

   1: function pointerUp(event) {

   2:     if (newGame) {

   3:         newGame = false;

   4:     }

   5:     else {

   6:         player.targetX = event.x;

   7:         player.targetY = event.y;

   8:     }

   9: }

Also, lets add the two others as well:

   1: function pointerDown(event) {

   2:     if (newGame) {

   3:     }

   4:     else {

   5:         player.targetX = event.x;

   6:         player.targetY = event.y;

   7:     }

   8: }

   9:  

  10: function pointerMove(event) {

  11:     if (newGame) {

  12:     }

  13:     else {

  14:         player.targetX = event.x;

  15:         player.targetY = event.y;

  16:     }

  17: }

 

The last thing we need to do is to update the player image to be rendered at the player positon. Add the following lines in the update function, below the code that makes the player move:

   1: playerIdleBitmap.x = player.positionX - (player.width / 2);

   2: playerIdleBitmap.y = player.positionY - (player.height / 2);

We want the center of the guy to move towards the location of the finger, not the top-left. thats why we subtract half of the height and width of the character.

The update() function should look like this:

   1: function update() {

   2:     if (newGame) {

   3:         logoScreenBitmap.visible = true;

   4:         playerIdleBitmap.visible = false;

   5:         floorBitmap.visible = false;

   6:     }

   7:     else {

   8:         logoScreenBitmap.visible = false;

   9:         playerIdleBitmap.visible = true;

  10:         floorBitmap.visible = true;

  11:  

  12:         if (player.targetX > player.positionX) {

  13:             player.positionX += 3;

  14:         }

  15:         if (player.targetX < player.positionX) {

  16:             player.positionX -= 3;

  17:         }

  18:         if (player.targetY > player.positionY) {

  19:             player.positionY += 3;

  20:         }

  21:         if (player.targetY < player.positionY) {

  22:             player.positionY -= 3;

  23:         }

  24:  

  25:         playerIdleBitmap.x = player.positionX - (player.width / 2);

  26:         playerIdleBitmap.y = player.positionY - (player.height / 2);

  27:     }

  28: }

 

If you run the app now, you should be able to move the guy!

Below is the entire source for this game:

   1: // For an introduction to the Blank template, see the following documentation:

   2: // http://go.microsoft.com/fwlink/?LinkId=232509

   3: (function () {

   4:     "use strict";

   5:  

   6:     WinJS.Binding.optimizeBindingReferences = true;

   7:  

   8:     var app = WinJS.Application;

   9:     var activation = Windows.ApplicationModel.Activation;

  10:  

  11:     var canvas, context;

  12:     var gameStage;

  13:     var preload;

  14:  

  15:     var logoScreenImage, logoScreenBitmap;

  16:     var floorImage, floorBitmap;

  17:     var playerIdleImage, playerIdleBitmap;

  18:  

  19:     var newGame = true;

  20:  

  21:     var player;

  22:  

  23:     var scaleW = window.innerWidth / 1366;

  24:     var scaleH = window.innerHeight / 768;

  25:  

  26:  

  27:     app.onactivated = function (args) {

  28:         if (args.detail.kind === activation.ActivationKind.launch) {

  29:             if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {

  30:                 // TODO: This application has been newly launched. Initialize

  31:                 // your application here.

  32:             } else {

  33:                 // TODO: This application has been reactivated from suspension.

  34:                 // Restore application state here.

  35:             }

  36:             args.setPromise(WinJS.UI.processAll());

  37:         }

  38:     };

  39:  

  40:     // The player class

  41:     function Player() {

  42:         this.positionX = window.innerWidth / 2;

  43:         this.positionY = window.innerHeight / 2;

  44:  

  45:         this.targetX = this.positionX;

  46:         this.targetY = this.positionY;

  47:  

  48:         this.width = playerIdleBitmap.image.width * scaleW;

  49:         this.height = playerIdleBitmap.image.height * scaleH;

  50:     }

  51:  

  52:  

  53:     function pointerUp(event) {

  54:         if (newGame) {

  55:             newGame = false;

  56:         }

  57:         else {

  58:             player.targetX = event.x;

  59:             player.targetY = event.y;

  60:         }

  61:     }

  62:  

  63:     function pointerDown(event) {

  64:         if (newGame) {

  65:         }

  66:         else {

  67:             player.targetX = event.x;

  68:             player.targetY = event.y;

  69:         }

  70:     }

  71:  

  72:     function pointerMove(event) {

  73:         if (newGame) {

  74:         }

  75:         else {

  76:             player.targetX = event.x;

  77:             player.targetY = event.y;

  78:         }

  79:     }

  80:  

  81:     function initialize() {

  82:         canvas = document.getElementById("gameCanvas");

  83:         canvas.width = window.innerWidth;

  84:         canvas.height = window.innerHeight;

  85:         context = canvas.getContext("2d");

  86:  

  87:         canvas.addEventListener("MSPointerUp", pointerUp, false);

  88:         canvas.addEventListener("MSPointerMove", pointerMove, false);

  89:         canvas.addEventListener("MSPointerDown", pointerDown, false);

  90:  

  91:         gameStage = new createjs.Stage(canvas);

  92:  

  93:         loadContent();

  94:     }

  95:  

  96:     function loadContent() {

  97:         preload = new createjs.PreloadJS();

  98:         preload.onComplete = prepareStage;

  99:  

 100:         var manifest = [

 101:             { id: "logoScreen", src: "images/GFX/LogoScreen.png" },

 102:             { id: "floor", src: "images/GFX/floor.png" },

 103:             { id: "ghost", src: "images/GFX/Ghost.png" },

 104:             { id: "playerIdle", src: "images/GFX/PlayerIdle.png" }

 105:         ];

 106:  

 107:         preload.loadManifest(manifest);

 108:     }

 109:  

 110:     function prepareStage() {

 111:         logoScreenImage = preload.getResult("logoScreen").result;

 112:         logoScreenBitmap = new createjs.Bitmap(logoScreenImage);

 113:         logoScreenBitmap.scaleX = scaleW;

 114:         logoScreenBitmap.scaleY = scaleH;

 115:         gameStage.addChild(logoScreenBitmap);

 116:  

 117:         floorImage = preload.getResult("floor").result;

 118:         floorBitmap = new createjs.Bitmap(floorImage);

 119:         floorBitmap.visible = false;

 120:         floorBitmap.scaleX = scaleW;

 121:         floorBitmap.scaleY = scaleH;

 122:         gameStage.addChild(floorBitmap);

 123:  

 124:         playerIdleImage = preload.getResult("playerIdle").result;

 125:         playerIdleBitmap = new createjs.Bitmap(playerIdleImage);

 126:         playerIdleBitmap.visible = false;

 127:         playerIdleBitmap.scaleX = scaleW;

 128:         playerIdleBitmap.scaleY = scaleH;

 129:         gameStage.addChild(playerIdleBitmap);

 130:  

 131:         player = new Player();

 132:  

 133:         createjs.Ticker.setInterval(window.requestAnimationFrame);

 134:         createjs.Ticker.addListener(gameLoop);

 135:     }

 136:  

 137:     function gameLoop() {

 138:         update();

 139:         draw();

 140:     }

 141:  

 142:     function update() {

 143:         if (newGame) {

 144:             logoScreenBitmap.visible = true;

 145:             playerIdleBitmap.visible = false;

 146:             floorBitmap.visible = false;

 147:         }

 148:         else {

 149:             logoScreenBitmap.visible = false;

 150:             playerIdleBitmap.visible = true;

 151:             floorBitmap.visible = true;

 152:  

 153:             if (player.targetX > player.positionX) {

 154:                 player.positionX += 3;

 155:             }

 156:             if (player.targetX < player.positionX) {

 157:                 player.positionX -= 3;

 158:             }

 159:             if (player.targetY > player.positionY) {

 160:                 player.positionY += 3;

 161:             }

 162:             if (player.targetY < player.positionY) {

 163:                 player.positionY -= 3;

 164:             }

 165:  

 166:             playerIdleBitmap.x = player.positionX - (player.width / 2);

 167:             playerIdleBitmap.y = player.positionY - (player.height / 2);

 168:         }

 169:     }

 170:  

 171:     function draw() {

 172:         gameStage.update();

 173:     }

 174:  

 175:     app.oncheckpoint = function (args) {

 176:         // TODO: This application is about to be suspended. Save any state

 177:         // that needs to persist across suspensions here. You might use the

 178:         // WinJS.Application.sessionState object, which is automatically

 179:         // saved and restored across suspension. If you need to complete an

 180:         // asynchronous operation before your application is suspended, call

 181:         // args.setPromise().

 182:     };

 183:  

 184:     document.addEventListener("DOMContentLoaded", initialize, false);

 185:  

 186:     app.start();

 187: })();

 188:  

In the next tutorial, we will finish the game. This includes handling all the ghosts and keeping track of the score, and a game over function.

image

Download the source of the game here:
http://sdrv.ms/T2KTFg

This entry was posted in Game programming, Tutorial, Windows 8. Bookmark the permalink.

5 Responses to HTML5 Game Development for Windows 8 #2: Adding a player

  1. Pingback: HTML5 Game Starter Kit for Windows 8 | digitalerr0r

  2. Pingback: Windows 8 Games with CreateJS Tutorials & Resources « skater coder

  3. Roudoudou. says:

    Bonjour.
    Ces lignes de code sont parfaites et le jeu fonctionne très bien.
    Bravo à l’auteur.
    Avez-vous d’autres sources concernant des jeux dans le même style sur Windows 8 en HTML5?
    Je vous remercie beaucoup et encore bravo

    Cordialement.

  4. Pingback: Game Starterkit for Windows 8 with leaderboard in Windows Azure | digitalerr0r

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.