卡牌遊戲戰鬥系統的設計和實現(二)

2021-08-27 14:24:32 字數 4160 閱讀 5241

在一篇文章中,我更多的是從遊戲理論的角度,討論了戰鬥的系統的設計。這篇文章中,我將從程式的角度,以一款航海類遊戲為例,實現戰鬥系統。

在航海類遊戲中,戰鬥角色是出海的船隻,一次出海的船隻的數量有限定,船隻可以裝配火炮,護甲,船帆等裝備,船隻還可以通過裝配船長來獲取技能。技能的發動是有概率的。戰鬥規則是,在20個回合內,如果把對方所有的船隻擊沉,即贏得戰鬥勝利,否則未平局。

戰鬥流程大致是這樣:

這個開炮的具體的演算法,我會在後面詳細的貼出**。

當我們了解了戰鬥的大致情況,並把所有的準備工作做好之後 (選擇了參戰的船隻, 船隻搭配了裝備,選擇了船長),還需要考慮的事情有如下幾點:

對手:在航海類遊戲中,對手有幾種:常規玩家,常規npc, 世界boss,海盜等。不同的對手有某些細微的差別,例如,和玩家對戰的時候,需要檢測玩家的參戰條件,和npc對戰的時候不需要。

技能:技能的型別可能有多種,每一種技能都需要考慮到技能的釋放物件,技能的影響,判斷技能是否發動成功等。

戰鬥的核心行為:設定攻擊者,防禦者,執行傷害程式等。

戰鬥的輔助操作:尋找艦隊中目前存活的第一艘船,獲取艦隊中現在還存活船隻的數目等。

戰鬥獎賞:處理每次戰鬥的獎賞。

戰鬥結算:不同的對手,結算的方式不同,最後提示的資訊也不同。

單次戰鬥記錄:需要記錄戰鬥的資訊,便於前端解析這些資訊,呈現戰鬥動畫

戰鬥觀察員:記錄整場戰鬥的資訊,便於戰鬥的回放。

針對以上的需要考慮的事情,我們可以做出多個類,每個類都有特定的職責,實現這些類中方法的思維過程就是把乙個複雜的戰鬥動作拆分成各種小動作。這是一種組合類的設計方式。由於這個類圖畫的過於大,無法貼圖,只有做出鏈結。

戰鬥系統類圖

在戰鬥模型父類裡面,主要實現的戰鬥的初始化工作和戰鬥的具體實現流程。

/**

* 戰鬥進行(外觀模式)

** @return const

*/public function process()

// 建立戰鬥記錄器

$this->_recorder = new model_battle_recorder($this->_self, $this->_enemy);

// 船隻初始化

$this->_initships();

// 船長初始化

$this->_initcaptains();

// 戰鬥進行

$this->_result = $this->_process();

// 通知記錄器記錄 戰鬥結果

$this->_recorder->setresult($this->_result);

// 預設顯示「再次攻擊」按鈕

$this->_recorder->setdata('isallowcombatagain', true);

// 新增一場戰鬥記錄

$this->_battleid = $this->_recorder->create();

return $this->_result;

}

這裡最最要的方法當然是_process()了,它是戰鬥流程的入口。根據以上我畫出來的戰鬥流程圖,這個函式需要做的事情有如下幾點:

1,如何確定回合制度。

2,如何雙方的船交替**權。

3,如何找到該**的船隻,並找到它的攻擊物件。

4,什麼時候對艦隊做出整理,剔除沉沒的船隻。

5,單次戰鬥的結算,如扣血,技能發動。

6,怎樣判定對方所有的船隻都沉沒了。

/**

* 戰鬥進行

** @return const model_battle_vs_abstract::win/lose/draw

*/protected function _process()

// 執行攻擊流程

$this->__attackprocess($round, $this->_selfships[$shipno], 'self');

}// 敵船攻擊我船

} elseif ($curfireturn == 'enemy')

// 執行攻擊流程

$this->__attackprocess($round, $this->_enemyships[$shipno], 'enemy');}}

// 下一次**權交給對方

$curfireturn = $curfireturn == 'self' ? 'enemy' : 'self';}}

}// 雙方戰平:n回合內仍未見勝負

return self::draw;

}

至於交替**權,我們這裡做了乙個好的思維方式是,把**權做成乙個變數,並迴圈賦值。

