自己動手打造html5星際迷航!


學習html5的canvas第三天,覺得還沒過癮,轉眼就忘,於是趁着有空,准備弄個小游戲來玩!游戲應該需要注意性能,還有一些邏輯需要斟酌,我想還需要用戶可修改性,也就是用戶配置。好,開始我們簡單但有趣的旅程吧——

想先看效果的,先跳轉試玩一下吧!

第一步,當然需要一張畫布

1 <canvas id="canvas" width="300" height="400">你的瀏覽器不支持Canvas</canvas>

JavaScript的總體結構如下:

var定義一些變量
planeMoveTimer飛機移動監聽/計時器
attackEnemyTimer發射炮彈計時器
onkeydown監聽
onkeyup監聽
drawPlane畫飛機
drawEnemy畫敵人

首先預定義一些變量

 1 var _keyA = _keyD = _keyW = _keyS = 0,  // 存儲按鍵狀態
 2 
 3     step = 8,                          // 飛機移動速率
 4     w = 34, h = 44,                  // 飛機實際大小
 5     planeX = 133, planeY = 356,      // 飛機目前位置
 6     planeSrc = "feiji.png",          // 飛機素材位置
 7     imgW = 177, imgH = 220,          // 飛機源圖尺寸
 8 
 9     cw = 300, ch = 400,  // 畫布大小
10     canvas = document.getElementById("canvas"),
11     ctx = canvas.getContext("2d");

本游戲只用到一個外部資源,就是那張圖片,獲取地址請訪問本文底部給出的項目GitHub位置鏈接。跳轉

先看畫圖的兩個方法

 1 function drawPlane(x, y) {
 2     var img = new Image();
 3     img.src = planeSrc;  // 飛機源圖地址
 4     img.onload = function() {
 5         ctx.drawImage(img, 0, 0, imgW, imgH, planeX, planeY, w, h);
 6     }
 7 }
 8 function drawEnemy(){
 9     for(var a=0;a<cw;a+=10) {
10         for(var b=0;b<ch-300;b+=10) {
11             ctx.beginPath();
12             ctx.fillStyle = "orange";
13             ctx.strokeStyle = "black";
14             ctx.strokeRect(a, b, 10 ,10);
15             ctx.fillRect(a, b, 10, 10);
16             ctx.closePath();
17         }
18     }
19 }

 飛機的圖片一定要在onload()方法里才能把飛機畫出來,目前的敵人還是一堆橙色的不會動的磚頭,通過遍歷在畫布的頂端把它們畫出來。

接着,看兩個鍵盤事件:

 1 window.document.onkeydown = function(evt){
 2     evt = (evt) ? evt : window.event;
 3     switch(evt.keyCode) {
 4         case 65:  // A
 5             _keyA = 1;
 6             break;
 7         case 68:  // D
 8             _keyD = 1;
 9             break;
10         case 87:  // W
11             _keyW = 1;
12             break;
13         case 83:  // S
14             _keyS = 1;
15             break;
16     }
17 }
18 window.document.onkeyup = function(evt){
19     evt = (evt) ? evt : window.event;
20     switch(evt.keyCode) {
21         case 65:  // A
22             _keyA = 0;
23             break;
24         case 68:  // D
25             _keyD = 0;
26             break;
27         case 87:  // W
28             _keyW = 0;
29             break;
30         case 83:  // S
31             _keyS = 0;
32             break;
33     }
34 }

至於為什么要在兩個事件里設置變量_keyA、_keyD、_keyW、_keyS,而不是直接觸發畫圖事件,原因是——同時長按兩個鍵時,無法同時觸發事件,先按者只觸發一次,只有后按者在按着鍵的時候才能一直觸發事件,簡單點來說,如果我想要向左上角移動,同時按下A和W,假設A比W慢了一點點,即時很微小,那么飛機的移動路徑是先上移一步然后一直向左移動,這顯然不是我想要的,我用4個變量來存儲按鍵的狀態,按下鍵的時候,設置其狀態為1,在按鍵起來的時候,設置其狀態為0,然后我們用計時器來不斷地讀這些鍵的狀態並及時更新飛機的狀態。

飛機移動計時器如下:

 1 var planeMoveTimer = window.setInterval(function(){
 2     if(_keyA||_keyD||_keyW||_keyS){
 3         ctx.clearRect(planeX, planeY, w, h);
 4         _keyA && (planeX-=step);
 5         _keyD && (planeX+=step);
 6         _keyW && (planeY-=step);
 7         _keyS && (planeY+=step);
 8         planeX>=0 || (planeX=0);
 9         planeX<=(cw-w) || (planeX=cw-w);
10         planeY>=0 || (planeY=0);
11         planeY<=(ch-h) || (planeY=ch-h);
12         drawPlane(planeX, planeY);
13     }
14 }, 10);

ctx.clearRect()用來清除原來位置的飛機,為繪制飛機的下一狀態做准備,但是有一個很大的問題,它是直接清除整塊的,要是游戲有背景,有交疊,那不是要把這些不是飛機的東西也一並清空了?恕我愚昧,暫時不考慮這個問題。

通過判斷按鍵狀態,每次移動的步距為預先設置的step,並做好邊界處理。

然后是攻擊計時器:

 1 var attackEnemyTimer = window.setInterval(function(){
 2     var cannonX = planeX+Math.floor(w/2);  // 炮口X軸位置
 3     var cannonY = planeY;  // 炮口Y軸位置
 4     var tmpTimer = window.setInterval(function(){  // 每顆炮彈的移動計時器
 5         ctx.clearRect(cannonX-1, cannonY-3, 2, 3);
 6         cannonY -= 3;  // 炮彈步距
 7         if(cannonY<0){
 8             // 炮彈的貫透效果
 9             ctx.beginPath();
10             ctx.moveTo(cannonX, 100);  // 100為enemy的最低位置
11             ctx.strokeStyle = "white";
12             ctx.lineWidth = "4";  // 模擬不規則毀壞,暫時尚未沒實現
13             ctx.lineTo(cannonX, 0);
14             ctx.stroke();
15             ctx.closePath();
16             window.clearInterval(tmpTimer);  // 清除該炮彈的計時器
17         }
18         ctx.clearRect(cannonX-1, cannonY-3, 2, 3);
19         ctx.beginPath();
20         ctx.fillStyle="red";
21         ctx.fillRect(cannonX-1, cannonY-3, 2, 3);  // 炮彈大小:2X3
22         ctx.closePath();
23     }, 0);
24 }, 500);

每0.5s發射一顆炮彈,每顆炮彈又單獨設置一個計時器,以便控制,炮彈的移動我也是采用先擦后畫的方式,由於炮彈移動也有步距,所謂炮彈貫透效果就是直接畫一條顏色跟背景色一樣的直線而已。試着修改炮彈步距可以調節炮彈的移動速度,也可以調節炮彈的尺寸。

最后一步了,還差點什么,一開始就要畫好敵人和飛機啦!

1 drawPlane();
2 drawEnemy();

大功告成!還想繼續優化增加可玩性的,但實在是沒時間弄了,還有很多其他的東西要學,所以這個游戲就先這樣啦!是不是很簡單!哈哈,囧了吧,標題太誘惑人,沒辦法!

其他:

在線試玩:http://xzh-loop.github.io/Manji/lab/html5game/Plane.html

訪問這個項目的GitHub位置:https://github.com/xzh-loop/Manji/tree/gh-pages/lab/html5game

訪問我的GitHub Pages:http://xzh-loop.github.io/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM