《遊戲指令碼的設計與開發》-(戰棋部分)第十章 物理攻擊

來源:互聯網
上載者:User

終於到了攻擊部分了,戰棋遊戲中的攻擊,主要分為物理攻擊和法術攻擊,本章就先從物理攻擊講起。物理攻擊又分為普通攻擊,連擊(雙擊),以及致命攻擊,再複雜一點的還有其他特殊攻擊,比如我的《三國記-亂世群雄》遊戲裡面,張飛的三次攻擊,關羽的多人攻擊等特殊的技能攻擊。我依然從簡單開始,先來看看如何來實現一下普通攻擊,攻擊的過程是,1,A對B進行攻擊。2,B受傷或者檔格。3,如果A在B的攻擊範圍之內,則B會進行一次反擊。4,A受傷或者檔格。

上一章發布之後,隔的時間比較長了,主要是工作忙,沒太多時間整理這些東西,下面我主要介紹一下代碼的核心部分,最後有源碼下載,大家可以對照著文章看一下,方便理解。

攻擊菜單

上一章已經解決了人物移動,接下來當人物移動結束的時候,需要彈出一個攻擊選擇,先看看攻擊菜單的製作。

ffunction LSouSouSMapMenuCtrl(x,y){var self = this;base(self,LSprite,[]);self.addMenu(x,y);}LSouSouSMapMenuCtrl.prototype.addMenu = function(x,y){var self = this;LSouSouObject.sMap.smapClick.removeClickEvent(); var menuLayer = new LSprite();var buttonAtk = new LButtonSample1("攻擊");buttonAtk.backgroundCorl = "red";buttonAtk.x = 15;buttonAtk.y = 15;menuLayer.addChild(buttonAtk);var buttonTactics = new LButtonSample1("策略");buttonTactics.x = 15;buttonTactics.y = buttonAtk.getHeight() + buttonAtk.y;menuLayer.addChild(buttonTactics);var buttonProps = new LButtonSample1("道具");buttonProps.x = 15;buttonProps.y = buttonAtk.getHeight()*2 + buttonAtk.y;menuLayer.addChild(buttonProps);var buttonStop = new LButtonSample1("停止");buttonStop.x = 15;buttonStop.y = buttonAtk.getHeight()*3 + buttonAtk.y;menuLayer.addChild(buttonStop);var buttonCancel = new LButtonSample1("取消");buttonCancel.backgroundCorl = "red";buttonCancel.x = 15;buttonCancel.y = buttonAtk.getHeight()*4 + buttonAtk.y;menuLayer.addChild(buttonCancel);var selfWidth = buttonAtk.getWidth()+30;var selfHeight = buttonAtk.getHeight()*5+30;        var bar = LSouSouObject.getBar(selfWidth,selfHeight);menuLayer.addChild(bar);self.addChild(menuLayer);x += LSouSouObject.sMap.nodeLength;if(x + LSouSouObject.sMap.backLayer.x + selfWidth > LSouSouObject.sMap.SCREEN_WIDTH){x -= (selfWidth + LSouSouObject.sMap.nodeLength); }if(y + LSouSouObject.sMap.backLayer.y + selfHeight > LSouSouObject.sMap.SCREEN_HEIGHT){y = LSouSouObject.sMap.SCREEN_HEIGHT - selfHeight - LSouSouObject.sMap.backLayer.y;}self.x = x + LSouSouObject.sMap.backLayer.x;self.y = y + LSouSouObject.sMap.backLayer.y;buttonAtk.addEventListener(LMouseEvent.MOUSE_UP,self.onclickAtk);buttonCancel.addEventListener(LMouseEvent.MOUSE_UP,self.onclickCancel);};LSouSouSMapMenuCtrl.prototype.onclickAtk = function(e){};LSouSouSMapMenuCtrl.prototype.onclickCancel = function(e){};

下面的一行代碼是上一章中移動結束事件的添加

LSouSouObject.charaSNow.addEventListener(LSouSouEvent.CHARACTER_MOVE_COMPLETE,self.onShowAttackMenu);

修改如下

LSouSouObject.charaSNow.addEventListener(LSouSouEvent.CHARACTER_MOVE_COMPLETE,self.onMoveComplete);

相應的回呼函數onMoveComplete如下。

