ゆびをふるとは
今回PHPポケモンで実装する技は「ゆびをふる」です。
ゆびをふる(ポケモンwiki)
「ゆびをふる大会」というゆびをふるのみを使った大会なども開催されているということもあり、ポケモンの技の中でも初代から長く愛されてきた1つです。ですが、他の技とは違って通常の追加効果処理では実装できないため、前回に引き続き特別処理を加えながら実装していきます。
技のランダム選出
ゆびをふるといえば、使用することでランダムで技が選出されるという変化技です。覚えていない技はもちろん、一度も使ったことの無いような技が選出されることもあります。
技の実装方法としては、現在作成されている技クラスをランダムで選出することで、自分の技として使えるようにしていきます。
対象外の技
ランダム選出されるといっても、全技が対象というわけではありません。例えば、ゆびをふるを使って「ゆびをふる」が選出されることはありませんし、前回実装した相手の技をコピーする「オウムがえし」が繰り出されることもありません。
対象外の技(第1世代)は以下の通りです。
オウムがえし、カウンター、へんしん、ものまね、ゆびをふる、わるあがき
では、ゆびをふるの技クラスを作成していきましょう。
ゆびをふる(/Classes/Move/MoveMetronome.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Move.php');
// ゆびをふる
class MoveMetronome extends Move
{
/**
* 正式名称
* @var string
*/
protected $name = 'ゆびをふる';
/**
* 説明文
* @var string
*/
protected $description = 'わざのどれかをランダムで繰り出す。';
/**
* タイプ
* @var string
*/
protected $type = 'TypeNormal';
/**
* 分類
* @var string(physical:物理|special:特殊|status:変化)
*/
protected $species = 'status';
/**
* 威力
* @var integer|null
*/
protected $power = null;
/**
* 命中率
* @var integer
*/
protected $accuracy = null;
/**
* 使用回数
* @var integer|null
*/
protected $pp = 10;
/**
* 対象
* @var string
*/
protected $target = 'friend';
/**
* ゆびをふる 特殊効果
* @return object::Move
*/
public function exMetronome() :object
{
// ブラックリスト
$black_list = [
// ゆびをふる・オウム返し・わるあがき・ものまね・カウンター・へんしん
get_class(), 'MoveMirrorMove', 'MoveStruggle', 'MoveMimic', 'MoveCounter', 'MoveTransform'
];
// 技クラスをランダムで取得
$move_list = glob(__DIR__.'/*.php');
// クラス名部分のみを抽出した配列に変換
$move_list = array_map(function($path){
return preg_replace('/\.php$/', '', basename($path));
}, $move_list);
// ブラックリストに登録されたクラスを弾く
$move_list = array_filter($move_list, function($class) use($black_list){
return !in_array($class, $black_list, true);
});
// リストからランダムにキーを抽出
$key = array_rand($move_list);
// 技クラスを返却
return new $move_list[$key];
}
}
ゆびをふるも、技を書き換える特殊な処理が必要になるので、専用のexMetronomeというメソッドを作成しました。
まず処理の初めに、ブラックリストとして例外技を配列で用意します。次に、既に用意されている技クラスを取得するためにglob関数を使います。
grob(PHP.net)
glob(__DIR__.'/*.php');
引数として、技クラスが格納されているディレクトリのphpファイルをアスタリスクを使って指定しています。返り値は配列で一致したファイルのパスが値として格納されているので、array_mapとpreg_replaceの正規表現を使ってファイル名(拡張子を除く)の配列に変換します。
array_map(function($path){
return preg_replace('/\.php$/', '', basename($path));
}, $move_list);
更に、ブラックリストに登録された技を対象外とするため、array_filterを使って取り除いていきます。
array_filter($move_list, function($class) use($black_list){
return !in_array($class, $black_list, true);
});
これで候補技クラスを格納した配列が出来上がったので、array_randでランダム選出してインスタンス化して返却します。
// リストからランダムにキーを抽出
$key = array_rand($move_list);
// 技クラスを返却
return new $move_list[$key];
これでゆびをふるのランダム選出処理が完成しました。
使用時の特別判定
それでは、攻撃処理の中にゆびをふるの判定を追加しましょう。オウムがえしと同じく技を変化させる処理のため、特別判定を加えつつあばれるとチャージ技が選出された際のループ回避処理も追加します。
攻撃用トレイト(/App/Traits/Service/Battle/ServiceBattleAttackTrait.php)
/**
* 攻撃
* (攻撃→ダメージ計算→ひんし判定)
*
* @param atk_pokemon:object::Pokemon
* @param def_pokemon:object::Pokemon
* @param move:object::Move
* @return object::Move
*/
protected function attack(object $atk_pokemon, object $def_pokemon, object $move) :object
{
// 補正値の初期化
$this->m = 1;
// 行動チェック(状態異常・状態変化)
if(
!$this->checkBeforeSa($atk_pokemon) ||
!$this->checkBeforeSc($atk_pokemon)
){
// 行動失敗
return $move;
}
// 「わるあがき」の確認とPP消費処理
if(!$this->checkEnabledMove($move, $atk_pokemon)){
setMessage($atk_pokemon->getPrefixName().'は出すことのできる技がない');
}
// 「オウムがえし」の特別処理
if(get_class($move) === 'MoveMirrorMove'){
$mirror_move = $this->exMirrorMove($atk_pokemon, $def_pokemon, $move);
if(!$mirror_move){
// 技失敗
setMessage('しかし上手く決まらなかった');
return $move;
}else{
// ミラー技をセット
$move = $mirror_move;
}
}
// 「ゆびをふる」の特別処理
if(get_class($move) === 'MoveMetronome'){
$move = $this->exMetronome($atk_pokemon, $move);
}
// チャージチェック
$charge = $move->charge($atk_pokemon);
if($charge){
// チャージターンなら行動終了
setMessage($charge);
return $move;
}
記述量も増えてきたので、特別処理のexMetronomuメソッドはトレイト分けしました。
攻撃特別処理用トレイト(/App/Traits/Service/Battle/ServiceBattleExTrait.php)
<?php
// 特別処理
trait ServiceBattleExTrait
{
/**
* オウムがえしの特別処理
*
* @param atk:object::Pokemon
* @param def:object::Pokemon
* @param move:object::Move
* @return mixed::Move|false
*/
protected function exMirrorMove(object $atk, object $def, object $move)
{
// チャージ・あばれる技の確認
$wait_move = $this->exGetWaitingMove($atk);
if(is_object($wait_move)){
return $wait_move;
}else{
// 「オウムがえし」の発動メッセージ
setMessage($atk->getPrefixName().'は'.$move->getName().'を使った!');
return $move->exMirrorMove($def, $this->battle_state);
}
}
/**
* ゆびをふるの特別処理
*
* @param atk:object::Pokemon
* @param move:object::Move
* @return object::Move
*/
protected function exMetronome(object $atk, object $move) :object
{
// チャージ・あばれる技の確認
$wait_move = $this->exGetWaitingMove($atk);
if(is_object($wait_move)){
return $wait_move;
}else{
// 「ゆびをふる」の発動メッセージ
setMessage($atk->getPrefixName().'は'.$move->getName().'を使った!');
return $move->exMetronome();
}
}
/**
* 特別処理時の待機技(チャージorあばれる)の取得
*
* @param atk:object::Pokemon
* @return mixed::Move|false
*/
protected function exGetWaitingMove(object $atk)
{
//「チャージ状態」になっているかどうかを確認
$charge = $atk->getChargeMove();
if($charge){
return new $charge;
}
//「あばれる状態」になっているかどうかを確認
$thrash = $atk->getThrashMove();
if($thrash){
return new $thrash;
}
return false;
}
}
ゆびをふるでは、技選出が失敗することは無いので技オブジェクトを返却で統一させています。
では実際にバトルで使用してみましょう。
使用するたびにランダムで技が選出されることが確認できました。これでゆびをふるの実装は完了です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「ゆびをふる」の実装方法をご紹介しました。
ゲームづくりに興味がある人は、ぜひ参考にしてみてくださいね。