ステータスの表示
前回経験値バーのアニメーションとレベルアップ時の動的な変更を実装しましたが、レベルアップ時に表示されるステータスの実装は先送りにしていました。なので今回はそのステータス表示を作成しましょう。
ステータスはメッセージとして返却せずに、小モーダルを起動させるという方法で対応します。
モーダルに合わせたレスポンスの返却
今まではパラメーターを返却して、それに合わせてアニメーションを起動していましたが、今回はモーダルを起動してそこへデータを表示するため、モーダル起動に合わせたパラメータを返却することで対応します。
bootstrap4のモーダルを起動するには、data要素としてtargetとtoggleを指定する必要があります。toggleにはモーダル、targetには対象となるモーダルのIDまたはクラスで指定するのが一般的です。今回はIDで指定できるように、レスポンスを生成しましょう。
ポケモンクラス(/Classes/Pokemon.php)
/**
* レベルアップ処理
*
* @param string|null $msg_id
* @return void
*/
protected function actionLevelUp($msg_id=null)
{
--省略
// メッセージIDを生成
$msg_id1 = $this->issueMsgId();
$msg_id2 = $this->issueMsgId();
// レベルアップアニメーション用レスポンス
$this->setResponse([
'param' => json_encode([
'level' => $this->level,
'remaining_hp' => $this->getRemainingHp(),
'remaining_hp_per' => $this->getRemainingHp('per'),
'max_hp' => $this->getStats('HP'),
]),
'action' => 'levelup',
], $msg_id1);
$this->setAutoMessage($msg_id1);
// レベルアップメッセージ
$this->setMessage($this->getNickName().'のレベルは'.$this->level.'になった!', $msg_id2);
// レスポンスデータをセット
$this->setResponse([
'toggle' => 'modal',
'target' => '#'.$msg_id2.'-modal',
], $msg_id2);
// 現在のレベルで習得できる技があるか確認
$this->checkMove();
}
レベルアップメソッドの中でレスポンスを生成します。toggleにはmodal、targetにはメッセージIDに-modalを付与したIDのモーダルを指定するように格納しています。
targetは別のアクションでも使用していましたが、toggleについては未実装だったので、こちらもあれば付与するようにタグへ追記しておきましょう。
バトル画面(/Resources/Pages/Battle.php)
<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>
</div>
data-toggleの追加以外にも修正ポイントがあるので簡単にまとめておきます。
- 今まではメッセージアクションにmessage-boxを使用していましたが、action-message-boxで起こせるように追記しました。
- message-scroll-iconでマウスイベントが発生しないように、cssで「pointer-events: none;」を指定しました。
- result-messageにモーダル起動アクションが含まれているため、この要素をメッセージボックスいっぱいに広げました。
以下CSSです。
.result-message{
display: none;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding: 1rem;
margin-bottom: 0;
}
モーダル生成値の作成
それでは次にモーダルの生成に必要なパラメーターを用意しましょう。ループ内で生成するのであれば、同じレスポンスに返却して生成することも可能ですが、どこにモーダルが潜んでいるかがわからなくなれば保守性も下がってしまいます。そうならないためにも、モーダルは統一で最下層に生成できるよう、モーダル用のレスポンスを作成します。
レスポンストレイト(/App/Traits/Response.php)
<?php
trait ResponseTrait
{
--省略
/**
* モーダルの格納用
* @var array
*/
private $modals = [];
--省略
/**
* モーダルテータの取得
*
* @return array
*/
public function getModals()
{
return $this->modals;
}
/**
* モーダル用テータの格納
*
* @param array $param
* @param boolean $merge
* @return array
*/
public function setModal(array $param, bool $merge=false)
{
if(empty($param)){
// 空の場合はスキップ
return;
}
if($merge){
// 結合(引き継ぎ)
$this->modals = array_merge($this->modals, $param);
}else{
$this->modals[] = $param;
}
}
/**
* モーダル情報の初期化
*
* @return void
*/
public function resetModal()
{
$this->modals = [];
}
/**
* 全リセット
*
* @return void
*/
public function resetAll()
{
$this->messages = [];
$this->responses = [];
$this->modals = [];
}
}
では、作成したレスポンスメソッドに合わせて、モーダルを作成するために必要なデータを格納していきましょう。
ポケモンクラス(/Classes/Pokemon.php)
/**
* レベルアップ処理
*
* @param string|null $msg_id
* @return void
*/
protected function actionLevelUp($msg_id=null)
{
--省略
// レスポンスデータをセット
$this->setResponse([
'toggle' => 'modal',
'target' => '#'.$msg_id2.'-modal',
], $msg_id2);
// モーダル用のレスポンスをセット
$this->setModal([
'id' => $msg_id2,
'modal' => 'levelup',
'stats' => $this->getStats(),
]);
// 現在のレベルで習得できる技があるか確認
$this->checkMove();
}
モーダルで使用するメッセージID、そのモーダルで使用するテンプレートファイル名(modal)、モーダル内で使うデータ(stats)の3つを格納しました。
レスポンスの上書き対策
今までのレスポンスを使わずに、新しくモーダル用のレスポンスを用意した理由の1つが、データ重複による上書きを回避するためです。
例えば、現在のレスポンスに「modals」というキーでデータを格納していくとしましょう。第3引数で複数データ格納を判別させれば、同一レスポンス内での生成は簡単に制御出来ますが、別インスタンスからデータを引き継ぐ際の一括登録の対応が複雑になってしまいます。そうならないためにも、モーダル用のレスポンスを作成しました。
現段階ではレベルアップ時のステータス表示のみしかモーダルで返却していませんが、技の習得などでもモーダルを使って処理をする必要が出てくるため、それらも考慮すべくレスポンスを分ける方法と選択しました。
※オブジェクトを使って格納する方法もありますが、現在の作り込み状況からすべてを変更するのは困難と判断して断念しました。仕様設計が大切だということ改めて痛感させられた今日このごろです。
最後にモーダルを最下部で生成しましょう。
バトル画面(/Resources/Pages/Battle.php)
<?php foreach($controller->getModals() as $modal): ?>
<?php include($root_path.'/Resources/Partials/Battle/Modals/'.$modal['modal'].'.php'); ?>
<?php endforeach; ?>
レベルアップ時のモーダル(/Resources/Partials/Battle/Modals/levelup.php)
<!-- Modal -->
<div class="modal fade" id="<?=$modal['id']?>-modal" tabindex="-1" role="dialog" aria-labelledby="<?=$modal['id']?>-modal-title" aria-hidden="true" data-keyboard="false" data-backdrop="static">
<div class="modal-dialog modal-dialog-centered modal-sm" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="<?=$modal['id']?>-title">ステータス</h5>
<button type="button" class="close action-message-box" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<table class="table table-bordered table-sm">
<tbody>
<?php foreach($modal['stats'] as $key => $val): ?>
<tr>
<th scope="row" class="w-50"><?=transJp($key)?></th>
<td><?=$val?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm action-message-box" data-dismiss="modal">閉じる</button>
</div>
</div>
</div>
</div>
メッセージアクションとの連携
最後にモーダルとメッセージアクションを連携させましょう。とは言っても、メッセージに対してモーダルを起動するために必要なパラメータを設定しているので、起動については連携ができています。連携させるのはモーダルを閉じる際のアクションです。
まず、先程作成したモーダルに設定したdata要素を見てみましょう。
data-keyboard="false"
data-backdrop="static"
この2つをセットしておくことで、画面外をクリックしてもモーダルを閉じることができません。さらに、閉じるボタンにメッセージアクションを発火させるためのクラス「action-message-box」を付与しています。
これで、ステータスモーダルを閉じるとメッセージアクションが起動し、レベルアップ後の経験値バーのアニメーションへと移行してくれます。
実際の動きを見てみましょう。
レベルアップ後にモーダル起動、閉じると次のメッセージアクションへ移行することができましたね。
これでレベルアップアニメーションの実装は完了です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「レベルアップ時のステータス表示」についてモーダルを使った方法をご紹介しました。
WEBプログラミングでゲームづくりをするには、その特徴を活かしながら作成していく必要があります。中には便利なものもありますが、場合によっては通常のゲーム開発では不要な機能まで実装しなければならない場合もあります。
現在プログラミング学習に取り組んでいる方、または興味を持っている方は、ぜひ参考にしてみてくださいね。