如何找到**的船隻,我們的做法是把艦隊裡面的船編號,從0-maxshipamount, 迴圈這些船隻,根據編號就可以找到要**的船隻。這裡或許你有個問題是,比如,我第一艘船**,把你的第一艘船擊沉了,那麼,該你開會的時候,你的第一艘船上沒有船隻了,按照我程式上面寫的,如果根據編號找不到船,那麼**權又交給他對方,這樣,又該我**了。其實這樣做也可以,但是我們不是這樣做的,我們的做法是,如果我擊沉了你的0號位上的船,那麼你的1號位的船自動變為0號位上的。 要實現這樣的功能,需要,在執行**之後,再一次整理船隻。

關於尋找攻擊物件,就是找對方第一艘存活的船隻,每次攻擊的時候,實際上都是攻擊0號位的船,這裡大家或許又有乙個疑問,既然每次都是攻擊0號位置上的船隻,那麼1號位置的船誰來攻擊,大家別忘了重整船隻後,1號位置會補充到2號位置上去的。

具體的****如下:

/**

* 進一步細化的攻擊流程(可供雙方呼叫)

** @param int $round 第幾回合

* @param model_ship $attackership 攻船例項

* @param string $attackerside self/enemy

* @return void

*/protected function __attackprocess($round, model_ship $attackership, $attackerside)

// 在攻擊前,攻船是否因為dot而沉沒

$attackershipissank = false;

// 攻方資訊

$attacker = $this->;

// 設定本次攻擊的攻船資訊

$logger->setround($round)

->setattackership($attackership)

->setattackeruid($attacker['uid']);

// 守方是誰

$defenderside = $attackerside == 'self' ? 'enemy' : 'self';

// 攻防雙方艦隊陣列

$attackerships = model_battle_util::filtersankships($this->);

$defenderships = model_battle_util::filtersankships($this->);

// 如果攻船正處於「封印」狀態,則不能發動技能

if (model_battle_inskill::issealed($attackership))

// 否則可以觸發攻船的戰鬥內技能

else

// 普通攻擊

if ($skillid < 1) else

}// 設定船隻buffs

$skill->setbuffs();

// 通知記錄器記錄技能相關資訊

$logger->setskill($skill);

// 記錄受技能方(們)

$logger->settargetships($targetships);

}// 通知戰場觀察員增加本條**記錄

$this->_recorder->add($round, $logger->build());

}

請注意,這裡的攻擊物件永遠是第一艘船隻。

開戰之前,也要重整艦隊,理由上面我已經說了。

這個函式會依賴很對類,戰鬥助手類,戰鬥技能類等。這裡我們可以參考的乙個設計思維是,多用組合,少用繼承。這樣我們可以便於擴充套件和修改,缺點是可能類的數量為增加。

外幣卡收單系統的設計和實現

隨著我國對外交往的不斷擴大,到我國旅遊和從事商務活動的外籍人士將越來越多,這對我國的銀行卡受理環境提出了更高的要求。另外,只有改善外幣卡受理環境,積極參與國際業務,才能積累豐富的國際金融業務經驗,進一步提高金融服務水平。因此,商業銀行提高對外幣卡的受理能力變得愈加重要,開發 建設功能強大的外幣卡收單...

外幣卡收單系統的設計和實現

隨著我國對外交往的不斷擴大,到我國旅遊和從事商務活動的外籍人士將越來越多,這對我國的銀行卡受理環境提出了更高的要求。另外,只有改善外幣卡受理環境,積極參與國際業務,才能積累豐富的國際金融業務經驗,進一步提高金融服務水平。因此,商業銀行提高對外幣卡的受理能力變得愈加重要,開發 建設功能強大的外幣卡收單...

Unity3D 卡牌遊戲中有關卡牌類的製作

需求製作 流程一些問題 卡牌效果的實現 還沒學到設計模式,所以自己和同學搗鼓了乙個,請各位大神多多指教!製作一款卡牌遊戲最核心的地方就是卡牌,遊戲中有生成卡牌,獲得卡牌,銷毀卡牌,檢視卡牌,打出卡牌,卡牌音效等幾大功能,但是最核心的可以分成三個 卡牌的生成與銷毀,卡牌的特效,卡牌的檢視,下面我們就遵...