PS:這個坦克大戰是在網上下的一段源碼之后,自己進行的重寫。 寫這個的目的是為了鞏固自己這段時間對js的學習。整理到博客上,算是對自己近端時間學習js的一個整理。 同時也希望可以幫助到學習js的園友。由於自己也是剛學js不久,所以難免出現錯誤。如果發現希望給予指正。 這個教程適合熟悉js基本語法和面向對象語法的園友學習。 本身沒有太難的東西,這個案例將js面向對象用的比較好,可以作為js面向對象的入門教程。
1. 創建基本對象,實現坦克簡單的移動。
1.1 如何在地圖中繪制畫布?
考慮到瀏覽器兼容的問題,我們用操作dom的方式來實現游戲對象的繪制和刷新。我們如何存儲我們的地圖呢? 我們應該把地圖用一個二維數組來保存, js中沒有二維數組,但是可以通過在一維數組從存儲數組來實現。
1.2 代碼實現
我們將畫布設計為 13 * 13 的一個二維數組,每個元素在地圖中對應的長和寬均為40px,可以把整個地圖看成由 40px*40p x大小的單元格組成的一個表格,那么我們整個畫布的大小為 520px * 520px ;
上代碼前先給大家來一張對象關系圖:

1.2.1 創建頂級對象
html代碼:

