1. 程式人生 > >HTML5遊戲開發進階指南讀書筆記

HTML5遊戲開發進階指南讀書筆記

建立遊戲圖層#gamecanvas(遊戲圖層)、#scorescreen(得分顯示圖層)、#gamestartscreen(遊戲開始圖層)、#levelselectscreen(關卡選擇圖層)、#loadingscreen(資源載入圖層)、#endingscreen(遊戲結束圖層)所有圖層共用.gamelayer,所有圖層放於#gamecontainer中。

解決動畫函式requestanimationframe相容性問題:

 1 (function(){
 2     var vendors = ['o','webkit','moz','ms'];
 3     var lastTime = 0;
 4     for(var i=0; i<vendors.length&&!window.requestAnimationFrame; i++){        //迴圈檢測當前瀏覽器支援的方法名
 5         window.requestAnimationFrame = window[vendors[i]+'requestAnimationFrame'];           //將不同瀏覽器動畫函式名統一
 6         window.cancelAnimationFrame = window[vendors[i]+'CancelAnimationFrame']||
 7                                       window[vendors[i]+'CancelRequestAnimationFrame'];
 8     }
 9     if(!window.requestAnimationFrame){    //檢測瀏覽器是否支援動畫函式
10         window.requestAnimationFrame =function (callback,element) {
11             var currTime = new Date().getTime();
12             var timeToCall = Math.max(0,16-(currTime-lastTime));         //理想重新整理率為60hz(每1/60秒重繪一次),不斷嘗試修正重新整理率。
13             var id = window.setTimeout(callback(),timeToCall);         //timeToCall為0時各瀏覽器將採用最小呼叫單位時間。
14             lastTime =currTime+timeToCall;         //執行後的時間。
15             return id;
16         }
17     }
18     if (!window.cancelAnimationFrame){
19         window.cancelAnimationFrame = function(id){
20             clearTimeout(id);
21         }
22     }
23 
24 }());

構建資源載入器:

 1 var loader = {
 2         totalCount : 0,
 3         loadedCount : 0,
 4         loaded : true,
 5         soundFileExtn:'mp3',
 6         init:function(){
 7             var audio = new Audio();
 8             if(audio.canPlayType){
 9                 loader.soundFileExtn = audio.canPlayType('audio/mpeg')?'.mp3':
10                 audio.canPlayType('audio/ogg')?'.ogg':undefined;
11             }
12         },
13         loadImg:function (url) {
14           loader.totalCount++;
15           loader.loaded = false;
16           $('#loadingscreen').show();
17           var img =new Image();
18           img.src = url;
19           img.onload = loader.itemLoaded;
20           return img;
21         },
22         loadSound:function (url) {
23             loader.totalCount++;
24             loader.loaded = false;
25             $('#loadingscreen').show();
26             var audio =new Audio();
27             audio.src = url;
28             audio.addEventListener("canplaythrough",loader.itemLoaded,false);
29             return audio;
30         },
31         itemLoaded:function () {       //某單個資源載入完成後觸發該函式
32             loader.loadedCount++;
33             $('#loadingmessage').html('loaded: '+loader.loadedCount+' of '+loader.totalCount)
34             if (loader.totalCount == loader.loadedCount){           //判斷是否已全部載入完
35                 loader.loaded = true;
36                 $('#loadingscreen').hide();
37             }
38             if (loader.onload){
39                 loader.onload();
40             }
41     }
42 }

建立關卡載入器:

 1 var level = {
 2     data:[    //建立data陣列儲存各關卡資料
 3         {
 4             foreground:'desert-foreground',
 5             background:'clouds-background',
 6         },
 7         {
 8             foreground:'desert-foreground',
 9             background:'clouds-background',
10         },
11         {
12             foreground:'desert-foreground',
13             background:'clouds-background',
14         }
15     ],
16     init:function () {
17         var html='';
18         for(var i =0; i<level.data.length; i++){
19             html +='<input type="button" value="'+(i+1)+'">';
20         };
21         $('#levelselectscreen').html(html);
22         $('#levelselectscreen input').click(function () {
23             level.load(this.value-1);         //載入各關卡資料。
24             $('#levelselectscreen').hide();
25         })
26     },
27     load:function (number) {
28         game.score = 0;
29         $('#score').html("score:"+game.score);
30         game.currtLevel.foregroundImage = loader.loadImg("img/backgrounds/"+level.data[number].foreground+".png");
31         game.currtLevel.backgroundImage = loader.loadImg("img/backgrounds/"+level.data[number].background+".png");
32         //將當前關卡中的資料儲存到game.currtLevel物件中。       game.slingshotImage = loader.loadImg("img/slingshot.png");
33         game.slingshotFrontImage = loader.loadImg("img/slingshot-front.png");
34         if (loader.loaded){
35             game.start();          //當前關卡資料載入完成後執行game.start()。
36         } else{
37             loader.onload = game.start();
38         }
39     }
40 }

