Compare v05 to v06
Produced: 13/1/17 5:35:48 pm
   
Mode:  All  
Left file: /Users/peetj/github/cs-js-beg-platformer/versions/game-05.js  
Right file: /Users/peetj/github/cs-js-beg-platformer/versions/game-06.js  
1 1 /* GLOBAL STATE VARIABLES START WITH A __ */
2 2 var _player = null;
3 3 var _viewportX = 0;
4 4 var _scoreDisplay = "";
5 5 var _gameStartTime = (new Date()).getTime();
6 6 var _timeLeftDisplay = "";
7 7 var _secondsTotal = 120;
8 8  
9 9 /* State */
10 10 var __STATE = {};
11 11 __STATE.level = 1;
12 12 __STATE.gameStarted = false;
13 13 __STATE.gameOver = false;
14 14 __STATE.timeLeft = _secondsTotal;
15 15 __STATE.currentScore = 0;
16 16 __STATE.gameOverIsDisplaying = false;
17 17 __STATE.numCoinsToCollect = -1;
18 18  
19 19 const PLAYER_SPEED = 4;
20 20 const WALKER_VELOCITY = -80;
21 21 const EVENT_PLAYER_DIE = "EVENT_PLAYER_DIE";
22 22 const EVENT_PLAYER_HIT_WALKER = "EVENT_PLAYER_HIT_WALKER";
23 23 const EVENT_PLAYER_HIT_WALL = "EVENT_PLAYER_HIT_WALL";
24 24 const EVENT_GAME_OVER = "EVENT_GAME_OVER";
25 25  
26 26 const SCREENWIDTH = 800;
27 27 const SCREENHEIGHT = 600;
28 28 const TILE_WIDTH = 80;
29 29 const TILE_HEIGHT = 60;
30 30 const GRAVITY_STRENGTH = 1000;
31 31 const RIGHT = 0;
32 32 const LEFT = 1;
33 33 const NONE = 2;
34 34  
35 35 var _player = null;
36 36  
37 37 var tileMap = [
38 38   [[0,1],[8,1],[0,13],[4,1],[0,8],[8,1],[0,5],[4,1],[0,7],[8,1],[0,6],[8,1],[0,2]],
39 39   [[0,8],[4,1],[0,3],[4,1],[0,6],[8,1],[0,28]],
40 40   [[0,8],[0,24],[4,1],[0,3],[4,1],[0,6],[8,1],[0,4]],
41 41   [[0,11],[4,1],[0,15],[4,1],[0,13],[4,1],[0,6]],
42 42   [[0,16],[8,1],[0,19],[8,1],[0,11]],
43 43   [[0,9],[4,1],[0,38]],
44 44   [[0,48]],
45 45   [[1,48]]
46 46 ];
47 47  
48 48 Crafty.init(800, 600, document.getElementById('gamecanvas'));
49 49 setupGlobalBindings();
50 50  
51 51 var assets = {'tiles': ['img/tile-1.png', 'img/platform.png', 'img/platformx2.png']};
52 52 var playerSprite = { 'sprites': { 'img/playerSprite.png': { tile: 50, tileh: 77, map: { man_left: [0, 1], man_right: [0, 2], jump_right: [6, 4] } } } };
53 53  
54 54 initialiseGame();
55 55  
56 56 function initialiseGame () {
57 57   Crafty.load(assets, function(){
58 58     reset();
59 59     loadBackground();
60 60     loadSprites();
61 61     generateMap();
62 62     spawnEntities();
63 63     displayText();
64 64     /* Load sounds */
65 65     Crafty.audio.add("coin", "sounds/coin.wav");
66 66     __STATE.gameStarted = true;
67 67   });
68 68 }
69 69  
70 70 function loadBackground () {
71 71   Crafty.background('#3BB9FF');
72 72   //Crafty.background('#FFFFFF url(img/bg.png) repeat-x center center');
73 73 }
74 74  
75 75 function loadSprites () {
76 76   Crafty.load(playerSprite);
  77   Crafty.load(walkerSprite);
77 78 }
78 79  
79 80 function spawnEntities () {
80 81   spawnPlayer();
  82   spawnWalkers();
81 83 }
82 84  
83 85 function spawnPlayer (){
84 86   _player = Crafty.e('Player, 2D, DOM, man_right, SpriteAnimation, Twoway, Collision, Gravity, Tween, Keyboard')
85 87     .attr({
86 88       x: 50,
87 89       y: 263
88 90     })
89 91     .reel('moveRight', 500, [[0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2]])
90 92     .reel('moveLeft', 500, [[0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1]])
91 93     .twoway(200, 510)
92 94     .gravity('FloorTile')
93 95     .gravityConst(GRAVITY_STRENGTH)
94 96     .bind('KeyDown',
95 97       function (e) {
96 98         if (Crafty.keydown['37'] && Crafty.keydown['39']) {
97 99           this.pauseAnimation();
98 100           this.resetAnimation();
99 101           this.isMoving = false;
100 102           return;
101 103         }
102 104         if (e.key === Crafty.keys.RIGHT_ARROW && !this.isJumping) {
103 105           this.animate('moveRight', -1);
104 106         }
105 107         else if (e.key === Crafty.keys.LEFT_ARROW && !this.isJumping) {
106 108           this.animate('moveLeft', -1);
107 109         }
108 110         this.isMoving = true;
109 111       }
110 112     )
111 113     .bind('KeyUp',
112 114       function (e) {
113 115         if ((this.isPlaying('moveRight') && e.key === Crafty.keys.RIGHT_ARROW) ||
114 116           (this.isPlaying('moveLeft') && e.key === Crafty.keys.LEFT_ARROW)) {
115 117           this.pauseAnimation();
116 118           this.resetAnimation();
117 119           /* Check/Set the player's moving state */
118 120           if (e.key === Crafty.keys.RIGHT_ARROW || e.key === Crafty.keys.LEFT_ARROW) {
119 121             this.isMoving = false;
120 122             return;
121 123           }
122 124         }
123 125         /* Kickstart animation if we need to */
124 126         if (this.isDown('RIGHT_ARROW') && !this.isJumping) {
125 127           this.animate('moveRight', -1);
126 128           this.isMoving = true;
127 129         }
128 130         else if (this.isDown('LEFT_ARROW') && !this.isJumping) {
129 131           this.animate('moveLeft', -1);
130 132           this.isMoving = true;
131 133         }
132 134       }
133 135     )
134 136     .bind('Moved', function (obj) {
135 137       if (this.x >= (SCREENWIDTH / 2) && this.x <= 3440) {
136 138         Crafty.viewport.scroll('_x', (this.x - (SCREENWIDTH / 2)) * -1);
137 139         displayScore();
138 140         displayTimeLeft();
139 141       }
140 142     })
141 143     .bind('CheckJumping', function (ground) {
142 144       this.isJumping = true;
143 145       var  canJump, doubleJump;
144 146       if(this.canJump === false && !this.inDoubleJumpMode){
145 147         /* Lets check if there is a platform above us */
146 148         var platforms = Crafty('Tile');
147 149         for(var i=0; i < platforms.length; i++){
148 150           var platform = platforms[i];
149 151           platform = Crafty(platform);
150 152           if(platform.x < this.x && platform.y < this.y && platform.x+160 > this.x){
151 153             /* We probably have a platform above us so don't allow double jump */
152 154             canJump = false;
153 155             doubleJump = false;
154 156             break;
155 157           }
156 158         }
157 159         this.canJump = canJump !== undefined ? canJump : true;
158 160         this.inDoubleJumpMode = doubleJump !== undefined ? doubleJump : true;
159 161       }
160 162       else if(this.inDoubleJumpMode){
161 163         this.canJump = false;
162 164       }
163 165       this.pauseAnimation();
164 166       this.resetAnimation();
165 167       this.sprite(this.currentDirection === RIGHT ? 6 : 2, 4);
166 168     })
167 169     .bind('LandedOnGround', function (ground) {
168 170       if (this.isJumping) {
169 171         this.isJumping = false;
170 172         this.gravityConst(GRAVITY_STRENGTH);
171 173         /* We cannot get the direction from the velocity. We'll use the current loaded sprite animation  */
172 174         this.sprite(0, this.getReel().id === 'moveRight' ? 2 : 1);
173 175         /* We may need to enable controls here as we may have disabled them */
174 176         if(this.bounced){
175 177           this.velocity().x = 0;
176 178           this.bounced = false;
177 179         }
178 180         this.inDoubleJumpMode = false;
179 181       }
180 182       /* Will need to enable controls in some circumstances */
181 183       this.enableControl();
182 184     })
183 185     .bind('NewDirection', function (obj) {
184 186       /* 0 is neither right nor left so we don't care about it */
185 187       if (obj.x === 0) return;
186 188       this.currentDirection = obj.x === 1 ? RIGHT : LEFT;
187 189       if (this.currentDirection === RIGHT && !this.isJumping) {
188 190         if (this.isMoving) {
189 191           /* Start running again */
190 192           this.animate('moveRight', -1);
191 193         }else {
192 194           this.sprite(0, 2);
193 195         }
194 196       }
195 197       else if (this.currentDirection === LEFT && !this.isJumping) {
196 198         if (this.isMoving) {
197 199           /* Start running again */
198 200           this.animate('moveLeft', -1);
199 201         }else {
200 202           this.sprite(0, 1);
201 203         }
202 204       }
203 205     })
204 206     .bind('EnterFrame', function(){
205 207       if(this.x <= -6) this.x = -5;
206 208       if(this.x >= 3785) this.x = 3784;
207 209     })
208 210  
209 211     /* Set player defaults */
210 212     _player.isJumping = false;
211 213     _player.currentDirection = RIGHT;
212 214     _player.isMoving = false;
213 215     _player.reel('moveRight');
214 216     _player.bounced = false;
215 217     _player.inDoubleJumpMode = false;
  218 }
  219  
  220 function spawnWalkers () {
  221   Crafty.e('Delay').delay(spawnWalker, Crafty.math.randomInt(2000, 8000), -1);
  222 }
  223  
  224 function spawnWalker () {
  225   Crafty.e('Walker')
  226     .onHit('Player', function(hitData) {
  227       var playerObj = hitData[0].obj;
  228       if(playerObj.isJumping){
  229         if(this.velocity().x !== 0){
  230           pauseAndResetAnimation(this);
  231           this.animate('die', 1);
  232           this.velocity().x = 0;
  233           this.tween({alpha: 0}, 750);
  234           Crafty.trigger(EVENT_PLAYER_HIT_WALKER);
  235         }
  236       }
  237       else{
  238         /* We need to check this is a genuine collision */
  239         if(this.getReel().id === 'die') return;
  240         this.velocity().x = 0;
  241         this.x += 5;
  242         pauseAndResetAnimation(this);
  243         this.reelPosition(1);
  244         Crafty.trigger(EVENT_PLAYER_DIE);
  245       }
  246     });
216 247 }
217 248  
218 249 function generateMap () {
219 250   const Y_OFFSET = 600 - (tileMap.length * TILE_HEIGHT);
220 251   tileMap.map(function (tileRow, rowIdx) {
221 252     var xPos = 0;
222 253     var yPos = 0;
223 254     tileRow.map(function (tile, tileIdx) {
224 255       yPos = Y_OFFSET + (rowIdx * 60);
225 256       var tileType = tile[0];
226 257       var tileNum = tile[1];
227 258       if (tileType === 0){
228 259         xPos += (tileNum * 80);
229 260       }
230 261       if (tileType === 1) {
231 262         for(var i=0; i < tileNum; i++){
232 263           Crafty.e('FloorTile, 2D, DOM, Image, Collision')
233 264             .attr({ x: xPos, y: yPos, w: TILE_WIDTH, h: TILE_HEIGHT })
234 265             .image(Crafty.assets['img/tile-' + tileType + '.png'].src);
235 266           xPos += 80;
236 267         }
237 268       }
238 269       else{
239 270         if (tileType === 4) {
240 271           Crafty.e('Platform')
241 272             .setImage('img/platform.png')
242 273             .setPlatform(xPos, yPos, 1)
243 274             .addCoins(Crafty.math.randomInt(1,2));
244 275         }
245 276         else if (tileType === 8) {
246 277           Crafty.e('Platform')
247 278             .setImage('img/platformx2.png')
248 279             .setPlatform(xPos, yPos, 2)
249 280             .addCoins(Crafty.math.randomInt(1,2));
250 281         }
251 282         xPos += 80;
252 283       }
253 284     });
254 285   });
255 286 }
256 287  
257 288 function displayText () {
258 289   displayScore();
259 290   displayTimeLeft();
260 291 }
261 292  
262 293 function displayTimeLeft () {
263 294   if(_timeLeftDisplay){
264 295     _timeLeftDisplay.destroy();
265 296   }
266 297   _timeLeftDisplay = Crafty.e("2D, DOM, Text")
267 298     .attr({ x: 720 - Crafty.viewport._x, y: 20 })
268 299     .text(__STATE.timeLeft)
269 300     .textColor('#FF0000')
270 301     .textFont({ size: '14px', weight: 'bold', family: 'Courier New' });
271 302 }
272 303  
273 304 function displayScore () {
274 305   if(_scoreDisplay){
275 306     _scoreDisplay.destroy();
276 307   }
277 308   _scoreDisplay = Crafty.e("2D, DOM, Text")
278 309     .attr({ x: 750 - Crafty.viewport._x, y: 20 })
279 310     .text(pad(__STATE.currentScore, 3))
280 311     .textColor('#FF0000')
281 312     .textFont({ size: '14px', weight: 'bold', family: 'Courier New' });
282 313 }
283 314  
284 315 function displayGameOver(){
285 316   if(Crafty("GameOver"))
286 317     Crafty("GameOver").destroy();
287 318  
288 319   Crafty.e("GameOver, 2D, DOM, Text")
289 320     .attr({ x: 280 - Crafty.viewport._x, y: 280, z:100, w: 250 })
290 321     .text("GAME OVER").textColor('#FF0000').textFont({ size: '36px', weight: 'bold', family: 'Courier New' });
291 322 }
292 323  
293 324 function displayLevelComplete(){
294 325   if(Crafty("LevelComplete"))
295 326     Crafty("LevelComplete").destroy();
296 327  
297 328   Crafty.e("LevelComplete, 2D, DOM, Text")
298 329     .attr({ x: 270 - Crafty.viewport._x, y: 280, z:100, w: 350 })
299 330     .text("LEVEL COMPLETE").textColor('#33FF33').textFont({ size: '36px', weight: 'bold', family: 'Courier New' });
300 331 }
301 332  
302 333 function updateScore(amt){
303 334   __STATE.currentScore += amt;
304 335   displayScore();
305 336 }
306 337  
307 338 function pad(num, size) {
308 339     var s = num+"";
309 340     while (s.length < size) s = "0" + s;
310 341     return s;
311 342 }
312 343  
313 344 function setupGlobalBindings () {
314 345   Crafty.bind(EVENT_GAME_OVER, function(){
315 346     _player.disableControl();
316 347     pauseAndResetAnimation(_player);
317 348     displayGameOver();
318 349   })
319 350 }
320 351  
321 352 function pauseAndResetAnimation (ent){
322 353   ent.pauseAnimation();
323 354   ent.resetAnimation();
324 355 }
325 356  
326 357 function reinstateMovement () {
327 358   _player.enableControl();
328 359 }
329 360  
330 361 function reset () {
331 362   _player = null;
332 363   _viewportX = 0;
333 364   _scoreDisplay = "";
334 365   _gameStartTime = (new Date()).getTime();
335 366   _timeLeftDisplay = "";
336 367   _secondsTotal = 120;
337 368  
338 369   __STATE.gameStarted = false;
339 370   __STATE.gameOver = false;
340 371   __STATE.timeLeft = _secondsTotal;
341 372   __STATE.currentScore = 0;
342 373   __STATE.gameOverIsDisplaying = false;
343 374   __STATE.numCoinsToCollect = -1;
344 375  
345 376   /* Position viewport */
346 377   Crafty.viewport.scroll('_x', 0)
347 378 }
348 379  
349 380 Crafty.bind('EnterFrame', function(){
350 381   if(__STATE.gameStarted === false)
351 382     return;
352 383  
353 384   if(Crafty.frame() % 50 === 1){
354 385     __STATE.timeLeft = _secondsTotal - Math.round(((new Date()).getTime() - _gameStartTime) / 1000);
355 386     displayTimeLeft();
356 387   }
357 388   if(__STATE.gameOver && !__STATE.gameOverIsDisplaying){
358 389     /* Display Game Over */
359 390     Crafty.trigger(EVENT_GAME_OVER);
360 391     __STATE.gameOverIsDisplaying = true;
361 392   }
362 393 })