オブジェクト指向の有効活用
β版に向けたPHPポケモンの構成見直し、今回は「オブジェクト指向」の役割について、より理解を深めつつ、保守性も良くなるように整えていきます。
機能を持たせる
様々なプロパティを定数や静的変数へ以降していますが、今回は「静的メソッド」の活用範囲を増やしていきます。まず最初に注目したのが「状態異常」についてです。
状態変化も同じくですが、それぞれに「行動前」「行動後」に発症するものがあり、解除条件や発動による行動可不可も異なります。サービスに付属するトレイト内に分岐を作ってそれぞれの処理を噛ませていましたが、本来は「状態異常クラス」そのものに効果を持たせる方が、オブジェクト指向としては正しい役割となります。
一例として、行動前に判定する状態異常に合わせてた静的メソッドを作成していきましょう。
状態異常クラス(/Classes/StatusAilment.php)
/**
* 行動前の状態異常発症
* @param pokemon:object
* @return array
*/
public static function onsetBefore(object $pokemon): array
{
return [
'result' => true,
];
}
親クラスにonsetBeforeという静的メソッドを作成しました。こちらが行動前の状態異常発症用となります。
行動前にこちらのメソッドが必要になるのは「まひ」「ねむり」「こおり」の3状態です。それ以外の状態異常では必要としませんが、共通して呼び出せるように親に基本の状態、必要なものにはそれぞれのクラス内でメソッドを作成し、エラーを回避しています。
では、25%の確率で行動ができなくなる「まひ」から見ていきましょう。
まひクラス(/Classes/Sa/SaParalysis.php)
/**
* 行動前の状態異常発症
* @param pokemon:object
* @return array
*/
public static function onsetBefore(object $pokemon): array
{
// 1/4の確率で行動不能
if(!random_int(0, 3)){
// 行動不能
return [
'result' => false,
'message' => static::getFailedMessage($pokemon->getPrefixName())
];
}else{
// 行動可能
return [
'result' => true,
];
}
}
判定は同じくrandom_intを使って25%の分岐をしています。もし行動不能であれば、配列でresultにfalse、messageに失敗時のメッセージを格納して返却、行動成功時にはresultにtrueをセットして返却しています。
返り値が同じ方が、受け取り側の処理が組みやすいため、今回は「配列」という形式をとりました。
では次に、解除が含まれる「ねむり」について見てみましょう。
ねむりクラス(/Classes/StatusAilment.php)
/**
* 行動前の状態異常発症
* @param pokemon:object
* @return array
*/
public static function onsetBefore(object $pokemon): array
{
// ターンカウントを進める
$pokemon->goSaTurn();
// ターンカウントが残っていれば行動不能
if($pokemon->getSa()){
// 行動不能
return [
'result' => false,
'message' => static::getFailedMessage($pokemon->getPrefixName())
];
}else{
// ねむり解除
return [
'result' => true,
'release' => true,
'message' => static::getRecoveryMessage($pokemon->getPrefixName())
];
}
}
ターンカウントを進め、状態異常を解除、その後行動判定を行なっています。
解除時にはアニメーション(ねむりアイコンを非表示にする)が必要になるため、releaseというキーにtrueを持たせることで呼び出し元へ通知しています。
状態異常の解除アニメーションは、全て同じアクションと引数で行えるため、現状はこれだけでの判定としていますが、パラメーターが変わるものがあれば必要に応じて配列に値を格納、受取先で分岐しましょう。
役割分担
次に、行動前の状態異常発症メソッドを呼び出すトレイト内のメソッドを見てみましょう。
バトルサービス用チェック関係トレイト(/App/Traits/Service/Battle/ServiceBattleCheckTrait.php)
/**
* 攻撃前の状態異常判定
* @param pokemon:object::Pokemon
* @return boolean
*/
protected function checkBeforeSa(object $pokemon): bool
{
$sa = $pokemon->getSa();
if(empty($sa)){
// 状態異常にかかっていない
return true;
}
// アタック前の症状を発火
$result = $sa::onsetBefore($pokemon);
// 解除の有無確認
if($result['release'] ?? false){
$msg_id = response()->issueMsgId();
response()->setResponse([
'action' => 'sa-release',
'target' => $pokemon->getPosition()
], $msg_id);
}
// メッセージがあれば格納
if(isset($result['message'])){
response()->setMessage($result['message'], $msg_id ?? null);
}
// 結果を返却
return $result['result'];
}
状態異常があれば、先程作成した静的メソッド(onsetBefore)を呼び出しています。その後、返り値を確認しながらメッセージやレスポンスを生成、最終的には結果をそのまま返却しました。
ここでのポイントは、メッセージやレスポンスの格納をサービス内で行なっているという点です。
現状、クラス内で行なっているメッセージの格納もありますが、できる限りサービス内またはコントローラー内で管理する方向でまとめています。なぜなら、クラス内で呼び出されることにより、いつどこでどのタイミングで呼び出されているのかがわかりづらく、更には「予期せぬタイミングでメッセージが生成されてしまう」ことに繋がるからです。
技や状態異常、ポケモンなどのクラスでは「そのクラスが持つ効果やクラス内に影響を与える処理」、サービスやコントローラーでは現在のアクションで必要な処理を担えるように、役割分担させることが、オブジェクト指向を上手く活用した開発に繋がります。
では、最後に修正した状態異常が正常に機能しているかどうかを確認してみましょう。
正常に動作していることが確認できました。
この調子で、それぞれの機能についてもクラス管理で移行予定です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「オブジェクト指向の有効活用」の方法として、静的メソッドの使い方をご紹介しました。
流石に100回近くもやっていると、なんとなくの理解だったクラスなども大分活用範囲が増えてきました。
現在プログラミング学習に取り組んでいる方や、ゲームづくりに興味がある人は、ぜひ参考にしてみてくださいね。