LSouSouSMap.prototype.onMoveComplete = function(){var self = LSouSouObject.sMap;LSouSouObject.charaSNow.removeEventListener(LSouSouEvent.CHARACTER_MOVE_COMPLETE,self.onMoveComplete);//移動結束if(LSouSouObject.charaSNow.belong == LSouSouObject.BELONG_SELF){self.showCtrlMenu();}else{//敵軍AI,暫略}};

上面代碼,當移動結束的人物所屬是我軍的時候,調用showCtrlMenu函數,如下

LSouSouSMap.prototype.showCtrlMenu = function(){var self = this;self.menu = LSouSouSMapMenu.addSMenu(LSouSouObject.charaSNow.x,LSouSouObject.charaSNow.y,"ctrl");self.menuLayer.addChild(self.menu);};

這樣就添加了攻擊菜單了,效果如下

攻擊範圍

點擊上面的挑選清單中的攻擊按鈕,首先應該確定攻擊範圍。

在arms.json兵種設定檔案中,攻擊範圍主要是由兩個屬性決定,RangeAttack是攻擊的範圍,RangeAttackTarget是攻擊時一次攻擊能攻擊到的人數範圍,比如下面的遊戲中,紅色地區由RangeAttack決定,綠色地區由RangeAttackTarget決定。

首先來顯示攻擊範圍,修改LSouSouSMapMenuCtrl類的onclickAtk函數,如下。

LSouSouSMapMenuCtrl.prototype.onclickAtk = function(e){var i,nodeChild;LSouSouObject.sMap.menu.parent.removeChild(LSouSouObject.sMap.menu);LSouSouObject.sMap.menu = null;var attackRange = LSouSouObject.sMap.attackRange = LSouSouObject.charaSNow.member.getRangeAttack();for(i=0;i<attackRange.length;i++){nodeChild = attackRange[i];LSouSouObject.sMap.attackRangeLayer.graphics.drawRect(1,"#000000",[nodeChild.x*LSouSouObject.sMap.nodeLength + LSouSouObject.charaSNow.x - LSouSouObject.sMap.backLayer.x,nodeChild.y*LSouSouObject.sMap.nodeLength + LSouSouObject.charaSNow.y - LSouSouObject.sMap.backLayer.y,LSouSouObject.sMap.nodeLength,LSouSouObject.sMap.nodeLength],true,"#FF0000");}LSouSouObject.sMap.menu = LSouSouSMapMenu.addSMenu(LSouSouObject.charaSNow.x,LSouSouObject.charaSNow.y,"cancel");LSouSouObject.sMap.menuLayer.addChild(LSouSouObject.sMap.menu);LSouSouObject.sMap.menu.clickEvent = function(event){LSouSouObject.sMap.menu.parent.removeChild(LSouSouObject.sMap.menu);LSouSouObject.sMap.menu = null;LSouSouObject.sMap.attackRangeLayer.graphics.clear();LSouSouObject.sMap.showCtrlMenu();};LSouSouObject.sMap.smapClick.setAtkClickEvent();};

其中的一行

LSouSouSMapMenu.addSMenu(LSouSouObject.charaSNow.x,LSouSouObject.charaSNow.y,"cancel");

是添加一個取消按鈕,用處是當點擊攻擊按鈕之後,可以取消之後重新選擇,在flash版三國記中取消按鈕是被我添加到了右側的按鈕列表,如下

這樣的話,使用者體驗上不太好,所以這次我把取消按鈕添加到攻擊者的位置上,取消按鈕代碼如下。

function LSouSouSMapMenuCancel(x,y){var self = this;base(self,LSprite,[]);self.clickEvent = null;self.addMenu(x,y);}LSouSouSMapMenuCancel.prototype.addMenu = function(x,y){var self = this;var menuLayer = new LSprite();var buttonCancel = new LButtonSample1("×");menuLayer.addChild(buttonCancel);self.addChild(menuLayer);self.x = x + LSouSouObject.sMap.backLayer.x + (LSouSouObject.sMap.nodeLength - buttonCancel.getWidth())*0.5;self.y = y + LSouSouObject.sMap.backLayer.y + (LSouSouObject.sMap.nodeLength - buttonCancel.getHeight())*0.5;buttonCancel.addEventListener(LMouseEvent.MOUSE_UP,self.onclickCancel);};LSouSouSMapMenuCancel.prototype.onclickCancel = function(e){var self = LSouSouObject.sMap.menu;if(self.clickEvent)self.clickEvent();};

運行程式後,效果如下。

攻擊

最後,就是當點擊攻擊的範圍,並且點擊的位置有敵軍存在的話,就開始攻擊,點擊事件如下

LSouSouSMapClick.prototype.onAtkClickUp = function(e){trace("onAtkClickUp is click");var mx = e.selfX;var my = e.selfY;var intX = ((mx - LSouSouObject.sMap.backLayer.x)/LSouSouObject.sMap.nodeLength) >>> 0;var intY = ((my - LSouSouObject.sMap.backLayer.y)/LSouSouObject.sMap.nodeLength) >>> 0;var nodeStr;var nodeArr;var _characterS;var list = LSouSouObject.sMap.enemylist;for(i=0;i _characterS.x + LSouSouObject.sMap.backLayer.x && mx < _characterS.x + LSouSouObject.sMap.backLayer.x + LSouSouObject.sMap.nodeLength && my > _characterS.y + LSouSouObject.sMap.backLayer.y && my < _characterS.y + LSouSouObject.sMap.backLayer.y + LSouSouObject.sMap.nodeLength){LSouSouObject.sMap.menu.parent.removeChild(LSouSouObject.sMap.menu);LSouSouObject.sMap.menu = null;LSouSouObject.sMap.attackRangeLayer.graphics.clear();LSouSouObject.charaSNow.targetCharacter = _characterS;trace("LSouSouObject.charaSNow.targetCharacter="+LSouSouObject.charaSNow.targetCharacter);//攻擊LSouSouObject.charaSNow.setAttackNumber();LSouSouObject.charaSNow.attackCalculate();}}};

上面的代碼,當點擊到敵軍的時候,首先調用LSouSouCharacterS類的setAttackNumber函數,然後調用attackCalculate函數,setAttackNumber函數是決定攻擊次數,比如雙擊等多次攻擊的判定是在這個函數中決定的,本次不考慮多次攻擊,所以setAttackNumber函數中的攻擊次數是預設為1的,如下

LSouSouCharacterS.prototype.setAttackNumber = function(){var self = this;//雙擊判定 暫略self.attackNumber = 1;self.attackIndex = 0;self.targetCharacter.attackIndex = 0;self.targetCharacter.attackNumber = 1;};

attackCalculate函數,包含攻擊之前的特技等判斷,暫時也不考慮,如下

LSouSouCharacterS.prototype.attackCalculate = function(){var self = this;//特技判定 暫略//物理攻擊self.toAttackStart();};

然後調用toAttackStart函數,開始物理攻擊,代碼如下。

LSouSouCharacterS.prototype.toAttackStart = function(){var self = this;trace("self.targetCharacter="+self.targetCharacter);if(!self.targetCharacter)return;if(self.x > self.targetCharacter.x){self.action = LStaticSouSouCharacterS.ATK_LEFT;}else if(self.x < self.targetCharacter.x){self.action = LStaticSouSouCharacterS.ATK_RIGHT;}else if(self.y > self.targetCharacter.y){self.action = LStaticSouSouCharacterS.ATK_UP;}else{self.action = LStaticSouSouCharacterS.ATK_DOWN;}self.action_mode = LStaticSouSouCharacterS.MODE_ATTACK;self.addEventListener(LSouSouEvent.ANIMATION_COMPLETE,self.attackOver);};

attackOver函數是當攻擊結束時調用的,代碼如下。

LSouSouCharacterS.prototype.attackOver = function(){var self = this;var charas,i;var target = self.targetCharacter;var checkBelong = LSouSouObject.sMap.belong_mode;self.removeEventListener(LSouSouEvent.ANIMATION_COMPLETE,self.attackOver);self.attackIndex++;//雙擊或雙擊以上攻擊 暫略//對方沒有混亂,兵力大於0,並且可以反擊if(self.targetCharacter.member.getTroops() > 0 && self.targetCharacter.attackIndex < self.targetCharacter.attackNumber){self.action = LStaticSouSouCharacterS.DOWN + self.direction;for(i=0;i<self.targetArray.length;i++){charas = self.targetArray[i];if(charas.action_mode == LStaticSouSouCharacterS.MODE_STOP){charas.action = LStaticSouSouCharacterS.DOWN + charas.direction;}else{charas.action = LStaticSouSouCharacterS.MOVE_DOWN + charas.direction;}}trace("self.targetCharacter.targetCharacter="+self.targetCharacter.targetCharacter);trace("LSouSouCharacterSAI="+LSouSouCharacterSAI.atAttackRect(self.targetCharacter,self.locationX(),self.locationY()));if(self.targetCharacter.targetCharacter && LSouSouCharacterSAI.atAttackRect(self.targetCharacter,self.locationX(),self.locationY())){self.targetCharacter.attackCalculate();}else{self.action_mode = LStaticSouSouCharacterS.MODE_STOP;self.targetCharacter.targetCharacter = null;self.targetCharacter = null;}}else{for(i=0;i<self.targetArray.length;i++){charas = self.targetArray[i];if(charas.action_mode == LStaticSouSouCharacterS.MODE_STOP){charas.action = LStaticSouSouCharacterS.DOWN + charas.direction;}else{charas.action = LStaticSouSouCharacterS.MOVE_DOWN + charas.direction;}}if(self.belong == LSouSouObject.charaSNow.belong){self.action_mode = LStaticSouSouCharacterS.MODE_STOP;self.action = LStaticSouSouCharacterS.DOWN + this.direction;self.targetCharacter.targetCharacter = null;self.targetCharacter = null;}else{self.action = LStaticSouSouCharacterS.MOVE_DOWN + this.direction;self.targetCharacter.action = LStaticSouSouCharacterS.DOWN + self.targetCharacter.direction;self.targetCharacter.action_mode = LStaticSouSouCharacterS.MODE_STOP;self.targetCharacter.targetCharacter = null;self.targetCharacter = null;}}};

上面代碼中,有攻擊者還是反擊者等判斷,toAttackStart和attackOver函數,只是攻擊開始和攻擊結束的處理,至於攻擊過程,掉血還是檔格等,是在攻擊動作的第三個動作時開始處理的,LSouSouCharacterS的貞函數中有下面的代碼。

if(self.action_mode == LStaticSouSouCharacterS.MODE_ATTACK){self.toAttackTargets();}

就是說當人物處在攻擊動作時,調用toAttackTargets函數,相關代碼如下。

LSouSouCharacterS.prototype.toAttackTargets = function(){var self = this,charas,_charalist,i;if(!self.targetCharacter)return;if(self.actionIndex == 2){_charalist = {};if(self.belong == LSouSouObject.BELONG_SELF || self.belong == LSouSouObject.BELONG_FRIEND){for(i=0;i<LSouSouObject.sMap.enemylist.length;i++){charas = LSouSouObject.sMap.enemylist[i];if(!charas.visible)continue;_charalist[charas.locationX() + "," + charas.locationY()] = charas;}}else{for(i=0;i<LSouSouObject.sMap.ourlist.length;i++){charas = LSouSouObject.sMap.ourlist[i];if(!charas.visible)continue;_charalist[charas.locationX() + "," + charas.locationY()] = charas;}for(i=0;i<LSouSouObject.sMap.friendlist.length;i++){charas = LSouSouObject.sMap.friendlist[i];if(!charas.visible)continue;_charalist[charas.locationX() + "," + charas.locationY()] = charas;}}self.targetArray = [];var node,nodeArr,rangeAttackTarget = self.member.getRangeAttackTarget();for(i=0;i= charas.member.getTroops()){hertValue = charas.member.getTroops();//擷取經驗值計算 暫略}//特技修正 暫略//減HP 暫略charas.action = LStaticSouSouCharacterS.HERT;//減HP顯示 var numberShow = new LSouSouSMapNumber(-hertValue);numberShow.x = charas.x + (charas.getWidth() - numberShow.getWidth())*0.5;numberShow.y = charas.y + (charas.getHeight() - numberShow.getHeight())*0.5;LSouSouObject.sMap.charaLayer.addChild(numberShow);}else{//檔格if(charas.member.getIndex() == self.targetCharacter.member.getIndex()){charas.targetCharacter = self;}if(self.x > charas.x){charas.action = LStaticSouSouCharacterS.BLOCK_RIGHT;}else if(self.x < charas.x){charas.action = LStaticSouSouCharacterS.BLOCK_LEFT;}else if(self.y > charas.y){charas.action = LStaticSouSouCharacterS.BLOCK_DOWN;}else{charas.action = LStaticSouSouCharacterS.BLOCK_UP;}}//升級判定 暫略}

下面是攻擊效果

測試連接如下

http://lufylegend.com/demo/test/lsharp/11/game/index.html

以上,本章就先講這麼多了,下一章會講一下我方,敵方和友方回合之間的切換,以及敵軍和友軍方面簡單的攻擊AI

本章為止的源碼如下,不包含lufylegend.js引擎源碼,請自己到官網下載

http://lufylegend.com/demo/test/lsharp/11/11.rar

※源碼運行說明:需要伺服器支援,詳細請看本系列文章《序》和《第一章》

《遊戲指令碼的設計與開發》系列文章目錄

http://blog.csdn.net/lufy_legend/article/details/8888787

本章就講到這裡,歡迎繼續關注我的部落格

轉載請註明:轉自lufy_legend的部落格http://blog.csdn.net/lufy_legend

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.