HTML5遊戲開發進階指南讀書筆記
阿新 • • 發佈:2018-12-17
建立遊戲圖層#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 }