<!doctype html><htmllang="en"><head><metacharset="UTF-8"><title>CH7EX9: Space Raiders With Optimized Dynamic Network Sound And State Loader</title>
<scriptsrc="modernizr.js"></script><scripttype="text/javascript">window.addEventListener('load',eventWindowLoaded,false);functioneventWindowLoaded(){canvasApp();}functionsupportedAudioFormat(audio){varreturnExtension="";if(audio.canPlayType("audio/ogg")=="probably"||audio.canPlayType("audio/ogg")=="maybe"){returnExtension="ogg";}elseif(audio.canPlayType("audio/wav")=="probably"||audio.canPlayType("audio/wav")=="maybe"){returnExtension="wav";}elseif(audio.canPlayType("audio/mp3")=="probably"||audio.canPlayType("audio/mp3")=="maybe"){returnExtension="mp3";}returnreturnExtension;}functioncanvasSupport(){returnModernizr.canvas;}functioncanvasApp(){varSTATE_INIT=10;varSTATE_LOADING=20;varSTATE_RESET=30;varSTATE_PLAYING=40;varappState=STATE_INIT;varloadCount=0;varitemsToLoad=0;varalienImage=newImage();varmissileImage=newImage();varplayerImage=newImage();varSOUND_EXPLODE="explode1";varSOUND_SHOOT="shoot1";varMAX_SOUNDS=6;varsoundPool=newArray();varexplodeSound;varexplodeSound2;varexplodeSound3;varshootSound;varshootSound2;varshootSound3;varaudioType;varmouseX;varmouseY;varplayer={x:250,y:475};varaliens=newArray();varmissiles=newArray();varALIEN_START_X=25;varALIEN_START_Y=25;varALIEN_ROWS=5;varALIEN_COLS=8;varALIEN_SPACING=40;if(!canvasSupport()){return;}vartheCanvas=document.getElementById("canvasOne");varcontext=theCanvas.getContext("2d");functionitemLoaded(event){loadCount++;if(loadCount>=itemsToLoad){shootSound.removeEventListener("canplaythrough",itemLoaded,false);shootSound2.removeEventListener("canplaythrough",itemLoaded,false);shootSound3.removeEventListener("canplaythrough",itemLoaded,false);explodeSound.removeEventListener("canplaythrough",itemLoaded,false);explodeSound2.removeEventListener("canplaythrough",itemLoaded,false);explodeSound3.removeEventListener("canplaythrough",itemLoaded,false);soundPool.push({name:"explode1",element:explodeSound,played:false});soundPool.push({name:"explode1",element:explodeSound2,played:false});soundPool.push({name:"explode1",element:explodeSound3,played:false});soundPool.push({name:"shoot1",element:shootSound,played:false});soundPool.push({name:"shoot1",element:shootSound2,played:false});soundPool.push({name:"shoot1",element:shootSound3,played:false});appState=STATE_RESET;}}functioninitApp(){loadCount=0;itemsToLoad=9;explodeSound=document.createElement("audio");document.body.appendChild(explodeSound);audioType=supportedAudioFormat(explodeSound);explodeSound.addEventListener("canplaythrough",itemLoaded,false);explodeSound.setAttribute("src","explode1."+audioType);explodeSound2=document.createElement("audio");document.body.appendChild(explodeSound2);explodeSound2.addEventListener("canplaythrough",itemLoaded,false);explodeSound2.setAttribute("src","explode1."+audioType);explodeSound3=document.createElement("audio");document.body.appendChild(explodeSound3);explodeSound3.addEventListener("canplaythrough",itemLoaded,false);explodeSound3.setAttribute("src","explode1."+audioType);shootSound=document.createElement("audio");document.body.appendChild(shootSound);shootSound.addEventListener("canplaythrough",itemLoaded,false);shootSound.setAttribute("src","shoot1."+audioType);shootSound2=document.createElement("audio");document.body.appendChild(shootSound2);shootSound2.addEventListener("canplaythrough",itemLoaded,false);shootSound2.setAttribute("src","shoot1."+audioType);shootSound3=document.createElement("audio");document.body.appendChild(shootSound3);shootSound3.addEventListener("canplaythrough",itemLoaded,false);shootSound3.setAttribute("src","shoot1."+audioType);alienImage=newImage();alienImage.onload=itemLoaded;alienImage.src="alien.png";playerImage=newImage();playerImage.onload=itemLoaded;playerImage.src="player.png";missileImage=newImage();missileImage.onload=itemLoaded;missileImage.src="missile.png";appState=STATE_LOADING;}functionstartLevel(){for(varr=0;r<ALIEN_ROWS;r++){for(varc=0;c<ALIEN_COLS;c++){aliens.push({speed:2,x:ALIEN_START_X+c*ALIEN_SPACING,y:ALIEN_START_Y+r*ALIEN_SPACING,width:alienImage.width,height:alienImage.height});}}}functionresetApp(){playSound(SOUND_EXPLODE,0);playSound(SOUND_SHOOT,0);startLevel();appState=STATE_PLAYING;}functiondrawScreen(){//Move missilesfor(vari=missiles.length−1;i>=0;i−−){missiles[i].y−=missiles[i].speed;if(missiles[i].y<(0-missiles[i].height)){missiles.splice(i,1);}}//Move Aliensfor(vari=aliens.length−1;i>=0;i−−){aliens[i].x+=aliens[i].speed;if(aliens[i].x>(theCanvas.width-aliens[i].width)||aliens[i].x<0){aliens[i].speed*=−1;aliens[i].y+=20;}if(aliens[i].y>theCanvas.height){aliens.splice(i,1);}}//Detect Collisionsmissile:for(vari=missiles.length−1;i>=0;i−−){vartempMissile=missiles[i]for(varj=aliens.length−1;j>=0;j−−){vartempAlien=aliens[j];if(hitTest(tempMissile,tempAlien)){playSound(SOUND_EXPLODE,.5);missiles.splice(i,1);aliens.splice(j,1);breakmissile;}}if(aliens.length<=0){appState=STATE_RESET;}}//Backgroundcontext.fillStyle="#000000";context.fillRect(0,0,theCanvas.width,theCanvas.height);//Boxcontext.strokeStyle="#EEEEEE";context.strokeRect(5,5,theCanvas.width−10,theCanvas.height−10);//Draw Playercontext.drawImage(playerImage,player.x,player.y);//Draw Missilesfor(vari=missiles.length−1;i>=0;i−−){context.drawImage(missileImage,missiles[i].x,missiles[i].y);}//draw aliensfor(vari=aliens.length−1;i>=0;i−−){context.drawImage(alienImage,aliens[i].x,aliens[i].y);}//Draw Textcontext.fillStyle="#FFFFFF";context.fillText("Active Sounds: "+soundPool.length,200,480);}functionhitTest(image1,image2){r1left=image1.x;r1top=image1.y;r1right=image1.x+image1.width;r1bottom=image1.y+image1.height;r2left=image2.x;r2top=image2.y;r2right=image2.x+image2.width;r2bottom=image2.y+image2.height;retval=false;if((r1left>r2right)||(r1right<r2left)||(r1bottom<r2top)||(r1top>r2bottom)){retval=false;}else{retval=true;}returnretval;}functioneventMouseMove(event){varx;vary;if(event.pageX||event.pageY){x=event.pageX;y=event.pageY;}else{x=e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft;y=e.clientY+document.body.scrollTop+document.documentElement.scrollTop;}x-=theCanvas.offsetLeft;y-=theCanvas.offsetTop;mouseX=x;mouseY=y;player.x=mouseX;player.y=mouseY;}functioneventMouseUp(event){missiles.push({speed:5,x:player.x+.5*playerImage.width,y:player.y-missileImage.height,width:missileImage.width,height:missileImage.height});playSound(SOUND_SHOOT,.5);}functionplaySound(sound,volume){varsoundFound=false;varsoundIndex=0;vartempSound;if(soundPool.length>0){while(!soundFound&&soundIndex<soundPool.length){vartSound=soundPool[soundIndex];if((tSound.element.ended||!tSound.played)&&tSound.name==sound){soundFound=true;tSound.played=true;}else{soundIndex++;}}}if(soundFound){tempSound=soundPool[soundIndex].element;tempSound.volume=volume;tempSound.play();}elseif(soundPool.length<MAX_SOUNDS){tempSound=document.createElement("audio");tempSound.setAttribute("src",sound+"."+audioType);tempSound.volume=volume;tempSound.play();soundPool.push({name:sound,element:tempSound,type:audioType,played:true});}}functionrun(){switch(appState){caseSTATE_INIT:initApp();break;caseSTATE_LOADING://wait for call backsbreak;caseSTATE_RESET:resetApp();break;caseSTATE_PLAYING:drawScreen();break;}}theCanvas.addEventListener("mouseup",eventMouseUp,false);theCanvas.addEventListener("mousemove",eventMouseMove,false);functiongameLoop(){window.setTimeout(gameLoop,20);run()}gameLoop();}</script>
</head><body><canvasid="canvasOne"width="500"height="500"style="position: absolute; top: 50px; left: 50px;">> Your browser does not support HTML5 Canvas.</canvas></body></html>
<!doctype html><htmllang="en"><head><metacharset="UTF-8"><title>CH9EX1: Geo Blaster Extended</title>
<scriptsrc="modernizr-1.6.min.js"></script><scripttype="text/javascript">window.addEventListener('load',eventWindowLoaded,false);functioneventWindowLoaded(){canvasApp();}functioncanvasSupport(){returnModernizr.canvas;}functionsupportedAudioFormat(audio){varreturnExtension="";if(audio.canPlayType("audio/ogg")=="probably"||audio.canPlayType("audio/ogg")=="maybe"){returnExtension="ogg";}elseif(audio.canPlayType("audio/wav")=="probably"||audio.canPlayType("audio/wav")=="maybe"){returnExtension="wav";}elseif(audio.canPlayType("audio/wav")=="probably"||audio.canPlayType("audio/wav")=="maybe"){returnExtension="mp3";}returnreturnExtension;}functioncanvasApp(){if(!canvasSupport()){return;}else{theCanvas=document.getElementById("canvas");context=theCanvas.getContext("2d");}//soundsvarSOUND_EXPLODE="explode1";varSOUND_SHOOT="shoot1";varSOUND_SAUCER_SHOOT="saucershoot"varMAX_SOUNDS=9;varsoundPool=newArray();varexplodeSound;varexplodeSound2;varexplodeSound3;varshootSound;varshootSound2;varshootSound3;varsaucershootSound;varsaucershootSound2;varsaucershootSound3;varaudioType;//application statesvarGAME_STATE_INIT=0;varGAME_STATE_WAIT_FOR_LOAD=5;varGAME_STATE_TITLE=10;varGAME_STATE_NEW_GAME=20;varGAME_STATE_NEW_LEVEL=30;varGAME_STATE_PLAYER_START=40;varGAME_STATE_PLAY_LEVEL=50;varGAME_STATE_PLAYER_DIE=60;varGAME_STATE_GAME_OVER=70;varcurrentGameState=0;varcurrentGameStateFunction=null;//title screenvartitleStarted=false;//game over screenvargameOverStarted=false;//objects for game play//game environmentvarscore=0;varlevel=0;varextraShipAtEach=10000;varextraShipsEarned=0;varplayerShips=3;//playfieldvarxMin=0;varxMax=400;varyMin=0;varyMax=400;//score valuesvarbigRockScore=50;varmedRockScore=75;varsmlRockScore=100;varsaucerScore=300;//rock scale constantsvarROCK_SCALE_LARGE=1;varROCK_SCALE_MEDIUM=2;varROCK_SCALE_SMALL=3;//create game objects and arraysvarplayer={};varrocks=[];varsaucers=[];varplayerMissiles=[];varparticles=[];varsaucerMissiles=[];varparticlePool=[];varmaxParticles=200;varnewParticle;vartempParticle;//level specificvarlevelRockMaxSpeedAdjust=1;varlevelSaucerMax=1;varlevelSaucerOccurrenceRate=25;varlevelSaucerSpeed=1;varlevelSaucerFireDelay=300;varlevelSaucerFireRate=30;varlevelSaucerMissileSpeed=1;//keyPressesvarkeyPressList=[];//tile sheetsvarshipTiles;varshipTiles2;varsaucerTiles;varlargeRockTiles;varmediumRockTiles;varsmallRockTiles;varparticleTiles;//loadingvarloadcCount=0;varitemsToLoad=0;functionitemLoaded(event){loadCount++;//console.log("loading:" + loadCount)if(loadCount>=itemsToLoad){shootSound.removeEventListener("canplaythrough",itemLoaded,false);shootSound2.removeEventListener("canplaythrough",itemLoaded,false);shootSound3.removeEventListener("canplaythrough",itemLoaded,false);explodeSound.removeEventListener("canplaythrough",itemLoaded,false);explodeSound2.removeEventListener("canplaythrough",itemLoaded,false);explodeSound3.removeEventListener("canplaythrough",itemLoaded,false);saucershootSound.removeEventListener("canplaythrough",itemLoaded,false);saucershootSound2.removeEventListener("canplaythrough",itemLoaded,false);saucershootSound3.removeEventListener("canplaythrough",itemLoaded,false);soundPool.push({name:"explode1",element:explodeSound,played:false});soundPool.push({name:"explode1",element:explodeSound2,played:false});soundPool.push({name:"explode1",element:explodeSound3,played:false});soundPool.push({name:"shoot1",element:shootSound,played:false});soundPool.push({name:"shoot1",element:shootSound2,played:false});soundPool.push({name:"shoot1",element:shootSound3,played:false});soundPool.push({name:"saucershoot",element:saucershootSound,played:false});soundPool.push({name:"saucershoot",element:saucershootSound2,played:false});soundPool.push({name:"saucershoot",element:saucershootSound3,played:false});switchGameState(GAME_STATE_TITLE)}}functionplaySound(sound,volume){ConsoleLog.log("play sound"+sound);varsoundFound=false;varsoundIndex=0;vartempSound;if(soundPool.length>0){while(!soundFound&&soundIndex<soundPool.length){vartSound=soundPool[soundIndex];if((tSound.element.ended||!tSound.played)&&tSound.name==sound){soundFound=true;tSound.played=true;}else{soundIndex++;}}}if(soundFound){ConsoleLog.log("sound found");tempSound=soundPool[soundIndex].element;//tempSound.setAttribute("src", sound + "." + audioType);//tempSound.loop = false;//tempSound.volume = volume;tempSound.play();}elseif(soundPool.length<MAX_SOUNDS){ConsoleLog.log("sound not found");tempSound=document.createElement("audio");tempSound.setAttribute("src",sound+"."+audioType);tempSound.volume=volume;tempSound.play();soundPool.push({name:sound,element:tempSound,type:audioType,played:true});}}functionrunGame(){currentGameStateFunction();}functionswitchGameState(newState){currentGameState=newState;switch(currentGameState){caseGAME_STATE_INIT:currentGameStateFunction=gameStateInit;break;caseGAME_STATE_WAIT_FOR_LOAD:currentGameStateFunction=gameStateWaitForLoad;break;caseGAME_STATE_TITLE:currentGameStateFunction=gameStateTitle;break;caseGAME_STATE_NEW_GAME:currentGameStateFunction=gameStateNewGame;break;caseGAME_STATE_NEW_LEVEL:currentGameStateFunction=gameStateNewLevel;break;caseGAME_STATE_PLAYER_START:currentGameStateFunction=gameStatePlayerStart;break;caseGAME_STATE_PLAY_LEVEL:currentGameStateFunction=gameStatePlayLevel;break;caseGAME_STATE_PLAYER_DIE:currentGameStateFunction=gameStatePlayerDie;break;caseGAME_STATE_GAME_OVER:currentGameStateFunction=gameStateGameOver;break;}}functiongameStateWaitForLoad(){//do nothing while loading events occurconsole.log("doing nothing...")}functioncreateObjectPools(){for(varctr=0;ctr<maxParticles;ctr++){varnewParticle={};particlePool.push(newParticle)}console.log("particlePool="+particlePool.length)}functiongameStateInit(){createObjectPools();loadCount=0;itemsToLoad=16;//change to 7 if experiencing problems in IEexplodeSound=document.createElement("audio");document.body.appendChild(explodeSound);audioType=supportedAudioFormat(explodeSound);explodeSound.setAttribute("src","explode1."+audioType);explodeSound.addEventListener("canplaythrough",itemLoaded,false);explodeSound2=document.createElement("audio");document.body.appendChild(explodeSound2);explodeSound2.setAttribute("src","explode1."+audioType);explodeSound2.addEventListener("canplaythrough",itemLoaded,false);explodeSound3=document.createElement("audio");document.body.appendChild(explodeSound3);explodeSound3.setAttribute("src","explode1."+audioType);explodeSound3.addEventListener("canplaythrough",itemLoaded,false);shootSound=document.createElement("audio");audioType=supportedAudioFormat(shootSound);document.body.appendChild(shootSound);shootSound.setAttribute("src","shoot1."+audioType);shootSound.addEventListener("canplaythrough",itemLoaded,false);shootSound2=document.createElement("audio");document.body.appendChild(shootSound2);shootSound2.setAttribute("src","shoot1."+audioType);shootSound2.addEventListener("canplaythrough",itemLoaded,false);shootSound3=document.createElement("audio");document.body.appendChild(shootSound3);shootSound3.setAttribute("src","shoot1."+audioType);shootSound3.addEventListener("canplaythrough",itemLoaded,false);saucershootSound=document.createElement("audio");audioType=supportedAudioFormat(saucershootSound);document.body.appendChild(saucershootSound);saucershootSound.setAttribute("src","saucershoot."+audioType);saucershootSound.addEventListener("canplaythrough",itemLoaded,false);saucershootSound2=document.createElement("audio");document.body.appendChild(saucershootSound2);saucershootSound2.setAttribute("src","saucershoot."+audioType);saucershootSound2.addEventListener("canplaythrough",itemLoaded,false);saucershootSound3=document.createElement("audio");document.body.appendChild(saucershootSound3);saucershootSound3.setAttribute("src","saucershoot."+audioType);saucershootSound3.addEventListener("canplaythrough",itemLoaded,false);shipTiles=newImage();shipTiles.src="ship_tiles.png";shipTiles.onload=itemLoaded;shipTiles2=newImage();shipTiles2.src="ship_tiles2.png";shipTiles2.onload=itemLoaded;saucerTiles=newImage();saucerTiles.src="saucer.png";saucerTiles.onload=itemLoaded;largeRockTiles=newImage();largeRockTiles.src="largerocks.png";largeRockTiles.onload=itemLoaded;mediumRockTiles=newImage();mediumRockTiles.src="mediumrocks.png";mediumRockTiles.onload=itemLoaded;smallRockTiles=newImage();smallRockTiles.src="smallrocks.png";smallRockTiles.onload=itemLoaded;particleTiles=newImage();particleTiles.src="parts.png";particleTiles.onload=itemLoaded;switchGameState(GAME_STATE_WAIT_FOR_LOAD);}functiongameStateTitle(){if(titleStarted!=true){fillBackground();setTextStyleTitle();context.fillText("Geo Blaster X-ten-d",120,70);setTextStyle();context.fillText("Press Space To Play",130,140);setTextStyleCredits();context.fillText("An HTML5 Example Game",125,200);context.fillText("From our upcoming HTML5 Canvas",100,215);context.fillText("book on O'Reilly Press",130,230);context.fillText("Game Code - Jeff Fulton",130,260);context.fillText("Sound Manager - Steve Fulton",120,275);titleStarted=true;}else{//wait for space key clickif(keyPressList[32]==true){ConsoleLog.log("space pressed");switchGameState(GAME_STATE_NEW_GAME);titleStarted=false;}}}functiongameStateNewGame(){ConsoleLog.log("gameStateNewGame")//set up new gamelevel=0;score=0;playerShips=3;player.maxVelocity=5;player.width=32;player.height=32;player.halfWidth=16;player.halfHeight=16;player.hitWidth=24;player.hitHeight=24;player.rotationalVelocity=10;//how many degrees to turn the shipplayer.thrustAcceleration=.05;player.missileFrameDelay=5;player.thrust=false;player.alpha=1;player.rotation=0;player.x=0;player.y=0;fillBackground();renderScoreBoard();switchGameState(GAME_STATE_NEW_LEVEL)}functiongameStateNewLevel(){rocks=[];saucers=[];playerMissiles=[];particles=[];saucerMissiles=[];level++;levelRockMaxSpeedAdjust=level*.25;if(levelRockMaxSpeedAdjust>3){levelRockMaxSpeed=3;}levelSaucerMax=1+Math.floor(level/10);if(levelSaucerMax>5){levelSaucerMax=5;}levelSaucerOccurrenceRate=10+3*level;if(levelSaucerOccurrenceRate>35){levelSaucerOccurrenceRate=35;}levelSaucerSpeed=1+.5*level;if(levelSaucerSpeed>5){levelSaucerSpeed=5;}levelSaucerFireDelay=120-10*level;if(levelSaucerFireDelay<20){levelSaucerFireDelay=20;}levelSaucerFireRate=20+3*level;if(levelSaucerFireRate<50){levelSaucerFireRate=50;}levelSaucerMissileSpeed=1+.2*level;if(levelSaucerMissileSpeed>4){levelSaucerMissileSpeed=4;}//create level rocksfor(varnewRockctr=0;newRockctr<level+3;newRockctr++){varnewRock={};newRock.scale=1;//scale//1 = large//2 = medium//3 = small//these will be used as the divisor for the new size//50/1 = 50//50/2 = 25//50/3 = 16newRock.width=64;newRock.height=64;newRock.halfWidth=32;newRock.halfHeight=32;newRock.hitWidth=48;newRock.hitHeight=48;//start all new rocks in upper left for ship safetynewRock.x=Math.floor(Math.random()*50);//ConsoleLog.log("newRock.x=" + newRock.x);newRock.y=Math.floor(Math.random()*50);//ConsoleLog.log("newRock.y=" + newRock.y);newRock.dx=(Math.random()*2)+levelRockMaxSpeedAdjust;if(Math.random()<.5){newRock.dx*=−1;}newRock.dy=(Math.random()*2)+levelRockMaxSpeedAdjust;if(Math.random()<.5){newRock.dy*=−1;}//rotation speed and directionif(Math.random()<.5){newRock.rotationInc=−1;}else{newRock.rotationInc=1;}newRock.animationDelay=Math.floor(Math.random()*3+1);newRock.animationCount=0;newRock.scoreValue=bigRockScore;newRock.rotation=0;rocks.push(newRock);//ConsoleLog.log("rock created rotationInc=" + newRock.rotationInc);}resetPlayer();switchGameState(GAME_STATE_PLAYER_START);}functiongameStatePlayerStart(){fillBackground();renderScoreBoard();if(player.alpha<1){player.alpha+=.01;ConsoleLog.log("player.alpha="+context.globalAlpha)}else{switchGameState(GAME_STATE_PLAY_LEVEL);player.safe=false;// added chapter 9}//renderPlayerShip(player.x, player.y,270,1);context.globalAlpha=1;//new in chapter 9checkKeys();update();render();//added chapter 9checkCollisions();checkForExtraShip();checkForEndOfLevel();frameRateCounter.countFrames();}functiongameStatePlayLevel(){checkKeys();update();render();checkCollisions();checkForExtraShip();checkForEndOfLevel();frameRateCounter.countFrames();}functionresetPlayer(){player.rotation=270;player.x=.5*xMax;player.y=.5*yMax;player.facingX=0;player.facingY=0;player.movingX=0;player.movingY=0;player.alpha=0;player.missileFrameCount=0;//added chapter 9player.safe=true;}functioncheckForExtraShip(){if(Math.floor(score/extraShipAtEach)>extraShipsEarned){playerShips++extraShipsEarned++;}}functioncheckForEndOfLevel(){if(rocks.length==0){switchGameState(GAME_STATE_NEW_LEVEL);}}functiongameStatePlayerDie(){if(particles.length>0||playerMissiles.length>0){fillBackground();renderScoreBoard();updateRocks();updateSaucers();updateParticles();updateSaucerMissiles();updatePlayerMissiles();renderRocks();renderSaucers();renderParticles();renderSaucerMissiles();renderPlayerMissiles();frameRateCounter.countFrames();}else{playerShips--;if(playerShips<1){switchGameState(GAME_STATE_GAME_OVER);}else{//resetPlayer();switchGameState(GAME_STATE_PLAYER_START);}}}functiongameStateGameOver(){//ConsoleLog.log("Game Over State");if(gameOverStarted!=true){fillBackground();renderScoreBoard();setTextStyle();context.fillText("Game Over!",160,70);context.fillText("Press Space To Play",130,140);gameOverStarted=true;}else{//wait for space key clickif(keyPressList[32]==true){ConsoleLog.log("space pressed");switchGameState(GAME_STATE_TITLE);gameOverStarted=false;}}}functionfillBackground(){// draw background and textcontext.fillStyle='#000000';context.fillRect(xMin,yMin,xMax,yMax);}functionsetTextStyle(){context.fillStyle='#ffffff';context.font='15px _sans';context.textBaseline='top';}functionsetTextStyleTitle(){context.fillStyle='#54ebeb';context.font='20px _sans';context.textBaseline='top';}functionsetTextStyleCredits(){context.fillStyle='#ffffff';context.font='12px _sans';context.textBaseline='top';}functionrenderScoreBoard(){context.fillStyle="#ffffff";context.fillText('Score '+score,10,20);renderPlayerShip(200,16,270,.75)context.fillText('X '+playerShips,220,20);context.fillText('FPS: '+frameRateCounter.lastFrameCount,300,20)}functioncheckKeys(){//check keysif(keyPressList[38]==true){//thrustvarangleInRadians=player.rotation*Math.PI/180;player.facingX=Math.cos(angleInRadians);player.facingY=Math.sin(angleInRadians);varmovingXNew=player.movingX+player.thrustAcceleration*player.facingX;varmovingYNew=player.movingY+player.thrustAcceleration*player.facingY;varcurrentVelocity=Math.sqrt((movingXNew*movingXNew)+(movingXNew*movingXNew));if(currentVelocity<player.maxVelocity){player.movingX=movingXNew;player.movingY=movingYNew;}player.thrust=true;}else{player.thrust=false;}if(keyPressList[37]==true){//rotate counterclockwiseplayer.rotation-=player.rotationalVelocity;if(player.rotation<0){player.rotation=350}}if(keyPressList[39]==true){//rotate clockwiseplayer.rotation+=player.rotationalVelocity;if(player.rotation>350){player.rotation=10}}if(keyPressList[32]==true){if(player.missileFrameCount>player.missileFrameDelay){playSound(SOUND_SHOOT,.5);firePlayerMissile();player.missileFrameCount=0;}}}functionupdate(){updatePlayer();updatePlayerMissiles();updateRocks();updateSaucers();updateSaucerMissiles();updateParticles();}functionrender(){fillBackground();renderScoreBoard();renderPlayerShip(player.x,player.y,player.rotation,1);renderPlayerMissiles();renderRocks();renderSaucers();renderSaucerMissiles();renderParticles();}functionupdatePlayer(){player.missileFrameCount++;player.x+=player.movingX*frameRateCounter.step;player.y+=player.movingY*frameRateCounter.step;if(player.x>xMax){player.x=-player.width;}elseif(player.x<-player.width){player.x=xMax;}if(player.y>yMax){player.y=-player.height;}elseif(player.y<-player.height){player.y=yMax;}}functionupdatePlayerMissiles(){vartempPlayerMissile={};varplayerMissileLength=playerMissiles.length-1;//ConsoleLog.log("update playerMissileLength=" + playerMissileLength);for(varplayerMissileCtr=playerMissileLength;playerMissileCtr>=0;playerMissileCtr--){//ConsoleLog.log("update player missile" + playerMissileCtr)tempPlayerMissile=playerMissiles[playerMissileCtr];tempPlayerMissile.x+=tempPlayerMissile.dx*frameRateCounter.step;tempPlayerMissile.y+=tempPlayerMissile.dy*frameRateCounter.step;if(tempPlayerMissile.x>xMax){tempPlayerMissile.x=-tempPlayerMissile.width;}elseif(tempPlayerMissile.x<-tempPlayerMissile.width){tempPlayerMissile.x=xMax;}if(tempPlayerMissile.y>yMax){tempPlayerMissile.y=-tempPlayerMissile.height;}elseif(tempPlayerMissile.y<-tempPlayerMissile.height){tempPlayerMissile.y=yMax;}tempPlayerMissile.lifeCtr++;if(tempPlayerMissile.lifeCtr>tempPlayerMissile.life){//ConsoleLog.log("removing player missile");playerMissiles.splice(playerMissileCtr,1)tempPlayerMissile=null;}}}functionupdateRocks(){vartempRock={};varrocksLength=rocks.length-1;//ConsoleLog.log("update rocks length=" + rocksLength);for(varrockCtr=rocksLength;rockCtr>=0;rockCtr--){tempRock=rocks[rockCtr];tempRock.x+=tempRock.dx*frameRateCounter.step;tempRock.y+=tempRock.dy*frameRateCounter.step;tempRock.animationCount++;if(tempRock.animationCount>tempRock.animationDelay){tempRock.animationCount=0;tempRock.rotation+=tempRock.rotationInc;if(tempRock.rotation>4){tempRock.rotation=0;}elseif(tempRock.rotation<0){tempRock.rotation=4;}}if(tempRock.x>xMax){tempRock.x=xMin-tempRock.width;}elseif(tempRock.x<xMin-tempRock.width){tempRock.x=xMax;}if(tempRock.y>yMax){tempRock.y=yMin-tempRock.width;}elseif(tempRock.y<yMin-tempRock.width){tempRock.y=yMax;}}}functionupdateSaucers(){//first check to see if we want to add a saucerif(saucers.length<levelSaucerMax){if(Math.floor(Math.random()*100)<=levelSaucerOccurrenceRate){//ConsoleLog.log("create saucer")varnewSaucer={};newSaucer.width=30;newSaucer.height=13;newSaucer.halfHeight=6.5;newSaucer.halfWidth=15;newSaucer.hitWidth=30;newSaucer.hitHeight=13;newSaucer.scoreValue=saucerScore;newSaucer.fireRate=levelSaucerFireRate;newSaucer.fireDelay=levelSaucerFireDelay;newSaucer.fireDelayCount=0;newSaucer.missileSpeed=levelSaucerMissileSpeed;newSaucer.dy=(Math.random()*2);if(Math.floor(Math.random)*2==1){newSaucer.dy*=−1;}//choose betweeen left or right edge to startif(Math.floor(Math.random()*2)==1){//start on right and go leftnewSaucer.x=450;newSaucer.dx=−1*levelSaucerSpeed;}else{//left to rightnewSaucer.x=−50;newSaucer.dx=levelSaucerSpeed;}newSaucer.missileSpeed=levelSaucerMissileSpeed;newSaucer.fireDelay=levelSaucerFireDelay;newSaucer.fireRate=levelSaucerFireRate;newSaucer.y=Math.floor(Math.random()*400);saucers.push(newSaucer);}}vartempSaucer={};varsaucerLength=saucers.length-1;//ConsoleLog.log("update rocks length=" + rocksLength);for(varsaucerCtr=saucerLength;saucerCtr>=0;saucerCtr--){tempSaucer=saucers[saucerCtr];//should saucer firetempSaucer.fireDelayCount++;if(Math.floor(Math.random()*100)<=tempSaucer.fireRate&&tempSaucer.fireDelayCount>tempSaucer.fireDelay){playSound(SOUND_SAUCER_SHOOT,.5);fireSaucerMissile(tempSaucer);tempSaucer.fireDelayCount=0;}varremove=false;tempSaucer.x+=tempSaucer.dx*frameRateCounter.step;tempSaucer.y+=tempSaucer.dy*frameRateCounter.step;//remove saucers on left and right edgesif(tempSaucer.dx>0&&tempSaucer.x>xMax){remove=true;}elseif(tempSaucer.dx<0&&tempSaucer.x<xMin-tempSaucer.width){remove=true;}//bounce saucers off over vertical edgesif(tempSaucer.y>yMax||tempSaucer.y<yMin-tempSaucer.width){tempSaucer.dy*=−1;}if(remove==true){//remove the saucersaucers.splice(saucerCtr,1);tempSaucer=null;}}}functionupdateSaucerMissiles(){vartempSaucerMissile={};varsaucerMissileLength=saucerMissiles.length-1;for(varsaucerMissileCtr=saucerMissileLength;saucerMissileCtr>=0;saucerMissileCtr--){//ConsoleLog.log("update player missile" + playerMissileCtr)tempSaucerMissile=saucerMissiles[saucerMissileCtr];tempSaucerMissile.x+=tempSaucerMissile.dx*frameRateCounter.step;tempSaucerMissile.y+=tempSaucerMissile.dy*frameRateCounter.step;if(tempSaucerMissile.x>xMax){tempSaucerMissile.x=-tempSaucerMissile.width;}elseif(tempSaucerMissile.x<-tempSaucerMissile.width){tempSaucerMissile.x=xMax;}if(tempSaucerMissile.y>yMax){tempSaucerMissile.y=-tempSaucerMissile.height;}elseif(tempSaucerMissile.y<-tempSaucerMissile.height){tempSaucerMissile.y=yMax;}tempSaucerMissile.lifeCtr++;if(tempSaucerMissile.lifeCtr>tempSaucerMissile.life){//removesaucerMissiles.splice(saucerMissileCtr,1);tempSaucerMissile=null;}}}functionupdateParticles(){varparticleLength=particles.length-1;for(varparticleCtr=particleLength;particleCtr>=0;particleCtr--){varremove=false;tempParticle=particles[particleCtr];tempParticle.x+=tempParticle.dx*frameRateCounter.step;tempParticle.y+=tempParticle.dy*frameRateCounter.step;tempParticle.lifeCtr++;if(tempParticle.lifeCtr>tempParticle.life){remove=true;}elseif((tempParticle.x>xMax)||(tempParticle.x<xMin)||(tempParticle.y>yMax)||(tempParticle.y<yMin)){remove=true;}if(remove){particlePool.push(tempParticle)particles.splice(particleCtr,1)}}}functionrenderPlayerShip(x,y,rotation,scale){//transformationcontext.save();//save current state in stackcontext.globalAlpha=parseFloat(player.alpha);varangleInRadians=rotation*Math.PI/180;varsourceX=Math.floor((player.rotation/10)%10)*32;varsourceY=Math.floor((player.rotation/10)/10)*32;if(player.thrust){context.drawImage(shipTiles2,sourceX,sourceY,32,32,player.x,player.y,32,32);}else{context.drawImage(shipTiles,sourceX,sourceY,32,32,player.x,player.y,32,32);}//restore contextcontext.restore();//pop old state on to screencontext.globalAlpha=1;}functionrenderPlayerMissiles(){vartempPlayerMissile={};varplayerMissileLength=playerMissiles.length-1;//ConsoleLog.log("render playerMissileLength=" + playerMissileLength);for(varplayerMissileCtr=playerMissileLength;playerMissileCtr>=0;playerMissileCtr--){//ConsoleLog.log("draw player missile " + playerMissileCtr)tempPlayerMissile=playerMissiles[playerMissileCtr];context.save();//save current state in stackvarsourceX=Math.floor(1%4)*tempPlayerMissile.width;varsourceY=Math.floor(1/4)*tempPlayerMissile.height;context.drawImage(particleTiles,sourceX,sourceY,tempPlayerMissile.width,tempPlayerMissile.height,tempPlayerMissile.x,tempPlayerMissile.y,tempPlayerMissile.width,tempPlayerMissile.height);context.restore();//pop old state on to screen}}functionrenderRocks(){vartempRock={};varrocksLength=rocks.length-1;for(varrockCtr=rocksLength;rockCtr>=0;rockCtr--){context.save();//save current state in stacktempRock=rocks[rockCtr];varsourceX=Math.floor((tempRock.rotation)%5)*tempRock.width;varsourceY=Math.floor((tempRock.rotation)/5)*tempRock.height;switch(tempRock.scale){case1:context.drawImage(largeRockTiles,sourceX,sourceY,tempRock.width,tempRock.height,tempRock.x,tempRock.y,tempRock.width,tempRock.height);break;case2:context.drawImage(mediumRockTiles,sourceX,sourceY,tempRock.width,tempRock.height,tempRock.x,tempRock.y,tempRock.width,tempRock.height);break;case3:context.drawImage(smallRockTiles,sourceX,sourceY,tempRock.width,tempRock.height,tempRock.x,tempRock.y,tempRock.width,tempRock.height);break;}context.restore();//pop old state on to screen}}functionrenderSaucers(){vartempSaucer={};varsaucerLength=saucers.length-1;for(varsaucerCtr=saucerLength;saucerCtr>=0;saucerCtr--){//ConsoleLog.log("saucer: " + saucerCtr);tempSaucer=saucers[saucerCtr];context.save();//save current state in stackvarsourceX=0;varsourceY=0;context.drawImage(saucerTiles,sourceX,sourceY,30,15,tempSaucer.x,tempSaucer.y,30,15);context.restore();//pop old state on to screen}}functionrenderSaucerMissiles(){vartempSaucerMissile={};varsaucerMissileLength=saucerMissiles.length-1;//ConsoleLog.log("saucerMissiles= " + saucerMissiles.length)for(varsaucerMissileCtr=saucerMissileLength;saucerMissileCtr>=0;saucerMissileCtr--){//ConsoleLog.log("draw player missile " + playerMissileCtr)tempSaucerMissile=saucerMissiles[saucerMissileCtr];context.save();//save current state in stackvarsourceX=Math.floor(0%4)*tempSaucerMissile.width;varsourceY=Math.floor(0/4)*tempSaucerMissile.height;context.drawImage(particleTiles,sourceX,sourceY,tempSaucerMissile.width,tempSaucerMissile.height,tempSaucerMissile.x,tempSaucerMissile.y,tempSaucerMissile.width,tempSaucerMissile.height);context.restore();//pop old state on to screen}}functionrenderParticles(){vartempParticle={};varparticleLength=particles.length-1;for(varparticleCtr=particleLength;particleCtr>=0;particleCtr--){tempParticle=particles[particleCtr];context.save();//save current state in stackvartile;//console.log("part type=" + tempParticle.type)switch(tempParticle.type){case0:// saucertile=0;break;case1://large rocktile=2break;case2://medium rocktile=3;break;case3://small rocktile=0;break;case4://playertile=1;break;}varsourceX=Math.floor(tile%4)*tempParticle.width;varsourceY=Math.floor(tile/4)*tempParticle.height;context.drawImage(particleTiles,sourceX,sourceY,tempParticle.width,tempParticle.height,tempParticle.x,tempParticle.y,tempParticle.width,tempParticle.height);context.restore();//pop old state on to screen}}functioncheckCollisions(){//loop through rocks then missiles.//There will always be rocks and a ship,//but there will not always be missiles.vartempRock={};varrocksLength=rocks.length-1;vartempPlayerMissile={};varplayerMissileLength=playerMissiles.length-1;varsaucerLength=saucers.length-1;vartempSaucer={};varsaucerMissileLength=saucerMissiles.length-1;rocks:for(varrockCtr=rocksLength;rockCtr>=0;rockCtr--){tempRock=rocks[rockCtr];missiles:for(varplayerMissileCtr=playerMissileLength;playerMissileCtr>=0;playerMissileCtr--){tempPlayerMissile=playerMissiles[playerMissileCtr];if(boundingBoxCollide(tempRock,tempPlayerMissile)){//ConsoleLog.log("hit rock");createExplode(tempRock.x+tempRock.halfWidth,tempRock.y+tempRock.halfHeight,10,tempRock.scale);if(tempRock.scale<3){splitRock(tempRock.scale+1,tempRock.x,tempRock.y);}addToScore(tempRock.scoreValue);playerMissiles.splice(playerMissileCtr,1);tempPlayerMissile=null;rocks.splice(rockCtr,1);tempRock=null;breakrocks;breakmissiles;}}saucers:for(varsaucerCtr=saucerLength;saucerCtr>=0;saucerCtr--){tempSaucer=saucers[saucerCtr];if(boundingBoxCollide(tempRock,tempSaucer)){//ConsoleLog.log("hit rock");createExplode(tempSaucer.x+tempSaucer.halfWidth,tempSaucer.y+tempSaucer.halfHeight,10,0);createExplode(tempRock.x+tempRock.halfWidth,tempRock.y+tempRock.halfHeight,10,tempRock.scale);if(tempRock.scale<3){splitRock(tempRock.scale+1,tempRock.x,tempRock.y);}saucers.splice(saucerCtr,1);tempSaucer=null;rocks.splice(rockCtr,1);tempRock=null;breakrocks;breaksaucers;}}//saucer missiles against rocks//this is done here so we don't have to loop through//rocks again as it would probably//be the biggest arraysaucerMissiles:for(varsaucerMissileCtr=saucerMissileLength;saucerMissileCtr>=0;saucerMissileCtr--){tempSaucerMissile=saucerMissiles[saucerMissileCtr];if(boundingBoxCollide(tempRock,tempSaucerMissile)){//ConsoleLog.log("hit rock");createExplode(tempRock.x+tempRock.halfWidth,tempRock.y+tempRock.halfHeight,10,tempRock.scale);if(tempRock.scale<3){splitRock(tempRock.scale+1,tempRock.x,tempRock.y);}saucerMissiles.splice(saucerCtr,1);tempSaucerMissile=null;rocks.splice(rockCtr,1);tempRock=null;breakrocks;breaksaucerMissiles;}}//check player against rocksif(boundingBoxCollide(tempRock,player)&&player.safe==false){//ConsoleLog.log("hit player");createExplode(tempRock.x+tempRock.halfWidth,tempRock.halfHeight,10,tempRock.scale);addToScore(tempRock.scoreValue);if(tempRock.scale<3){splitRock(tempRock.scale+1,tempRock.x,tempRock.y);}rocks.splice(rockCtr,1);tempRock=null;playerDie();}}//now check player against saucers and then saucers against player missiles//and finally player against saucer missilesplayerMissileLength=playerMissiles.length-1;saucerLength=saucers.length-1;saucers:for(varsaucerCtr=saucerLength;saucerCtr>=0;saucerCtr--){tempSaucer=saucers[saucerCtr];missiles:for(varplayerMissileCtr=playerMissileLength;playerMissileCtr>=0;playerMissileCtr--){tempPlayerMissile=playerMissiles[playerMissileCtr];if(boundingBoxCollide(tempSaucer,tempPlayerMissile)){//ConsoleLog.log("hit rock");createExplode(tempSaucer.x+tempSaucer.halfWidth,tempSaucer.y+tempSaucer.halfHeight,10,0);addToScore(tempSaucer.scoreValue);playerMissiles.splice(playerMissileCtr,1);tempPlayerMissile=null;saucers.splice(saucerCtr,1);tempSaucer=null;breaksaucers;breakmissiles;}}//player against saucersif(boundingBoxCollide(tempSaucer,player)&player.safe==false){ConsoleLog.log("hit player");createExplode(tempSaucer.x+16,tempSaucer.y+16,10,tempRock.scale);addToScore(tempSaucer.scoreValue);saucers.splice(rockCtr,1);tempSaucer=null;playerDie();}}//saucerMissiles against playersaucerMissileLength=saucerMissiles.length-1;saucerMissiles:for(varsaucerMissileCtr=saucerMissileLength;saucerMissileCtr>=0;saucerMissileCtr--){tempSaucerMissile=saucerMissiles[saucerMissileCtr];if(boundingBoxCollide(player,tempSaucerMissile)&player.safe==false){ConsoleLog.log("saucer missile hit player");playerDie();saucerMissiles.splice(saucerCtr,1);tempSaucerMissile=null;breaksaucerMissiles;}}}functionfirePlayerMissile(){//ConsoleLog.log("fire playerMissile");varnewPlayerMissile={};newPlayerMissile.dx=5*Math.cos(Math.PI*(player.rotation)/180);newPlayerMissile.dy=5*Math.sin(Math.PI*(player.rotation)/180);newPlayerMissile.x=player.x+player.halfWidth;newPlayerMissile.y=player.y+player.halfHeight;newPlayerMissile.life=60;newPlayerMissile.lifeCtr=0;newPlayerMissile.width=2;newPlayerMissile.height=2;newPlayerMissile.hitHeight=2;newPlayerMissile.hitWidth=2;playerMissiles.push(newPlayerMissile);}functionfireSaucerMissile(saucer){varnewSaucerMissile={};newSaucerMissile.x=saucer.x+.5*saucer.width;newSaucerMissile.y=saucer.y+.5*saucer.height;newSaucerMissile.width=2;newSaucerMissile.height=2;newSaucerMissile.hitHeight=2;newSaucerMissile.hitWidth=2;newSaucerMissile.speed=saucer.missileSpeed;//ConsoleLog.log("saucer fire");//fire at player from small saucervardiffx=player.x-saucer.x;vardiffy=player.y-saucer.y;varradians=Math.atan2(diffy,diffx);vardegrees=360*radians/(2*Math.PI);newSaucerMissile.dx=saucer.missileSpeed*Math.cos(Math.PI*(degrees)/180);newSaucerMissile.dy=saucer.missileSpeed*Math.sin(Math.PI*(degrees)/180);newSaucerMissile.life=160;newSaucerMissile.lifeCtr=0;saucerMissiles.push(newSaucerMissile);}functionplayerDie(){ConsoleLog.log("player die");createExplode(player.x+player.halfWidth,player.y+player.halfWidth,50,4);resetPlayer();switchGameState(GAME_STATE_PLAYER_DIE);}functioncreateExplode(x,y,num,type){playSound(SOUND_EXPLODE,.5);for(varpartCtr=0;partCtr<num;partCtr++){if(particlePool.length>0){newParticle=particlePool.pop();newParticle.dx=Math.random()*3;if(Math.random()<.5){newParticle.dx*=−1;}newParticle.dy=Math.random()*3;if(Math.random()<.5){newParticle.dy*=−1;}newParticle.life=Math.floor(Math.random()*30+30);newParticle.lifeCtr=0;newParticle.x=x;newParticle.width=2;newParticle.height=2;newParticle.y=y;newParticle.type=type;//ConsoleLog.log("newParticle.life=" + newParticle.life);particles.push(newParticle);}}}functionboundingBoxCollide(object1,object2){varleft1=object1.x;varleft2=object2.x;varright1=object1.x+object1.hitWidth;varright2=object2.x+object2.hitWidth;vartop1=object1.y;vartop2=object2.y;varbottom1=object1.y+object1.hitHeight;varbottom2=object2.y+object2.hitHeight;if(bottom1<top2)return(false);if(top1>bottom2)return(false);if(right1<left2)return(false);if(left1>right2)return(false);return(true);};functionsplitRock(scale,x,y){for(varnewRockctr=0;newRockctr<2;newRockctr++){varnewRock={};//ConsoleLog.log("split rock");if(scale==2){newRock.scoreValue=medRockScore;newRock.width=32;newRock.height=32;newRock.halfWidth=16;newRock.halfHeight=16;newRock.hitWidth=24;newRock.hitHeight=24;}else{newRock.scoreValue=smlRockScore;newRock.width=24;newRock.height=24;newRock.halfWidth=12;newRock.halfHeight=12;newRock.hitWidth=16;newRock.hitHeight=16;}newRock.scale=scale;newRock.x=x;newRock.y=y;newRock.dx=Math.random()*3;if(Math.random()<.5){newRock.dx*=−1;}newRock.dy=Math.random()*3;if(Math.random()<.5){newRock.dy*=−1;}if(Math.random()<.5){newRock.rotationInc=−1;}else{newRock.rotationInc=1;}newRock.animationDelay=Math.floor(Math.random()*3+1);newRock.animationCount=0;newRock.rotation=0;ConsoleLog.log("new rock scale"+(newRock.scale));rocks.push(newRock);}}functionaddToScore(value){score+=value;}document.onkeydown=function(e){e=e?e:window.event;//ConsoleLog.log(e.keyCode + "down");keyPressList[e.keyCode]=true;}document.onkeyup=function(e){//document.body.onkeyup = function(e){e=e?e:window.event;//ConsoleLog.log(e.keyCode + "up");keyPressList[e.keyCode]=false;};//*** application startswitchGameState(GAME_STATE_INIT);varFRAME_RATE=40;frameRateCounter=newFrameRateCounter(FRAME_RATE);//**** application loopvarintervalTime=1000/FRAME_RATE;setInterval(runGame,intervalTime);}//***** object prototypes *****//*** consoleLog util object//create constructorfunctionConsoleLog(){}//create function that will be added to the classconsole_log=function(message){if(typeof(console)!=='undefined'&&console!=null){console.log(message);}}//add class/static function to class by assignmentConsoleLog.log=console_log;//*** end console log object//*** new FrameRateCounter object prototypefunctionFrameRateCounter(fps){if(fps==undefined){this.fps=40}else{this.fps=fps}this.lastFrameCount=0;vardateTemp=newDate();this.frameLast=dateTemp.getTime();deletedateTemp;this.frameCtr=0;this.lastTime=dateTemp.getTime();this.step=1;}FrameRateCounter.prototype.countFrames=function(){vardateTemp=newDate();vartimeDifference=dateTemp.getTime()-this.lastTime;this.step=(timeDifference/1000)*this.fps;this.lastTime=dateTemp.getTime();this.frameCtr++;if(dateTemp.getTime()>=this.frameLast+1000){ConsoleLog.log("frame event");this.lastFrameCount=this.frameCtr;this.frameCtr=0;this.frameLast=dateTemp.getTime();}deletedateTemp;}</script>
</head><body><divstyle="position: absolute; top: 50px; left: 50px;"><canvasid="canvas"width="400"height="400">Your browser does not support HTML5 Canvas.</canvas></div></body></html>
Example A-3 gives the full code listing for CH11EX1.html. Notice that many of the code
styles and constructs we have used through the course of this book are
still in place in this application. Besides the obvious inclusion of code
related directly to WebGL, this application operates essentially the same
way as the other apps we discussed in this book.
<!doctype html><htmllang="en"><head><metacharset="UTF-8"><title>CH11EX1: WebGL Test</title>
<scriptsrc="modernizr.js"></script><scripttype="text/javascript"src="sylvester.js"></script><scripttype="text/javascript"src="glUtils.js"></script><scriptid="shader-fs"type="x-shader/x-fragment">#ifdefGL_ESprecisionhighpfloat;#endifvaryingvec4vColor;voidmain(void){gl_FragColor=vColor;}</script><scriptid="shader-vs"type="x-shader/x-vertex">attributevec3aVertexPosition;attributevec4aVertexColor;uniformmat4uMVMatrix;uniformmat4uPMatrix;varyingvec4vColor;voidmain(void){gl_Position=uPMatrix*uMVMatrix*vec4(aVertexPosition,1.0);vColor=aVertexColor;}</script><scripttype="text/javascript">window.addEventListener("load",eventWindowLoaded,false);functioneventWindowLoaded(){canvasApp();}functioncanvasSupport(){returnModernizr.canvas;}functionwebglSupport(){returnModernizr.webgl;}functioncanvasApp(){functiondrawScreen(){webGLContext.viewport(0,0,webGLContext.viewportWidth,webGLContext.viewportHeight);webGLContext.clear(webGLContext.COLOR_BUFFER_BIT|webGLContext.DEPTH_BUFFER_BIT);perspective(25,(webGLContext.viewportWidth/webGLContext.viewportHeight),0.1,100.0);loadIdentity();mvTranslate([0,0.0,−10.0]);mvPushMatrix();mvRotate(rotateCube,[0,.5,.5]);webGLContext.bindBuffer(webGLContext.ARRAY_BUFFER,cubeVertexPositionBuffer);webGLContext.vertexAttribPointer(shaderProgram.vertexPositionAttribute,cubeVertexPositionBuffer.itemSize,webGLContext.FLOAT,false,0,0);webGLContext.bindBuffer(webGLContext.ARRAY_BUFFER,cubeVertexColorBuffer);webGLContext.vertexAttribPointer(shaderProgram.vertexColorAttribute,cubeVertexColorBuffer.itemSize,webGLContext.FLOAT,false,0,0);webGLContext.bindBuffer(webGLContext.ELEMENT_ARRAY_BUFFER,cubeVertexIndexBuffer);setMatrixUniforms();webGLContext.drawElements(webGLContext.TRIANGLES,cubeVertexIndexBuffer.numItems,webGLContext.UNSIGNED_SHORT,0);mvPopMatrix();rotateCube+=2;}if(!canvasSupport()){alert("Unable to initialize Canvas");return;}if(!webglSupport()){alert("Unable to initialize WebGL");return;}varwebGLContext;varrotateCube=0;vartheCanvas=document.getElementById("canvasOne");webGLContext=theCanvas.getContext("experimental-webgl");webGLContext.viewportWidth=theCanvas.width;webGLContext.viewportHeight=theCanvas.height;initShaders();initBuffers();webGLContext.clearColor(0.0,0.0,0.0,1.0);webGLContext.clearDepth(1.0);webGLContext.enable(webGLContext.DEPTH_TEST);webGLContext.depthFunc(webGLContext.LEQUAL);setInterval(drawScreen,33);functiongetShader(webglcontext,id){varshaderScript=document.getElementById(id);if(!shaderScript){returnnull;}varstr="";varscriptChild=shaderScript.firstChild;while(scriptChild){if(scriptChild.nodeType==3){str+=scriptChild.textContent;}scriptChild=scriptChild.nextSibling;}varshader;if(shaderScript.type=="x-shader/x-fragment"){shader=webGLContext.createShader(webGLContext.FRAGMENT_SHADER);}elseif(shaderScript.type=="x-shader/x-vertex"){shader=webGLContext.createShader(webGLContext.VERTEX_SHADER);}else{returnnull;}webGLContext.shaderSource(shader,str);webGLContext.compileShader(shader);if(!webGLContext.getShaderParameter(shader,webGLContext.COMPILE_STATUS)){alert(webGLContext.getShaderInfoLog(shader));returnnull;}returnshader;}varshaderProgram;functioninitShaders(){varfragmentShader=getShader(webGLContext,"shader-fs");varvertexShader=getShader(webGLContext,"shader-vs");shaderProgram=webGLContext.createProgram();webGLContext.attachShader(shaderProgram,vertexShader);webGLContext.attachShader(shaderProgram,fragmentShader);webGLContext.linkProgram(shaderProgram);if(!webGLContext.getProgramParameter(shaderProgram,webGLContext.LINK_STATUS)){alert("Could not initialize shaders");}webGLContext.useProgram(shaderProgram);shaderProgram.vertexPositionAttribute=webGLContext.getAttribLocation(shaderProgram,"aVertexPosition");webGLContext.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);shaderProgram.vertexColorAttribute=webGLContext.getAttribLocation(shaderProgram,"aVertexColor");webGLContext.enableVertexAttribArray(shaderProgram.vertexColorAttribute);shaderProgram.pMatrixUniform=webGLContext.getUniformLocation(shaderProgram,"uPMatrix");shaderProgram.mvMatrixUniform=webGLContext.getUniformLocation(shaderProgram,"uMVMatrix");}varmvMatrix;varmvMatrixStack=[];functionmvPushMatrix(matrix){if(matrix){mvMatrixStack.push(matrix.dup());mvMatrix=matrix.dup();}else{mvMatrixStack.push(mvMatrix.dup());}}functionmvPopMatrix(){if(mvMatrixStack.length==0){throw"Invalid popMatrix!";}mvMatrix=mvMatrixStack.pop();returnmvMatrix;}functionloadIdentity(){mvMatrix=Matrix.I(4);}functionmultMatrix(matrix){mvMatrix=mvMatrix.x(matrix);}functionmvTranslate(vector){varmatrix=Matrix.Translation($V([vector[0],vector[1],vector[2]])).ensure4x4();multMatrix(matrix);}functionmvRotate(angle,vector){varradians=angle*Math.PI/180.0;varmatrix=Matrix.Rotation(radians,$V([vector[0],vector[1],vector[2]])).ensure4x4();multMatrix(matrix);}varpMatrix;functionperspective(fovy,aspect,znear,zfar){pMatrix=makePerspective(fovy,aspect,znear,zfar);}functionsetMatrixUniforms(){webGLContext.uniformMatrix4fv(shaderProgram.pMatrixUniform,false,newFloat32Array(pMatrix.flatten()));webGLContext.uniformMatrix4fv(shaderProgram.mvMatrixUniform,false,newFloat32Array(mvMatrix.flatten()));}varcubeVertexPositionBuffer;varcubeVertexColorBuffer;varcubeVertexIndexBuffer;functioninitBuffers(){cubeVertexPositionBuffer=webGLContext.createBuffer();webGLContext.bindBuffer(webGLContext.ARRAY_BUFFER,cubeVertexPositionBuffer);vertices=[// Front face−1.0,−1.0,1.0,1.0,−1.0,1.0,1.0,1.0,1.0,−1.0,1.0,1.0,// Back face−1.0,−1.0,−1.0,−1.0,1.0,−1.0,1.0,1.0,−1.0,1.0,−1.0,−1.0,// Top face−1.0,1.0,−1.0,−1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,−1.0,// Bottom face−1.0,−1.0,−1.0,1.0,−1.0,−1.0,1.0,−1.0,1.0,−1.0,−1.0,1.0,// Right face1.0,−1.0,−1.0,1.0,1.0,−1.0,1.0,1.0,1.0,1.0,−1.0,1.0,// Left face−1.0,−1.0,−1.0,−1.0,−1.0,1.0,−1.0,1.0,1.0,−1.0,1.0,−1.0,];webGLContext.bufferData(webGLContext.ARRAY_BUFFER,newFloat32Array(vertices),webGLContext.STATIC_DRAW);cubeVertexPositionBuffer.itemSize=3;cubeVertexPositionBuffer.numItems=24;cubeVertexColorBuffer=webGLContext.createBuffer();webGLContext.bindBuffer(webGLContext.ARRAY_BUFFER,cubeVertexColorBuffer);varcolors=[[1.0,1.0,1.0,1.0],// Front face[0.9,0.0,0.0,1.0],// Back face[0.6,0.6,0.6,1.0],// Top face[0.6,0.0,0.0,1.0],// Bottom face[0.3,0.0,0.0,1.0],// Right face[0.3,0.3,0.3,1.0],// Left face];varunpackedColors=[]for(variincolors){varcolor=colors[i];for(varj=0;j<4;j++){unpackedColors=unpackedColors.concat(color);}}webGLContext.bufferData(webGLContext.ARRAY_BUFFER,newFloat32Array(unpackedColors),webGLContext.STATIC_DRAW);cubeVertexColorBuffer.itemSize=4;cubeVertexColorBuffer.numItems=24;cubeVertexIndexBuffer=webGLContext.createBuffer();webGLContext.bindBuffer(webGLContext.ELEMENT_ARRAY_BUFFER,cubeVertexIndexBuffer);varcubeVertexIndices=[0,1,2,0,2,3,// Front face4,5,6,4,6,7,// Back face8,9,10,8,10,11,// Top face12,13,14,12,14,15,// Bottom face16,17,18,16,18,19,// Right face20,21,22,20,22,23// Left face]webGLContext.bufferData(webGLContext.ELEMENT_ARRAY_BUFFER,newUint16Array(cubeVertexIndices),webGLContext.STATIC_DRAW);cubeVertexIndexBuffer.itemSize=1;cubeVertexIndexBuffer.numItems=36;}}</script>
</head><body><divstyle="position: absolute; top: 50px; left: 50px;"><canvasid="canvasOne"width="500"height="500">Your browser does not support HTML5 Canvas or WebGLContext.</canvas></div></body></html>