構建滑鼠物件:

 1 var mouse = {
 2     x:0,
 3     y:0,
 4     down:false,
 5     dragging:false,
 6     init:function(){       //為在#gamecanvas上的滑鼠事件繫結監聽函式
 7         $('#gamecanvas').mousemove(mouse.mousemovehandler);
 8         $('#gamecanvas').mousedown(mouse.mousedownhandler);
 9         $('#gamecanvas').mouseup(mouse.mouseuphandler);
10         $('#gamecanvas').mouseout(mouse.mouseuphandler);
11     },
12     mousemovehandler:function (ev) {
13         var offset = $('#gamecanvas').offset();
14         mouse.x = ev.pageX - offset.left;
15         mouse.y = ev.pageY - offset.right;         //獲取滑鼠在畫布中的座標
16         if(mouse.down){      //判斷是否點選並移動
17             mouse.dragging = true;
18         }
19     },
20     mousedownhandler:function (ev) {
21         mouse.down = true;
22         mouse.downX = mouse.x;
23         mouse.downY = mouse.y;
24         ev.originalEvent.preventDefault();
25     },
26     mouseuphandler:function () {
27         mouse.down = false;
28         mouse.dragging = false;
29     }
30 }

構建game物件

初始化init( ):呼叫loader物件初始化函式檢測瀏覽器支援的音訊格式;

呼叫level物件初始化函式獲取內部定義的關卡資料,加載出#levelselectscreen關卡按鈕併為按鈕繫結關卡資源載入函式,對應關卡資源載入完畢呼叫game物件的start函式;

呼叫mouse物件初始化函式為滑鼠行為繫結處理函式;

獲取#gamecanvas繪製上下文;

為game物件建立start函式

1 start:function () {
2         $('.gamelayer').hide();
3         $('#gamecanvas').show();
4         $('#scorescreen').show();
5         game.mode = "intro";      //進入'intro'狀態
6         game.ended = false;
7         game.animateFrame = window.requestAnimationFrame(game.animate,game.canvas);       //執行game.animate函式,開始過場動畫
8     }

為game物件建立animate函式

 1 animate:function () {
 2         game.handlePanning();       //確定game.offsetLeft大小和“方向”
 3         game.context.drawImage(game.currtLevel.backgroundImage,game.offsetLeft/4,0,640,480,0,0,640,480);
 4         game.context.drawImage(game.currtLevel.foregroundImage,game.offsetLeft,0,640,480,0,0,640,480);       //動態繪製背景圖
 5         game.context.drawImage(game.slingshotImage,game.slingshotX,game.slingshotY);
 6         game.context.drawImage(game.slingshotFrontImage,game.slingshotX,game.slingshotY);
 7         if(!game.ended){        //若遊戲未結束不斷重繪
 8             game.animateFrame = window.requestAnimationFrame(game.animate,game.canvas);
 9         }
10     }

為game物件建立handlePanning函式

 1 handlePanning:function(){  //通過game.mode遊戲狀態確定移動方式並切換遊戲狀態
 2         if(game.mode == "intro"){
 3             if(game.panTo(700)){           //“啟用”,判斷當前是否移動到指定位置並進入下一個遊戲狀態
 4                 game.mode = "load-next-hero";
 5             };
 6         }
 7         if(game.mode == "wait-for-firing"){
 8             if(mouse.dragging){
 9                 game.panTo(mouse.x+game.offsetLeft);
10             }else {
11                 game.panTo(game.slingshotX);
12             }
13         }
14         if(game.mode == "load-next-hero"){
15             game.panTo(game.slingshotX);
16             game.mode == "wait-for-firing";
17         }
18 
19     }

為game物件建立panTo函式

 1 panTo:function(newcenter){
 2         if(Math.abs(newcenter-game.offsetLeft-game.canvas.width/4)>0 && game.offsetLeft >= game.minoffset&&
 3            game.offsetLeft <= game.maxoffset){       //判斷當前中心位置是否位於兩臨界點間或在制定中心位置附近
 4             var deltaX = Math.round((newcenter-game.offsetLeft-game.canvas.width/4)/2);         //初步確定單次移動量和移動方向
 5             if (Math.abs(deltaX)>game.maxspeed){         //控制在maxspeed中
 6                 deltaX = game.maxspeed*Math.abs(deltaX)/deltaX;
 7             }
 8             console.log("deltaX="+deltaX);
 9             game.offsetLeft += deltaX;
10             console.log("game.offsetLeft="+game.offsetLeft);
11         }else{       //完成指定中心位移return 結果停止位移(動畫)
12             return true;
13         }
14         if (game.offsetLeft < game.minoffset) {       //超過零界點重置
15             game.offsetLeft = game.minoffset;
16             return true;
17         }
18         if (game.offsetLeft > game.maxoffset) {
19             game.offsetLeft = game.maxoffset;
20             return true;
21         }
22         return false;
23     }