上一篇文章,我主要是从全局的一个角度,架构了战斗系统,这里我将详细分析具体的实现细节。
这场战斗中,我们需要关注的点:战斗前期准备,单次战斗结算, 技能释放,战斗结算。
战斗前期
在航海类游戏中,参战的首要条件是,你必须是出海状态,然后检测你的参战资格,例如你的生命值不能低于25HP,然后初始化玩家对象,玩家的舰队,玩家的船长等。
具体的流程图如下:
这里需要注意的的有如下几点:
1 验证formHash,同时要把对方的ID加密,这样做都是为了恶意攻击。如果加密和验证,我记住了你的ID,我就不断的可以攻击你。最简单的外挂就是这样做的。
2 初始化舰队的时候,船只的实力是装备过装备的实力。
3 初始化战斗类型的时候,可以使用工厂模式。
战斗技能
技能发动是有某个装配了船长的船发动的,而且是有概率的。当船发动攻击的时候,我们会做出一个判断技能是否发动成功:
// 如果攻船正处于“封印”状态,则不能发动技能
if (Model_Battle_InSkill::isSealed($attackerShip)) {
$skillId = 0;
}
// 否则可以触发攻船的战斗内技能
else {
// 返回0表示触发失败,触发成功则返回技能Id
$skillId = Model_Battle_InSkill::triggerSkill($attacker, $attackerShip);
}
如果技能触发成功了后,我就会实例化这个技能:
// 创建本次技能实例
$skill = Model_Battle_InSkill::factory($skillId);
创建了技能之后,我们就要明白技能到底是如何工作的。
作用对象:我的的舰队,或者敌方的舰队。
效果:
该buff持续回合数
该buff是良性or恶性
影响比例(小于100%表示减少,大于表示增加)
该buff是良性or恶性
影响比例(小于100%表示减少,大于表示增加)
可能有这样的一个技能:
火爆出击: 把对方的任意三艘船的战斗力减少为50%,持续2回合。
技能的数据库设计:
需要的动作:
初始化双方的舰队,便于寻找作用对象
// 设置己方舰队
public function setSelfShips(array $ships)
{
$this->_selfShips = $ships;
}
// 设置对方舰队
public function setEnemyShips(array $ships)
{
$this->_enemyShips = $ships;
}
设置作用对象 技能的作用对象都是存在表中。
// 设置受技能对象(们)
public function setTargetShips()
{
$targetConfig = explode(':', $this->_prop['target_config']);
// 攻击哪方
$targetSide = isset($targetConfig[0]) ? $targetConfig[0] : null;
// 攻击规则
$targetRule = isset($targetConfig[1]) ? $targetConfig[1] : null;
// 攻击范围
$targetNum = isset($targetConfig[2]) ? $targetConfig[2] : null;
// 受技能方的舰队信息
$ships = $targetSide == 'SELF' ? $this->_selfShips : $this->_enemyShips;
switch ($targetRule) {
// 全体
case 'ALL':
$this->_targetShips = $ships;
break;
// 随机定位
case 'RAND':
// 随机定位1艘存活的船
if ($targetNum == 1) {
$this->_targetShips = array(Model_Battle_Util::findRandAliveShip($ships, 1));
}
// 随机定位N艘存活的船
else {
$this->_targetShips = Model_Battle_Util::findRandAliveShip($ships, $targetNum);
}
break;
// 随机定位敌方一艘存活的带有战斗内技能的船
case 'RAND_SKILLED':
$targetShip = Model_Battle_Util::findRandAliveShipWithSkillIn($shipss, 1);
// 如果敌方没有一艘船是有技能的
if (! $targetShip) {
// 那么随机定位敌方一艘存活的船
$targetShip = Model_Battle_Util::findRandAliveShip($ships, 1);
}
$this->_targetShips = array($targetShip);
break;
// 缺省为舰队中存活的第一艘船
default:
$this->_targetShips = array(Model_Battle_Util::findFirstAliveShip($ships));
break;
}
}
设置作用效果
// 设置船只buffs
public function setBuffs()
{
if (! $buffType = $this->_prop['buff_type']) {
return null;
}
switch ($buffType) {
// 影响攻击力
case 'offense':
// 中毒
case 'poisoned':
foreach ($this->getTargetShips() as $ship) {
$ship->buffs[$buffType] = array(
'rounds' => $this->_prop['buff_rounds'], // 该buff持续回合数
'status' => $this->_prop['buff_status'], // 该buff是良性or恶性
'rate' => $this->_prop['buff_effect_rate'], // 影响比例(小于100%表示减少,大于表示增加)
);
}
break;
// 冰冻
case 'frozen':
// 封印
case 'sealed':
foreach ($this->getTargetShips() as $ship) {
$ship->buffs[$buffType] = array(
'rounds' => $this->_prop['buff_rounds'],
'status' => $this->_prop['buff_status'],
);
}
break;
// 清除良性buff
case 'clear_good':
foreach ($this->getTargetShips() as $ship) {
foreach ($ship->buffs as $key => $buff) {
if ($buff['status'] == 'good') {
unset($ship->buffs[$key]);
}
}
}
break;
// 清除恶性buff
case 'clear_bad':
foreach ($this->getTargetShips() as $ship) {
foreach ($ship->buffs as $key => $buff) {
if ($buff['status'] == 'bad') {
unset($ship->buffs[$key]);
}
}
}
break;
}
}
这里,给某艘船只施加技能效果的主要做法是,给船只数组添加新技能的属性,或者删除旧技能属性。
或许到这里,大家明白了什么时候会触发技能,什么时候施加技能效果,但这些效果是如何体现的,我们可能还不知道。
技能的影响是在具体的开火结算类。也就是下面我要说的。
单次战斗结算
什么是战斗结算,就是计算伤害点数,计算这个点数的时候,我们需要考虑如下几点:
1,应用buff并返回处理结果(攻/防/暴/闪/命/抗暴的增减益),这里就应用了技能的影响。
2,应用炮甲相克对守船防御力造成的折扣,这里涉及到相生相克的问题。
结算流程:
public function execute()
{
if (! $this->_attackerShip || ! $this->_defenderShip) {
return null;
}
// 应用buff并返回处理结果(攻/防/暴/闪/命/抗暴的增减益)
$oddsData = Model_Battle_InSkill::applyShipBuff($this->_attackerShip, $this->_defenderShip);
// 应用单次行动前的属性影响
if ($this->_skill) {
$oddsData = Model_Battle_InSkill::applySingleActEffect($oddsData, $this->_skill);
}
// 导出数组变量
extract($oddsData);
// 应用炮甲相克对守船防御力造成的折扣
if ($this->_attackerShip['cannon_id'] && $this->_defenderShip['armor_id']) {
$defenderDefense *= self::getCannonVsArmorEffectRatio($this->_attackerShip['cannon'], $this->_defenderShip['armor']);
}
// 计算本次伤害点数
$damage = $this->_calcDamagePoint($attackerOffense, $defenderDefense, $attackerHitOdds, $defenderAvoidOdds, $attackerCritOdds, $defenderAntiCritOdds);
// 执行扣血
if ($damage > 0) {
self::deductShipHp($this->_defenderShip, $damage);
}
// 记录本次的伤害数值
$this->_logger->setDamage($damage);
}
注意,类的职能的划分很重要,主要extract()函数的使用,妙。下面是具体的应用buff的实现。
/**
* 应用buff生效
*/
public static function applyShipBuff(Model_Ship $attackerShip, Model_Ship $defenderShip)
{
$attackerOffense = $attackerShip['offense']; // 攻船攻击力
$attackerHitOdds = $attackerShip['hit_odds']; // 攻船命中率
$attackerCritOdds = $attackerShip['crit_odds']; // 攻船暴击率
$defenderDefense = $defenderShip['defense']; // 守船防御力
$defenderAvoidOdds = $defenderShip['avoid_odds']; // 守船闪避力
$defenderAntiCritOdds = $defenderShip['anti_crit_odds']; // 守船抗暴击率
// 应用攻船的buff
if (isset($attackerShip->buffs) && $attackerShip->buffs) {
foreach ($attackerShip->buffs as $buffType => $buff) {
// 如果是攻击力增强、减弱状态
if ($buffType == 'offense') {
$attackerOffense = floor($attackerOffense * $buff['rate']);
}
// 如果是命中率增强、减弱状态
elseif ($buffType == 'hit') {
$attackerHitOdds = floor($attackerHitOdds * $buff['rate']);
}
// 如果是暴击率增强、减弱状态
elseif ($buffType == 'crit') {
$attackerCritOdds = floor($attackerCritOdds * $buff['rate']);
}
}
}
// 应用守船的buff
if (isset($defenderShip->buffs) && $defenderShip->buffs) {
foreach ($defenderShip->buffs as $buffType => $buff) {
// 如果是防御力增强、减弱状态
if ($buffType == 'defense') {
$defenderDefense = floor($defenderDefense * $buff['rate']);
}
// 如果是闪避率增强、减弱状态
elseif ($buffType == 'avoid') {
$defenderAvoidOdds = floor($defenderAvoidOdds * $buff['rate']);
}
// 如果是抗暴击率增强、减弱状态
elseif ($buffType == 'anti_crit') {
$defenderAntiCritOdds = floor($defenderAntiCritOdds * $buff['rate']);
}
}
}
return array(
'attackerOffense' => $attackerOffense,
'attackerHitOdds' => $attackerHitOdds,
'attackerCritOdds' => $attackerCritOdds,
'defenderDefense' => $defenderDefense,
'defenderAvoidOdds' => $defenderAvoidOdds,
'defenderAntiCritOdds' => $defenderAntiCritOdds,
);
}
以上,就是战斗过程的具体实现方式了。