1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 2 <html> 3 <head> 4 <title>坦克大戰</title> 5 <link rel=stylesheet href="css/main.css" /> 6 <script src="js/Common.js"></script> 7 <script src="js/TankObject.js"></script> 8 <script src="js/Mover.js"></script> 9 <script src="js/Tank.js"></script> 10 <script src="js/Frame.js"></script> 11 <script> 12 window.onload = function () { 13 // 調用游戲裝載對象 14 var loader = new GameLoader(); 15 loader.Begin(); 16 } 17 </script> 18 </head> 19 20 <body> 21 <!--地圖容器--> 22 <div id="divMap"> 23 </div> 24 <div id="debugInfo"> 25 </div> 26 </body> 27 </html>
TankObject.js文件:

1 // 頂級對象 2 TankObject = function () { 3 this.XPosition = 0; // 對象在地圖(13*13)中的X的位置 4 this.YPosition = 0; 5 this.UI = null; // dom元素 6 } 7 // 更改UI靜態方法 8 TankObject.prototype.UpdateUI = function (battlFiled) { } 9 // 設置位置,參數是這樣:1*40,6*40 10 TankObject.prototype.SetPosition = function (leftPosition, topPosition) { 11 // 在地圖的位置 Math.round四舍五入 12 this.XPosition = Math.round(leftPosition / 40); 13 this.YPosition = Math.round(topPosition / 40); 14 // 設置在窗體上的位置 15 if (this.UI != null && this.UI.style != null) { 16 this.UI.style.left = leftPosition + "px"; 17 this.UI.style.top = topPosition + "px"; 18 } 19 }
這里我們用X,Y坐標表示對象在地圖上的位置。后面我們會將地圖中的每個對象都放入二維數組中,這時可以通過X,Y坐標來取得對應的對象。
然后用css中的left和top來控制我們對象在窗體中的位置。(可以移動的對象:坦克,子彈)
1.2.2 創建公用對象
我們還需要創建一個公共的對象,來寫入我們常用的一些方法。
Common.js:

// 坦克移動的四個方向 var EnumDirection = { Up: "0", Right: "1", Down: "2", Left: "3" }; // 通用方法對象 var UtilityClass = { // 創建dom元素到parentNode中,可指定id,className CreateE: function (type, id, className, parentNode) { var J = document.createElement(type); if (id) { J.id = id }; if (className) { J.className = className }; return parentNode.appendChild(J); }, // 移除元素 RemoveE: function (obj, parentNode) { parentNode.removeChild(obj); }, GetFunctionName: function (context, argumentCallee) { for (var i in context) { if (context[i] == argumentCallee) { return i }; } return ""; }, // 綁定事件,返回func方法,this為傳入的obj BindFunction: function (obj,func) { return function () { func.apply(obj, arguments); }; } };
1.2.3 創建移動對象
Mover.js

1 // 移動對象,繼承自頂層對象 2 Mover = function () { 3 this.Direction = EnumDirection.Up; 4 this.Speed = 1; 5 } 6 Mover.prototype = new TankObject(); 7 Mover.prototype.Move = function () { 8 if (this.lock) { 9 return;/* 停用或者尚在步進中,操作無效 */ 10 } 11 // 根據方向設置坦克的背景圖片 12 this.UI.style.backgroundPosition = "0 -" + this.Direction * 40 + "px"; 13 // 如果方向是上和下,vp就是top;如果方向是上和左,val就是-1 14 var vp = ["top", "left"][((this.Direction == EnumDirection.Up) || (this.Direction == EnumDirection.Down)) ? 0 : 1]; 15 var val = ((this.Direction == EnumDirection.Up) || (this.Direction == EnumDirection.Left)) ? -1 : 1; 16 this.lock = true;/* 加鎖 */ 17 // 把當前對象保存到This 18 var This = this; 19 // 記錄對象移動起始位置 20 var startmoveP = parseInt(This.UI.style[vp]); 21 var xp = This.XPosition, yp = This.YPosition; 22 var subMove = setInterval(function () { 23 // 開始移動,每次移動5px 24 This.UI.style[vp] = parseInt(This.UI.style[vp]) + 5 * val + "px"; 25 // 每次移動一個單元格 40px 26 if (Math.abs((parseInt(This.UI.style[vp]) - startmoveP)) >= 40) { 27 clearInterval(subMove); 28 This.lock = false;/* 解鎖,允許再次步進 */ 29 // 記錄對象移動后在表格中的位置 30 This.XPosition = Math.round(This.UI.offsetLeft / 40); 31 This.YPosition = Math.round(This.UI.offsetTop / 40); 32 33 } 34 }, 80 - this.Speed * 10); 35 36 }
這里的移動對象繼承自我們的頂級對象 ,這里this就代表調用Move方法的對象。
Move對象的功能根據對象的方向和速度進行移動,每次移動5px總共移動40px一個單元格。后面這個對象還會進行擴展,會加入碰撞檢測等功能。
1.2.4 創建坦克對象
Tank.js 文件:

//tank對象 繼承自Mover Tank=function(){} Tank.prototype = new Mover(); // 創建玩家坦克,繼承自tank對象 SelfTank = function () { this.UI = UtilityClass.CreateE("div", "", "itank", document.getElementById("divMap")); this.MovingState = false; this.Speed = 4; } SelfTank.prototype = new Tank(); // 設置坦克的位置 SelfTank.prototype.UpdateUI = function () { this.UI.className = "itank"; // 頂級對象方法,設置坦克的位置 this.SetPosition(this.XPosition * 40, this.YPosition * 40); }
現在只創建了玩家坦克,后面我們還會往里添加敵人坦克。
1.2.5 創建游戲裝載對象(核心)

1 // 游戲載入對象 整個游戲的核心對象 2 GameLoader = function () { 3 this.mapContainer = document.getElementById("divMap"); // 存放游戲地圖的div 4 this._selfTank = null; // 玩家坦克 5 this._gameListener = null; // 游戲主循環計時器id 6 } 7 GameLoader.prototype = { 8 Begin: function () { 9 // 初始化玩家坦克 10 var selfT = new SelfTank(); 11 selfT.XPosition = 4; 12 selfT.YPosition = 12; 13 selfT.UpdateUI(); 14 this._selfTank = selfT; 15 16 // 添加按鍵事件 17 var warpper = UtilityClass.BindFunction(this, this.OnKeyDown); 18 window.onkeydown = document.body.onkeydown = warpper; 19 warpper = UtilityClass.BindFunction(this, this.OnKeyUp); 20 window.onkeyup = document.body.onkeyup = warpper; 21 // 游戲主循環 22 warpper = UtilityClass.BindFunction(this, this.Run); 23 /*長定時器監聽控制鍵*/ 24 this._gameListener = setInterval(warpper, 20); 25 26 } 27 // 鍵盤按下玩家坦克開始移動 28 , OnKeyDown: function (e) { 29 switch ((window.event || e).keyCode) { 30 case 37: 31 this._selfTank.Direction = EnumDirection.Left; 32 this._selfTank.MovingState = true; 33 break; //左 34 case 38: 35 this._selfTank.Direction = EnumDirection.Up; 36 this._selfTank.MovingState = true; 37 break; //上 38 case 39: 39 this._selfTank.Direction = EnumDirection.Right; 40 this._selfTank.MovingState = true; 41 break; //右 42 case 40: 43 this._selfTank.Direction = EnumDirection.Down; 44 this._selfTank.MovingState = true; 45 break; //下 46 } 47 48 } 49 // 按鍵彈起停止移動 50 , OnKeyUp: function (e) { 51 switch ((window.event || e).keyCode) { 52 case 37: 53 case 38: 54 case 39: 55 case 40: 56 this._selfTank.MovingState = false; 57 break; 58 } 59 } 60 /*游戲主循環運行函數,游戲的心臟,樞紐*/ 61 , Run: function () { 62 if (this._selfTank.MovingState) { 63 this._selfTank.Move(); 64 } 65 } 66 67 68 };
游戲裝載對象代碼看起來很多,其實就做了兩件事情:
1、創建玩家坦克對象。
2、添加按鍵監聽事件,當玩家按下移動鍵調用坦克Move方法移動坦克。
總結:到這里我們的坦克可以通過按鍵自由的移動了。下一步我們需要完善地圖和碰撞檢測。
這個版本源碼下載地址: