壁技とは
前回実装した「しろいきり」と同じく、初代から実装されたフィールド効果技が存在します。それが「壁技」です。
壁(ポケモンwiki)
壁とは、バトルにおける場の状態の一種、およびその場を形成するわざの総称。わざとしては第一世代から存在するが、場の状態としては第二世代で導入された。
場がこの状態になると、受けるわざのダメージを軽減する効果がある。壁にはいくつか種類があるが、いずれも共通した仕様があることと、わざマシンで習得可能な汎用性が高い技であることから一括りに説明されることが多い。
初代技の中でこの壁技に該当するのは「リフレクター」と「ひかりのかべ」の2つです。フィールド効果技に該当するので、技クラスとフィールドクラスを合わせて作成していきましょう。
リフレクター
リフレクター(ポケモンwiki)
まずはリフレクターから実装していきます。リフレクターは使用することで5ターンの間、物理技を半減させるフィールド効果を味方の場に作り出します。
リフレクター:技(/Classes/Move/MoveReflect.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Move.php');
// リフレクター
class MoveReflect extends Move
{
/**
* 正式名称
* @var string
*/
protected $name = 'リフレクター';
/**
* 説明文
* @var string
*/
protected $description = '5ターンの間、相手の物理技のダメージが半分になる。';
/**
* タイプ
* @var string
*/
protected $type = 'TypePsychic';
/**
* 分類
* @var string(physical:物理|special:特殊|status:変化)
*/
protected $species = 'status';
/**
* 威力
* @var integer
*/
protected $power = null;
/**
* 命中率
* @var integer
*/
protected $accuracy = null;
/**
* 使用回数
* @var integer
*/
protected $pp = 20;
/**
* 優先度
* @var integer
*/
protected $priority = 0;
/**
* フィールド効果
*
* @return array
*/
public function field()
{
return [
'class' => 'FieldReflect',
'turn' => 5,
];
}
}
リフレクター:フィールド(/Classes/Field/FieldReflect.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Field.php');
// リフレクター
class FieldReflect extends Field
{
/**
* 正式名称
* @var string
*/
protected $name = 'リフレクター';
/**
* フィールドセット時のメッセージ
* @var string
*/
protected $set_msg = '::prefixはリフレクターで物理に強くなった';
/**
* 既にフィールドセットされている状態のメッセージ
* @var string
*/
protected $already_msg = 'しかし上手く決まらなかった';
/**
* フィールド解除時のメッセージ
* @var string
*/
protected $release_msg = '::prefixのリフレクターが無くなった';
}
※メッセージの返却方法を状態異常などと同様にstr_replaceで置き換える方法に統一しました。
ひかりのかべ
ひかりのかべ(ポケモンwiki)
物理に対して、特殊攻撃を半減させる技が「ひかりのかべ」です。こちらもリフレクターと同じ要領で技クラスとフィールドクラスを作成していきます。
ひかりのかべ:技(/Classes/Move/MoveLightScreen.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Move.php');
// ひかりのかべ
class MoveLightScreen extends Move
{
/**
* 正式名称
* @var string
*/
protected $name = 'ひかりのかべ';
/**
* 説明文
* @var string
*/
protected $description = '5ターンの間、相手の特殊技のダメージが半分になる。';
/**
* タイプ
* @var string
*/
protected $type = 'TypePsychic';
/**
* 分類
* @var string(physical:物理|special:特殊|status:変化)
*/
protected $species = 'status';
/**
* 威力
* @var integer
*/
protected $power = null;
/**
* 命中率
* @var integer
*/
protected $accuracy = null;
/**
* 使用回数
* @var integer
*/
protected $pp = 30;
/**
* 優先度
* @var integer
*/
protected $priority = 0;
/**
* フィールド効果
*
* @return array
*/
public function field()
{
return [
'class' => 'FieldLightScreen',
'turn' => 5,
];
}
}
ひかりのかべ:フィールド(/Classes/Move/FieldLightScreen.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Field.php');
// ひかりのかべ
class FieldLightScreen extends Field
{
/**
* 正式名称
* @var string
*/
protected $name = 'ひかりのかべ';
/**
* フィールドセット時のメッセージ
* @var string
*/
protected $set_msg = '::prefixはひかりのかべで特殊に強くなった';
/**
* 既にフィールドセットされている状態のメッセージ
* @var string
*/
protected $already_msg = 'しかし上手く決まらなかった';
/**
* フィールド解除時のメッセージ
* @var string
*/
protected $release_msg = '::prefixのひかりのかべが無くなった';
}
ダメージ計算
それでは、作成したフィールド効果をバトル内で使えるように処理を追加していきましょう。
壁技はダメージ計算に影響します。リフレクターであれば物理技を半減する効果を持っているため、攻撃ポケモンが使用してきた技が物理技かどうかを判別して、防御ポケモン側のフィールドにリフレクターが張られていれば半減(0.5倍)の補正値を乗算します。
また、壁補正はタイプ相性などと同じく、その攻撃に対して1度だけ行われるものです。なのでattackメソッド内で補正値の計算を行います。さらに、一撃必殺では補正値の計算が不要になるので、無駄処理を回避するためにも、一撃必殺処理後に追記しておきましょう。
攻撃用トレイト(/App/Traits/Service/Battle/ServiceBattleAttackTrait.php)
/**
* 攻撃
* (攻撃→ダメージ計算→ひんし判定)
*
* @param object $atk_pokemon
* @param object $def_pokemon
* @param object $move
* @return void
*/
protected function attack(object $atk_pokemon, object $def_pokemon, object $move)
{
--省略
// 一撃必殺
if($move->getOneHitKnockoutFlg()){
$def_pokemon->calRemainingHp('death');
// HPバーのアニメーション用レスポンス
$this->setResponse([
'param' => $def_pokemon->getStats('HP'),
'action' => 'hpbar',
'target' => $def_pokemon->getPosition(),
], $this->atk_msg_id);
$this->setMessage('一撃必殺');
return;
}
// 壁補正
$this->checkWall($move, $def_pokemon);
// 技を回数分実行
$times = $move->times();
for($i = 0; $i < $times; $i++){
// 攻撃判定成功時の処理
$this->attackSuccess($atk_pokemon, $def_pokemon, $move);
}
// 連続技はヒット回数のメッセージを返却
if($times > 1){
return $this->setMessage($times.'回当たった');
}
}
--省略
/**
* 壁補正判定
*
* @param Move:object $move
* @param Pokemon:object $def
* @return string
*/
private function checkWall(object $move, object $def)
{
// ダメージ補正(初期値は等倍)
$m = 1;
// 技種類での分岐
switch ($move->getSpecies()) {
// 物理
case 'physical':
// 相手がリフレクター状態であれば半減
if($this->checkField($def->getPosition(), new FieldReflect)){
$m = 0.5;
}
break;
// 特殊
case 'special':
// 相手がひかりのかべ状態であれば半減
if($this->checkField($def->getPosition(), new FieldLightScreen)){
$m = 0.5;
}
break;
}
// プロパティに算出結果を乗算
$this->m *= $m;
}
引数では技オブジェクトと防御ポケモンのオブジェクトを取得しています。取得後は物理技か特殊技かを判定して、それぞれ半減対象のフィールドをチェックしています。もし半減対象となれば、その時点でローカル補正値$mに0.5をセットして、最終で補正値のプロパティに乗算しています。
それでは、壁補正値が反映されているかどうかを確認してみましょう。
壁技使用前
壁技使用後
壁(リフレクター)を張っていない状態でゼニガメから物理攻撃(たいあたり)を受けると、2ダメージでしたが、リフレクター後には同じゼニガメからの攻撃が1ダメージになりました。ダメージ数が少ないので乱数の可能性もありますが、何度かやってみるとその差がプレイ画面上でも確認することができます。
まとめ
いかがだったでしょうか。
今回のPHPポケモンは「壁技」の実装方法をご紹介しました。
リフレクターやひかりのかべは、現在のポケモンでも重宝されている技であり、特に耐久力を補うためには欠かせません。
プログラミング学習に取り組んでいる方や、ゲームづくりに興味がある方は、ぜひ参考にしてみてくださいね。