站長資訊網(wǎng)
        最全最豐富的資訊網(wǎng)站

        自己動手打造html5星際迷航的示例代碼分享

        學(xué)習(xí)html5的canvas第三天,覺得還沒過癮,轉(zhuǎn)眼就忘,于是趁著有空,準(zhǔn)備弄個(gè)小游戲來玩!游戲應(yīng)該需要注意性能,還有一些邏輯需要斟酌,我想還需要用戶可修改性,也就是用戶配置。好,開始我們簡單但有趣的旅程吧——

        想先看效果的,先跳轉(zhuǎn)試玩一下吧!

        第一步,當(dāng)然需要一張畫布

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

        JavaScript的總體結(jié)構(gòu)如下:

        var定義一些變量  planeMoveTimer飛機(jī)移動監(jiān)聽/計(jì)時(shí)器  attackEnemyTimer發(fā)射炮彈計(jì)時(shí)器  onkeydown監(jiān)聽  onkeyup監(jiān)聽  drawPlane畫飛機(jī)  drawEnemy畫敵人

        首先預(yù)定義一些變量

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

        本游戲只用到一個(gè)外部資源,就是那張圖片,獲取地址請?jiān)L問本文底部給出的項(xiàng)目GitHub位置鏈接。跳轉(zhuǎn)

        先看畫圖的兩個(gè)方法

        function drawPlane(x, y) {      var img = new Image();      img.src = planeSrc;  // 飛機(jī)源圖地址      img.onload = function() {          ctx.drawImage(img, 0, 0, imgW, imgH, planeX, planeY, w, h);      }  }  function drawEnemy(){      for(var a=0;a<cw;a+=10) {          for(var b=0;b<ch-300;b+=10) {              ctx.beginPath();              ctx.fillStyle = "orange";              ctx.strokeStyle = "black";              ctx.strokeRect(a, b, 10 ,10);              ctx.fillRect(a, b, 10, 10);              ctx.closePath();          }      }  }

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

        接著,看兩個(gè)鍵盤事件:

        window.document.onkeydown = function(evt){      evt = (evt) ? evt : window.event;      switch(evt.keyCode) {          case 65:  // A              _keyA = 1;              break;          case 68:  // D              _keyD = 1;              break;          case 87:  // W              _keyW = 1;              break;          case 83:  // S              _keyS = 1;              break;      }  }  window.document.onkeyup = function(evt){      evt = (evt) ? evt : window.event;      switch(evt.keyCode) {          case 65:  // A              _keyA = 0;              break;          case 68:  // D              _keyD = 0;              break;          case 87:  // W              _keyW = 0;              break;          case 83:  // S              _keyS = 0;              break;      }  }

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

        飛機(jī)移動計(jì)時(shí)器如下:

        var planeMoveTimer = window.setInterval(function(){      if(_keyA||_keyD||_keyW||_keyS){          ctx.clearRect(planeX, planeY, w, h);          _keyA && (planeX-=step);          _keyD && (planeX+=step);          _keyW && (planeY-=step);          _keyS && (planeY+=step);          planeX>=0 || (planeX=0);          planeX<=(cw-w) || (planeX=cw-w);          planeY>=0 || (planeY=0);          planeY<=(ch-h) || (planeY=ch-h);          drawPlane(planeX, planeY);      }  }, 10);

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

        通過判斷按鍵狀態(tài),每次移動的步距為預(yù)先設(shè)置的step,并做好邊界處理。

        然后是攻擊計(jì)時(shí)器:

        var attackEnemyTimer = window.setInterval(function(){      var cannonX = planeX+Math.floor(w/2);  // 炮口X軸位置      var cannonY = planeY;  // 炮口Y軸位置      var tmpTimer = window.setInterval(function(){  // 每顆炮彈的移動計(jì)時(shí)器          ctx.clearRect(cannonX-1, cannonY-3, 2, 3);          cannonY -= 3;  // 炮彈步距          if(cannonY<0){              // 炮彈的貫透效果              ctx.beginPath();              ctx.moveTo(cannonX, 100);  // 100為enemy的最低位置              ctx.strokeStyle = "white";              ctx.lineWidth = "4";  // 模擬不規(guī)則毀壞,暫時(shí)尚未沒實(shí)現(xiàn)              ctx.lineTo(cannonX, 0);              ctx.stroke();              ctx.closePath();              window.clearInterval(tmpTimer);  // 清除該炮彈的計(jì)時(shí)器          }          ctx.clearRect(cannonX-1, cannonY-3, 2, 3);          ctx.beginPath();          ctx.fillStyle="red";          ctx.fillRect(cannonX-1, cannonY-3, 2, 3);  // 炮彈大小:2X3          ctx.closePath();      }, 0);  }, 500);

        每0.5s發(fā)射一顆炮彈,每顆炮彈又單獨(dú)設(shè)置一個(gè)計(jì)時(shí)器,以便控制,炮彈的移動我也是采用先擦后畫的方式,由于炮彈移動也有步距,所謂炮彈貫透效果就是直接畫一條顏色跟背景色一樣的直線而已。試著修改炮彈步距可以調(diào)節(jié)炮彈的移動速度,也可以調(diào)節(jié)炮彈的尺寸。

        最后一步了,還差點(diǎn)什么,一開始就要畫好敵人和飛機(jī)啦!

        1 drawPlane();  2 drawEnemy();

        大功告成!還想繼續(xù)優(yōu)化增加可玩性的,但實(shí)在是沒時(shí)間弄了,還有很多其他的東西要學(xué),所以這個(gè)游戲就先這樣啦!是不是很簡單!哈哈,囧了吧,標(biāo)題太誘惑人,沒辦法!

        贊(0)
        分享到: 更多 (0)
        網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
        主站蜘蛛池模板: 日韩精品无码熟人妻视频| 久久中文精品无码中文字幕| 精品一久久香蕉国产线看播放| 久久棈精品久久久久久噜噜| 欧美成人精品第一区二区三区 | 欧美激情精品久久久久久| 大桥未久在线精品视频在线| 久久久免费精品re6| 亚洲国产精品毛片av不卡在线| 国产精品成人免费观看 | laowang在线精品视频| 亚洲AV无码成人精品区天堂| 98香蕉草草视频在线精品看| 国产精品自拍一区| 国内精品久久人妻互换| 亚洲精品成人网站在线观看| 欧美日韩精品系列一区二区三区国产一区二区精品 | 日韩视频中文字幕精品偷拍| 国产精品嫩草影院久久| 亚洲天堂久久精品| 青青草国产精品久久久久| 精品一卡2卡三卡4卡免费视频| 精品国产VA久久久久久久冰| 在线观看国产精品普通话对白精品| 麻豆精品三级全部视频| 久久久无码精品午夜| 欧美日韩国产精品系列| 人妻少妇看A偷人无码精品| 日本欧美国产精品第一页久久| 欧美精品高清在线xxxx| 麻豆精品| 亚洲精品亚洲人成在线观看下载| 白浆都出来了视频国产精品| 国产精品无套内射迪丽热巴| 国产精品亚洲精品日韩已满| 69国产成人综合久久精品| 2048亚洲精品国产| 四虎国产精品免费久久5151| 国产成人精品怡红院在线观看| 国产成人精品久久亚洲高清不卡| 92国产精品午夜福利免费|