進化アニメーションの実装
今回は後回しにしていた進化アニメーションの作り込みをしていきます。今までもレベルに達すれば進化はしていましたが、その演出はありませんでした。また、ポケモンではBボタンを押すことで進化のキャンセルをすることができます。なので、この辺りも実際のゲームを再現していきましょう。
コントローラーの作成
まずは進化画面用のコントローラーを作成します。
進化画面用コントローラー(/App/Controllers/Evolve/EvolveController.php)
<?php
$root_path = __DIR__.'/../../..';
require_once($root_path.'/App/Controllers/Controller.php');
// 進化画面用コントローラー
class EvolveController extends Controller
{
/**
* @return void
*/
public function __construct()
{
// 親コンストラクタの呼び出し
parent::__construct();
// 引き継ぎ
$this->pokemon = $this->unserializeObject($_SESSION['__data']['pokemon']);
// 分岐処理
$this->branch();
// 親デストラクタの呼び出し
parent::__destruct();
}
/**
* アクションに合わせた分岐
* @return void
*/
private function branch()
{
// 進化処理が終わっていればホーム画面へ移管
if(!$this->pokemon->getEvolveFlg()){
$this->goToHome();
}
switch ($_POST['action'] ?? '') {
/******************************************
* 進化
*/
case 'evolve':
$this->pokemon = $this->pokemon
->evolve();
$this->setMessage($this->pokemon->getMessages());
$this->setResponse($this->pokemon->getResponses());
break;
/******************************************
* 進化キャンセル
*/
case 'cancel':
// 進化フラグをfalseにする
$this->pokemon
->setEvolveFlgFalse();
$_SESSION['__data']['pokemon'] = $this->serializeObject($this->pokemon);
$this->goToHome();
break;
/******************************************
* 進化確認画面(初期)
*/
default:
// 確認メッセージ
$msg_id1 = $this->issueMsgId();
$this->setMessage('・・・おや!? '.$this->pokemon->getNickName().'の様子が・・・!');
$this->setAutoMessage($msg_id1);
$this->setResponse([
'action' => 'evolve'
], $msg_id1);
// 終了メッセージ
$msg_id2 = $this->issueMsgId();
$this->setMessage('あれ・・・? '.$this->pokemon->getNickName().'の変化が止まった!', $msg_id2);
$this->setResponse([
'action' => 'cancel'
], $msg_id2);
break;
}
$this->setEmptyMessage();
}
/**
* ホーム画面へ移管させる処理
* @return void
*/
private function goToHome()
{
$_SESSION['__route'] = 'home';
header("Location: ./", true, 307);
}
}
※ポケモンオブジェクトの引き継ぎもシリアライズ関数を使った引き継ぎに変更しました
進化用のメソッド(evolve)はポケモンクラスに作成済みなので、今回はそのまま利用します。
※処理自体は少ないですが、もし作り込むならサービス内で進化処理を行う方が良いです
コントローラーの分岐は「進化」「キャンセル」「デフォルト(開始時)」の3つに分けています。
次に進化画面を準備しましょう。
進化画面用ヘッド(/Resources/Partials/Layouts/Head/evolve.php)
<?php
require_once($root_path.'/App/Controllers/Evolve/EvolveController.php');
require_once($root_path.'/Resources/Lang/Translation.php');
$controller = new EvolveController();
$responses = $controller->getResponses();
$pokemon = $controller->getPokemon();
$_SESSION['__data']['pokemon'] = $controller->serializeObject($pokemon); # 自ポケモンの情報をセッションに格納
進化画面(/Resources/Pages/Evolve.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Resources/Partials/Layouts/Head/evolve.php');
?>
<!DOCTYPE html>
<html lang="jp" dir="ltr">
<head>
<?php
# metaの読み込み
include($root_path.'/Resources/Partials/Layouts/Head/meta.php');
# cssの読み込み
include($root_path.'/Resources/Partials/Layouts/Head/css.php');
?>
</head>
<body>
<?php
# headerの読み込み
include($root_path.'/Resources/Partials/Layouts/Head/header.php');
?>
<main>
<div class="container">
<section>
<div class="row">
<div class="col-12 text-center mb-5">
<figure class="position-relative d-inline-block">
<img
src="/Assets/img/pokemon/dots/front/<?=$pokemon->getAfterClass()?>.gif"
alt="進化先"
class="bg-white p-5">
<img
id="pokemon-before"
src="/Assets/img/pokemon/dots/front/<?=get_class($pokemon)?>.gif"
alt="<?=$pokemon->getName()?>"
class="position-absolute bg-white p-5"
style="left:0;top:0;">
</figure>
</div>
</div>
</section>
<section>
<div class="row">
<div class="col-12">
<div class="message-box action-message-box border p-3 mb-3">
<?php # メッセージエリア ?>
<?php foreach($controller->getMessages() as $key => list($msg, $status, $auto)): ?>
<?php $class = $key === $controller->getMessageFirstKey() ? 'active' : ''; ?>
<?php $last_class = $key === $controller->getMessageLastKey() ? 'last-message' : ''; ?>
<p class="result-message <?=$class?> <?=$last_class?> <?=$status ?? ''?>"
data-action='<?=$responses[$status]['action'] ?? ''?>'
data-target='<?=$responses[$status]['target'] ?? ''?>'
data-param='<?=$responses[$status]['param'] ?? ''?>'
data-toggle='<?=$responses[$status]['toggle'] ?? ''?>'
data-auto='<?=$auto ?? ''?>'>
<?=$msg?>
</p>
<?php endforeach; ?>
<span class="message-scroll-icon small">【CLICK】</span>
<button type="button" id="cancel-evolve" class="btn btn-danger" style="display:none;">進化させない</button>
</div>
</div>
</div>
</section>
<?php
# お知らせ
include($root_path.'/Resources/Partials/Common/notice.php');
?>
</div>
</main>
<?php # 遠隔操作用隠しフォーム ?>
<form action="" method="post" id="remote-form">
<input type="hidden" name="action" id="remote-form-action">
<?php input_token(); ?>
</form>
<?php
# footerの読み込み
include($root_path.'/Resources/Partials/Layouts/Foot/footer.php');
# モーダルの読み込み
# JSの読み込み
include($root_path.'/Resources/Partials/Layouts/Foot/js.php');
?>
<script src="/Assets/js/Evolve/message.js" type="text/javascript"></script>
</body>
</html>
新しいコントローラーを導入したので、ルーティングに追加しておきましょう。
ルーティング(/Classes/Route.php)
<?php
// ルーティング
class Route
{
/**
* @var string
*/
private $name;
/**
*
* @return void
*/
public function __construct($name, $token)
{
$this->name = $name;
if(
!isset($_POST['__token']) ||
($_POST['__token'] !== $token)
){
$_POST = [];
}
}
/**
* テンプレートパス取得
* @return string
*/
public function template():string
{
switch ($this->name) {
// ホーム画面
case 'home':
$path = '/Resources/Pages/Home.php';
break;
// バトル画面
case 'battle':
$path = '/Resources/Pages/Battle.php';
break;
// 進化画面
case 'evolve':
$path = '/Resources/Pages/Evolve.php';
break;
// デフォルト(初期設定)
default:
$path = '/Resources/Pages/Initial.php';
break;
}
// テンプレートパスを返却
return $path;
}
}
進化のタイミング
では、進化のタイミングについてです。ポケモンではバトル中に進化することは有りません。アニメでは戦闘中に進化するようなこともありますが、ゲームでは戦闘終了後に進化アニメーションが入ります。
また、進化レベルに達していても戦闘不能状態(ひんし)になってしまうと進化することはありません。交代ポケモンがいない現状、進化レベルに達してひんし状態になることはありませんが、こちらもしっかりとチェックを入れていきます。
まず、バトルコントローラーの終了分岐を作成します。
/**
* バトル終了メソッド
*
* @return boolean
*/
private function battleEnd()
{
// ポケモンのランク補正・状態変化・バトルダメージを解除
$this->pokemon
->releaseBattleStatsAll();
// 更新したポケモンオブジェクトをセッションへ格納
$_SESSION['__data']['pokemon'] = $this->serializeObject($this->pokemon);
// セッション破棄
$target = [
'enemy', 'run', 'field',
'before_responses', 'before_messages', 'before_modals'
];
foreach($target as $key){
unset($_SESSION['__data'][$key]);
}
// 進化フラグのチェック
if($this->pokemon->getEvolveFlg()){
// 進化画面へ移管
$_SESSION['__route'] = 'evolve';
}else{
// ホーム画面へ移管
$_SESSION['__route'] = 'home';
}
header("Location: ./", true, 307);
exit;
}
今まではバトル終了メソッド(battleEnd)でホーム画面へのリダイレクト処理を行なっていましたが、もし進化レベルに達していた場合は作成した進化画面へとリダイレクトさせています。
判定用のフラグについては、ポケモンクラスに新しくプロパティとして用意しましょう。
ポケモンクラス(/Classes/Pokemon.php)
/**
* 進化フラグ
* @var boolean
*/
protected $evolve_flg = false;
こちらはコントローラー内の判定で使用するため、getメソッドを作成しています。ですが、進化フラグをのアクセス制限をpublicにしたくありませんので、setメソッドには「setEvolveFlgFalse」というfalseのみをセットできるメソッドを用意しました。
次に、コントローラーから進化を呼び出すため、進化用のevolveメソッドをpublicに書き換えておきましょう。
/**
* 進化
*
* @return Pokemon
*/
public function evolve()
{
if(
$this->evolve_flg
&& class_exists($this->after_class ?? null)
){
// 現在のHPを取得
$before_hp = $this->getStats('HP');
// 進化ポケモンのインスタンスを生成
$pokemon = new $this->after_class($this);
// HPの上昇値分だけ残りHPを加算(ひんし状態を除く)
if(!isset($pokemon->sa['SaFainting'])){
$pokemon->calRemainingHp('add', $pokemon->getStats('HP') - $before_hp);
}
$pokemon->setMessage('おめでとう!'.$this->getNickName().'は'.$pokemon->getName().'に進化した!');
// 進化後のインスタンスを返却
return $pokemon;
}else{
$this->setMessage('このポケモンは進化できません');
return $this;
}
}
今までは経験値取得後にevolveメソッドを呼び出していましたが、ここでは呼び出しをせず、進化判定フラグをtrueにしましょう。
ポケモンクラス用セットトレイト(/App/Traits/Class/Pokemon/ClassPokemonSetTrait.php)
// setExpメソッド内
// 進化判定
if(
isset($levelup) &&
isset($this->evolve_level) &&
$this->evolve_level <= $this->level
){
$this->evolve_flg = true;
}
これで進化レベルに達した時点でフラグをtrueにしています。
キャンセル
もしポケモンを進化させない場合、ホーム画面に戻す必要があります。ただ、PHPポケモンはブラウザで動く関係上、更新やヒストリーバックの対応も必要です。なので、進化終了またはキャンセル処理がされたら進化フラグをfalseに変更してそれらを回避します。
先程作成した進化画面用コントローラー内のキャンセル分岐をみてみましょう。
/******************************************
* 進化キャンセル
*/
case 'cancel':
// 進化フラグをfalseにする
$this->pokemon
->setEvolveFlgFalse();
$_SESSION['__data']['pokemon'] = $this->serializeObject($this->pokemon);
$this->goToHome();
break;
ここで現在のポケモンの進化フラグをfalseにしています。ですが、そのままリダイレクトしても、セッション内のデータの進化フラグはtrueのままなので、再度シリアライズをしてセッションに格納しています。
進化処理の場合は、進化判定フラグを引き継ぎ対象としなければ、初期値でfalseとなっているため、false化の処理は不要です。
これでバックエンド(PHP)の処理は完了です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンは進化演出のバックエンド処理について紹介しました。
PHP側の処理は比較的慣れているのでスムーズに進むのですが、JavaScript(jQuery)の処理は慣れていないため、記述量がこの半分以下だったとしても数倍の時間がかかっています。
1つの言語をしっかり理解しておけば、その応用で他の言語も読み書きはできます。しかし、言語の特徴的な処理はどうにも躓きポイントとなってしまいます。非同期とか非同期とか非同期とか・・・
現在プログラミング学習に取り組んでいる人は、ぜひ参考にしてみてくださいね。