1 // --- 2 // Copyright (c) 2010 Francesco Cottone, http://www.kesiev.com/ 3 // --- 4 5 /** 6 * @namespace 7 * Gamecycle contains your basic game loop: intro, menus, 8 * crossfading between stages/lifes, gameover and ending. 9 */ 10 var gamecycle={ 11 12 /** 13 * Gamecycle constructor - initializes a new game object 14 * 15 * @param id unique id of object 16 * @param group name of group to store the object in 17 */ 18 createMaingame:function(id,group) { 19 return gbox.addObject({ 20 id:id, 21 group:group, 22 counter:0, 23 difficulty:0, 24 25 // state transition 26 state:50, 27 stateFirstIteration:true, 28 29 hud:{}, 30 31 /** 32 * This method is called whenever you load a new map. It's meant to be 33 * overridden when you create your game. 34 */ 35 changeLevel:function() { }, 36 37 /** 38 * This method is called every time a player is "reborn". This method is 39 * meant to be overridden since you have to do garbage collection. 40 */ 41 newLife:function() { }, 42 43 // game disclaimer animation (if needed) 44 gameDisclaimerAnimation:function(reset) { 45 return true; 46 }, 47 48 // game intro animation 49 gameIntroAnimation:function(reset) { 50 if (reset) { 51 gbox.stopChannel("bgmusic"); 52 toys.resetToy(this,"default-blinker"); 53 } else { 54 gbox.blitFade(gbox.getBufferContext(),{alpha:1}); 55 return toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"LETS BEGIN!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),blinkspeed:5,times:6}); 56 } 57 }, 58 59 // level intro animation 60 levelIntroAnimation:function(reset) { 61 if (reset) { 62 gbox.stopChannel("bgmusic"); 63 toys.resetToy(this,"default-blinker"); 64 } else { 65 gbox.blitFade(gbox.getBufferContext(),{alpha:1}); 66 return toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"GET READY!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),blinkspeed:5,times:6}); 67 } 68 }, 69 70 // Life intro animation 71 newlifeIntroAnimation:function(reset) { 72 if (reset) { 73 gbox.stopChannel("bgmusic"); 74 toys.resetToy(this,"default-blinker"); 75 } else { 76 gbox.blitFade(gbox.getBufferContext(),{alpha:1}); 77 return toys.text.fixed(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"GET READY!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),time:30}); 78 } 79 }, 80 81 // gameover animation 82 gameoverIntroAnimation:function(reset) { 83 if (reset) { 84 gbox.stopChannel("bgmusic"); 85 toys.resetToy(this,"default-blinker"); 86 } else { 87 gbox.blitFade(gbox.getBufferContext(),{alpha:1}); 88 return toys.text.fixed(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"GAME OVER",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),time:50}); 89 } 90 }, 91 92 // game title animation 93 gameTitleIntroAnimation:function(reset) { 94 if (reset) 95 gbox.stopChannel("bgmusic"); 96 else { 97 gbox.blitFade(gbox.getBufferContext(),{alpha:1}); 98 gbox.blitText(gbox.getBufferContext(),{font:"small",text:"GAME TITLE",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH()-100}); 99 } 100 }, 101 102 // End level animation 103 endlevelIntroAnimation:function(reset) { 104 if (reset) { 105 toys.resetToy(this,"default-blinker"); 106 } else { 107 return toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"WELL DONE!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),blinkspeed:5,times:10}); 108 } 109 }, 110 111 // Game ending 112 gameEndingIntroAnimation:function(reset) { 113 if (reset) { 114 toys.resetToy(this,"default-blinker"); 115 } else { 116 gbox.blitFade(gbox.getBufferContext(),{alpha:1}); 117 return toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"CONGRATULATIONS!",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:0,dw:gbox.getScreenW(),dh:gbox.getScreenH(),blinkspeed:5,times:10}); 118 } 119 }, 120 121 // PRESS START 122 pressStartIntroAnimation:function(reset) { 123 if (reset) { 124 toys.resetToy(this,"default-blinker"); 125 } else { 126 toys.text.blink(this,"default-blinker",gbox.getBufferContext(),{font:"small",text:"PRESS A TO START",valign:gbox.ALIGN_MIDDLE,halign:gbox.ALIGN_CENTER,dx:0,dy:Math.floor(gbox.getScreenH()/3),dw:gbox.getScreenW(),dh:Math.floor(gbox.getScreenH()/3)*2,blinkspeed:10}); 127 return gbox.keyIsHit("a"); 128 } 129 }, 130 131 /** 132 * This method is called when the player dies. 133 */ 134 gameIsOver:function() { return true; }, 135 136 /** 137 * Actions done during the game (i.e. stage is clear or other ending conditions) 138 */ 139 gameEvents:function() { 140 141 }, 142 143 gameMenu:function(reset) { 144 if (reset) { 145 toys.resetToy(this,"difficulty"); 146 } else { 147 gbox.blitFade(gbox.getBufferContext(),{alpha:0.5}); 148 if (toys.ui.menu(this,"difficulty",{audiooption:"default-menu-option",audioconfirm:"default-menu-confirm",font:"small",keys:{up:"up",down:"down",ok:"a",cancel:"b"},selector:">",items:["EASY","NORMAL","HARD"],x:10,y:10})) { 149 if (toys.getToyValue(this,"difficulty","ok") == -1) return -1; 150 else { 151 this.difficulty=toys.getToyValue(this,"difficulty","selected"); 152 return true; 153 } 154 } 155 return false; 156 } 157 }, 158 159 // CHECK 160 161 gameIsHold:function() { // Use this clause to check collision and kill player: if true the level is changing 162 return (this.state==400)||(this.state==401); 163 }, 164 165 isCompleted:function() { 166 return (this.state==800); 167 }, 168 169 // GAME CYCLE 170 171 getNextLevel:function() { 172 return this._nextlevel; 173 }, 174 175 gotoLevel:function(level) { 176 this._nextlevel=level; 177 this.setState(400); 178 }, 179 180 playerDied:function(data) { 181 this._loselife=data; 182 this.setState(500); 183 }, 184 185 gameIsCompleted:function() { 186 this.setState(800); 187 }, 188 189 // private methods 190 191 /** 192 * Changes the current game state 193 * 194 * @param st state number 195 */ 196 setState:function(st) { 197 this.state=st; 198 this.stateFirstIteration=true; 199 }, 200 201 /* 202 * Removes all objects in each group except the game 203 * cycle group. Used for garbage collection when resetting the game. 204 */ 205 _resetGroups:function() { 206 var g=gbox.getGroups(); 207 for (var i=0;i<g.length;i++) 208 if (g[i]!=this.group) gbox.clearGroup(g[i]); 209 gbox.soloGroup(this.group); 210 }, 211 212 stateIsReady:function() { this.stateFirstIteration=false; }, 213 214 blit:function() { 215 switch (this.state) { 216 217 // Disclaimer 218 case 50: { 219 if (this.stateFirstIteration) { 220 this._resetGroups(); 221 this.gameDisclaimerAnimation(true); 222 this.stateIsReady(); 223 } 224 if (this.gameDisclaimerAnimation(false)) 225 this.setState(100); 226 break; 227 } 228 // main menu 229 case 100: 230 case 101: 231 case 102: { // Press Start / Menu 232 if (this.stateFirstIteration && (this.state == 100)) { 233 this._resetGroups(); 234 this.gameTitleIntroAnimation(true); 235 } 236 this.gameTitleIntroAnimation(false); 237 switch (this.state) { 238 case 100: { // Press to start 239 if (this.stateFirstIteration) { 240 gbox.resetChannel("bgmusic"); 241 this.pressStartIntroAnimation(true); 242 this.stateIsReady(); 243 } 244 if (this.pressStartIntroAnimation(false)) this.setState(101); 245 break; 246 } 247 case 101: { // Game menu 248 if (this.stateFirstIteration) { 249 gbox.setChannelVolume("bgmusic",0.5); 250 this.gameMenu(true); 251 this.stateIsReady(); 252 } 253 254 var menu=this.gameMenu(false); 255 if (menu) 256 if (menu == -1) this.setState(100); else this.setState(102); 257 break; 258 } 259 case 102: { // Fader 260 if (this.stateFirstIteration) { 261 this._resetGroups(); 262 toys.resetToy(this,"fadeout"); 263 this.stateIsReady(); 264 } 265 if (toys.fullscreen.fadeout(this,"fadeout",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) 266 this.setState(200); 267 break; 268 } 269 break; 270 } 271 break; 272 } 273 case 200:// Game intro animation 274 275 case 300:// Start game 276 case 301:// Game is going 277 278 case 400:// Fade out to change level 279 case 401:// Level animation (levelIntroAnimation) 280 case 402:// Fade in to next level 281 282 case 500:// Wait after dead 283 case 501:// Dead fadeout 284 285 case 600:// Next life intro 286 case 601:// New life fadein 287 288 case 700:// Gameover animation 289 290 case 800:// Fade out game ending 291 case 801:// Game ending 292 293 { // Game playing 294 if (this.stateFirstIteration) { 295 switch (this.state) { 296 case 200: { // Game intro 297 toys.resetToy(this,"fadein"); 298 this.level=null; 299 this._nextlevel=null; 300 this.hud=toys.ui.hud("maingamehud"); 301 302 this.initializeGame(); 303 this.gameIntroAnimation(true); 304 305 break; 306 } 307 case 300: { 308 // Game start 309 this.level=this._nextlevel; 310 gbox.playAllGroups(); 311 this.changeLevel(this._nextlevel); 312 } 313 case 800: 314 case 400:{ 315 this.endlevelIntroAnimation(true); 316 toys.resetToy(this,"fadeout"); 317 break; 318 } 319 case 501: { 320 toys.resetToy(this,"fadeout"); 321 break; 322 } 323 case 401: { 324 gbox.soloGroup(this.group); 325 this.levelIntroAnimation(true); 326 break; 327 } 328 case 402: { 329 toys.resetToy(this,"fadein"); 330 this.level=this._nextlevel; 331 gbox.playAllGroups(); 332 this.changeLevel(this._nextlevel); 333 break; 334 } 335 case 600: { 336 gbox.soloGroup(this.group); 337 this.newlifeIntroAnimation(true); 338 break; 339 } 340 case 500: { 341 this._loselife.counter=0; 342 break; 343 } 344 case 601: { 345 toys.resetToy(this,"fadein"); 346 this.newLife(); 347 gbox.playAllGroups(); 348 break; 349 } 350 case 700: { 351 gbox.resetChannel("bgmusic"); 352 gbox.soloGroup(this.group); 353 this.gameoverIntroAnimation(true); 354 break; 355 } 356 case 801: { 357 gbox.resetChannel("bgmusic"); 358 gbox.soloGroup(this.group); 359 this.gameEndingIntroAnimation(true); 360 break; 361 } 362 } 363 this.stateIsReady(); 364 } 365 366 switch (this.state) { 367 case 200: { // Game intro 368 if (this.gameIntroAnimation(false)) this.setState(300); 369 break; 370 } 371 case 601: // Fade in with new life 372 case 402: // Fade in after level change 373 case 300: { // Fade in at the beginning of the game 374 if (toys.fullscreen.fadein(this,"fadein",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) this.setState(301); 375 break; 376 } 377 case 301: { // Ingame stuff 378 this.gameEvents(); 379 break; 380 } 381 case 400: { // Fade out before changing the level 382 if (this.endlevelIntroAnimation(false)) 383 if (toys.fullscreen.fadeout(this,"fadeout",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) this.setState(401); 384 break; 385 } 386 case 800: { // Fade out before game ending 387 if (this.endlevelIntroAnimation(false)) 388 if (toys.fullscreen.fadeout(this,"fadeout",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) this.setState(801); 389 break; 390 } 391 case 501: { // Fade out after dead 392 if (toys.fullscreen.fadeout(this,"fadeout",gbox.getBufferContext(),{fadespeed:0.05,audiochannelfade:"bgmusic"})) 393 if (this.gameIsOver()) 394 this.setState(700); // GAME OVER 395 else 396 this.setState(600); 397 break; 398 } 399 case 401:{ // Level intro animation 400 if (this.levelIntroAnimation(false)) this.setState(402); 401 break; 402 } 403 case 500: { // Wait after dead 404 this._loselife.counter++; 405 if (this._loselife.counter==this._loselife.wait) this.setState(501); 406 break; 407 } 408 case 600:{ // New life intro 409 if (this.newlifeIntroAnimation(false)) this.setState(601); 410 break; 411 } 412 case 700:{ // gameover 413 if (this.gameoverIntroAnimation(false)) this.setState(100); // Restart game 414 break; 415 } 416 case 801:{ // Game ending 417 if (this.gameEndingIntroAnimation(false)) { 418 this._loselife={ending:true}; 419 this.setState(700); // Game over 420 } 421 break; 422 } 423 } 424 this.hud.blit(); 425 break; 426 } 427 } 428 } 429 }); 430 } 431 } 432