用javascript 物件導向製作坦克大戰(四)
我們現在還差一個重要的功能,沒錯,敵人坦克的建立以及子彈擊中敵人坦克時的碰撞檢測功能。 5. 建立敵人坦克完成炮彈碰撞檢測 5.1 建立敵人坦克對象 敵人坦克和玩家坦克一樣,同樣繼承自我們的坦克對象。所以我們在Tank.js中寫入以下代碼: 複製代碼 1 // 敵人坦克對象 2 EnimyTank = function () { 3 this.Direction = EnumDirection.Down; 4 this.BombNum = 1; 5 this.UI = UtilityClass.CreateE("div", "", "etank", document.getElementById("divMap")); 6 this.UI.style.backgroundPosition = "0 -" + this.Direction * 40 + "px"; 7 8 } 9 10 EnimyTank.prototype = new Tank;複製代碼 然後在我們的遊戲裝載對象初始化遊戲時建立敵人坦克。 1 var enimyT1 = new EnimyTank();2 enimyT1.XPosition = 0;3 enimyT1.YPosition = 0;4 enimyT1.UpdateUI(this._battleField);5 this._enimyTanks.push(enimyT1); 5.2 敵人坦克移動和發射炮彈 坦克建立好了,我們怎麼讓他動起來呢? 很簡單,只需要在我們的遊戲裝載對象中添加一個敵人坦克移動並發射的方法,並且在Run主迴圈中進行調用就可以了。 代碼: 複製代碼1 for (var i = 0; i < this._enimyTanks.length; i++) {2 3 if (this._enimyTanks[i] instanceof Mover) {4 this._enimyTanks[i].Move(this._battleField);5 if (Math.random() * 100 < 5) { this._enimyTanks[i].Shot(this._battleField) };/* 5%的機率發射炮彈 */6 }7 }複製代碼 ok,現在我們的坦克可以正常的移動和發射炮彈了。但是我們發現坦克移動的方向不會發生改變,所以還需要一個小小的處理,在我們的Mover對象的Move方法中添加以下代碼,敵人坦克就能隨機變換方向了。 1 // 敵人坦克有30%幾率變換方向2 if ((this instanceof EnimyTank) && Math.random() * 100 > 30) {3 this.Direction = parseInt(Math.random() * 4);4 } 5.3 炮彈碰撞檢測 之前我們炮彈的碰撞檢測唯寫了打到障礙物的檢測,所以我們還需要添加炮彈碰撞到坦克的情況。 實現思路很簡單,當我們的子彈穿過空地或草地(坦克能停留的兩種地形)時,我們檢測地圖的佔有對象是不是坦克就可以了。上代碼: Bomb.js: 複製代碼 1 // 如果下一個是草或者空地 2 else if (nextObj.obj instanceof EmptyB || nextObj.obj instanceof TodB) { 3 // 玩家炮彈打中敵人坦克 4 if (nextObj.occupier instanceof EnimyTank && this.Owner instanceof SelfTank) { 5 UtilityClass.RemoveE(nextObj.occupier.UI, document.getElementById("divMap")); 6 nextObj.occupier.UI = null; 7 GameLoader.prototype._enimyTanks.pop(); 8 nextObj.occupier = null; 9 } // 敵人炮彈打中玩家坦克10 else if (nextObj.occupier instanceof SelfTank && this.Owner instanceof EnimyTank) {11 //UtilityClass.RemoveE(nextObj.occupier.UI, document.getElementById("divMap"));12 //nextObj.occupier = null;13 }14 }複製代碼 此時,我們會發現當玩家的炮彈擊中敵人後,敵人坦克會隨機的佔有他的4個方向中的一個儲存格。這是什麼原因造成的呢? 我們可以想想,當我們的炮彈命中敵人的時候,他有可能正在移動。這時候我們把他移除了,但是他的Move的步進方法還會繼續執行,別忘了,我們是用的setInterval,所以他就鬼使神差步進到下一個儲存格。 這時候坦克對象移除了,但是佔用還在,就會出問題了。 解決的方案很簡單,我們在移除坦克時將坦克的UI 已經設定為null了,所以在步進前我們判斷他UI的值為null時,我們就停止步進就ok了。代碼很簡單: 複製代碼1 if (This instanceof EnimyTank) {2 // 如果敵人坦克被銷毀,則停止步進3 if (This.UI == null) {4 clearInterval(subMove);5 }6 }複製代碼 5.4 多個敵人坦克的解決方案 這時候我們還發現一個嚴重的問題: 我們的敵人坦克是儲存在遊戲裝載對象裡的一個數組,當我們消滅敵人坦克時,我們不知道到底該從中移除哪個坦克。 其實這個問題的解決思路相當簡單:在初始化敵人坦克時給他一個屬性儲存他在數組中的索引,當需要消除坦克對象時,我們直接根據索引移除就可以了。 1、初始化儲存索引 enimyT1.index = this._enimyTanks.length; 2、給Array擴充原型方法,移除指定位置的數組。 複製代碼 1 Array.prototype.removeAt = function (index) { 2 var arr = [], j = 0; 3 // 遍曆數組,過濾指定位置的元素 4 for (var i = 0; i < this.length; i++) { 5 if (i != index) { 6 arr[j++] = this[i]; 7 } 8 } 9 return arr;10 }複製代碼 3、修改炮彈打中敵人的代碼。 複製代碼 1 // 玩家炮彈打中敵人坦克 2 if (nextObj.occupier instanceof EnimyTank && this.Owner instanceof SelfTank) { 3 UtilityClass.RemoveE(nextObj.occupier.UI, document.getElementById("divMap")); 4 nextObj.occupier.UI = null; 5 var arr = GameLoader.prototype._enimyTanks.removeAt(nextObj.occupier.index); 6 // 重設坦克索引 7 for (var i = 0; i < arr.length; i++) { 8 arr[i].index = i; 9 }10 GameLoader.prototype._enimyTanks = arr;11 nextObj.occupier = null;12 } 複製代碼 這裡有一個重設索引的代碼,大家可能不明白為什麼這麼做。 當我們移除掉一個坦克後,數組的元素個數變了,所以原來的數組索引有可能失效。所以我們只要重設一下,就ok了。