PHPポケモンが第18回にしていよいよバトルの第一歩、野生ポケモンとの遭遇編に突入です。
新しいコントローラーの作成と、バトル画面の作成、そしてポケモンデータの受け渡しなどを中心にご紹介します。
バトル画面の実装
ポケモンのゲームでも、野生ポケモンが現れるとバトル画面へ移管します。今回も同画面のまま制御していくのは流石に大変になってきたので、バトル用の画面を新しく作成します。
バトル画面(/battle.php)
<?php
require_once(__DIR__.'/Classes/Controller/BattleController.php');
require_once(__DIR__.'/Resources/Lang/Translation.php');
session_start();
$controller = new BattleController();
?>
<!DOCTYPE html>
<html lang="jp" dir="ltr">
<head>
<meta charset="utf-8">
<title>PHPポケモン-バトル-</title>
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" href="Resources/Assets/css/style.css">
</head>
<body>
<header>
<div class="container">
<section>
<div class="row">
<div class="col-12">
<h1>PHPポケモン-バトル-</h1>
</div>
</div>
</section>
</div>
</header>
<main>
<div class="container">
</div>
</main>
</body>
</html>
バトルアクションの追加
まずはバトル画面へ移管するためのアクションを作成しましょう。
出力用ファイル(/index.php)
<?php
require_once(__DIR__.'/Classes/Controller.php');
require_once(__DIR__.'/Resources/Lang/Translation.php');
session_start();
$controller = new Controller();
$action_path = '/';
$battle_path = '/battle.php';
?>
--省略
<div class="col-12 col-sm-6 mb-5">
<h2 class="mb-3">メソッドの実行</h2>
<?php if(is_object($controller->pokemon ?? null)): ?>
<?php $_SESSION['pokemon'] = $controller->pokemon->export(); # ポケモンの情報をセッションに格納 ?>
<?php include('Resources/Partials/Forms/change_nickname.php'); # ニックネームの変更?>
<?php include('Resources/Partials/Forms/add_exp.php'); # 経験値の取得 ?>
<?php include('Resources/Partials/Forms/battle.php'); # バトル ?>
<?php include('Resources/Partials/Forms/reset.php'); # リセット ?>
<?php else: ?>
<?php include('Resources/Partials/Forms/select_pokemon.php'); ?>
<?php endif; ?>
</div>
バトルフォーム(/Resources/Partials/Forms/battle.php)
<form action="<?=$battle_path?>" method="post">
<div class="input-group mb-3">
<input class="btn btn-success" type="submit" value="バトル">
</div>
</form>
内容は至って簡単です。新しくフォームを作成し、そのアクション(action)にバトル画面のパスを指定してsubmitしています。
コントローラーの作成
バトル用画面でも記述していますが、バトル用のコントローラー(BattleController)も合わせて作成します。
バトル用コントローラー(/Classes/Controller/ BattleController.php)
<?php
require_once(__DIR__.'/../AutoLoader.php');
require_once(__DIR__.'/../../Traits/ResponseTrait.php');
// コントローラー
class BattleController
{
use ResponseTrait;
/**
* 敵ポケモン格納用
* @var object
*/
public $enemy;
/**
* 自ポケモン格納用
* @var object
*/
public $pokemon;
/**
* @return void
*/
public function __construct()
{
$post = $_POST;
$session = $_SESSION;
// オートローダーの起動
new AutoLoader();
// 自ポケモンの格納
$this->myPokemon($session['pokemon']);
// 敵ポケモンの格納
if(isset($session['enemy'])){
$this->enemyPokemon($session['enemy']);
}else{
$this->enemyPokemon();
}
}
/**
* 自ポケモンの格納
*
* @param array $pokemon
* @return void
*/
private function myPokemon($pokemon)
{
$this->pokemon = new $pokemon['class_name']($pokemon);
}
/**
* 敵ポケモンの格納
*
* @param array|null $pokemon
* @return void
*/
private function enemyPokemon($pokemon=null)
{
if(is_null($pokemon)){
$this->enemy = new Fushigidane();
$this->setMessage('野生の'.$this->enemy->getName().'が現れた!');
}else{
$this->enemy = new $pokemon['class_name']($pokemon);
}
}
}
※今後は、コントローラーも親クラスを継承する仕様に変更予定です
まずはプロパティから見ていきましょう。
/**
* 敵ポケモン格納用
* @var object
*/
public $enemy;
/**
* 自ポケモン格納用
* @var object
*/
public $pokemon;
自ポケモンの格納用には今までと同様にpokemonのプロパティに格納します。次に相手(野生ポケモン)用の格納プロパティとして、enemyを用意します。前回までは1匹のポケモンをやり取りする形式をとっていましたが、今回からは敵を含めた2匹分をやりとりします。ですが、引き継ぎ処理等は基本的に同じなので、そこまで複雑ではありません。
次にコンストラクタを見てみましょう。
/**
* @return void
*/
public function __construct()
{
$post = $_POST;
$session = $_SESSION;
// オートローダーの起動
new AutoLoader();
// 自ポケモンの格納
$this->myPokemon($session['pokemon']);
// 敵ポケモンの格納
if(isset($session['enemy'])){
$this->enemyPokemon($session['enemy']);
}else{
$this->enemyPokemon();
}
}
オートローダーはバトルでも活用するので、初めにインスタンス化しておきます。
次にmyPokemonというメソッドを使って前画面から引き継いだ自ポケモンのデータをプロパティへ格納します。敵ポケモンについては、開始時には新規作成、2ターン名以降では前回画面から引き継ぐ必要があります。
/**
* 自ポケモンの格納
*
* @param array $pokemon
* @return void
*/
private function myPokemon($pokemon)
{
$this->pokemon = new $pokemon['class_name']($pokemon);
}
myPokemonのメソッドでは、引き継ぎのインスタンスを作成しています。
次に敵ポケモン格納用メソッド(enemyPokemon)についてです。
/**
* 敵ポケモンの格納
*
* @param array|null $pokemon
* @return void
*/
private function enemyPokemon($pokemon=null)
{
if(is_null($pokemon)){
$this->enemy = new Fushigidane();
$this->setMessage('野生の'.$this->enemy->getName().'が現れた!');
}else{
$this->enemy = new $pokemon['class_name']($pokemon);
}
}
引数指定がされていなければ、新しいインスタンスを作成します。今回はランダムではなく、フシギダネが野生で出てくるようにクラス名を指定しました。
ポケモンでは、ターンが進んでいくにつれて個体値が変更になることはありません。なので、前画面から敵のデータも引き継がれていれば、自ポケモン同様に引数をいれてインスタンス化をしています。
アクションの作成
次にバトルアクションを作成します。初代ポケモンのバトルシステムでは以下の4アクションがあるので、それを一つずつに再現していきましょう。
- たたかう
- どうぐ
- ポケモン
- にげる
にげる
今回は最も簡単なアクション(にげる)を作成します。にげるというアクションは、バトルから離脱することが目的なので、前の画面(index.php)へ移管させるという処理にします。本来、100%逃げられるということはありませんが、バトル要素が実装されていない現状、その判定は今回無視しておきます。
バトル画面(/battle.php)
<section>
<div class="row">
<div class="col-12 col-sm-6 mb-5">
<h2 class="mb-3">メソッドの実行</h2>
<?php $_SESSION['pokemon'] = $controller->pokemon->export(); # 自ポケモンの情報をセッションに格納 ?>
<?php $_SESSION['enemy'] = $controller->enemy->export(); # 敵ポケモンの情報をセッションに格納 ?>
<?php # 覚えている技 ?>
<table class="table table-bordered table-hover mb-3">
<thead class="thead-light">
<tr>
<th scope="col">使える技</th>
<th scope="col">タイプ</th>
<th scope="col">PP</th>
</tr>
</thead>
<tbody>
<?php foreach($controller->pokemon->getMove() as $move): ?>
<tr>
<th scope="row" class="w-50"><?=$move->getName()?></th>
<td><?=$move->getType()->getName()?></td>
<td><?=$move->getPp()?>/<?=$move->getPp()?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<form action="/" method="post">
<div class="input-group mb-3">
<input type="hidden" name="action" value="retreat">
<input class="btn btn-danger" type="submit" value="逃げる">
</div>
</form>
</div>
<div class="col-12 col-sm-6 mb-5">
<h2 class="mb-3">実行結果</h2>
<div class="result-box border p-3 mb-3">
<?php foreach($controller->getMessages() as list($msg, $status)): ?>
<?php if($status == 'error') $class = 'text-danger'; ?>
<?php if($status == 'success') $class = 'text-success'; ?>
<p class="<?=$class ?? ''?>"><?=$msg?></p>
<?php endforeach; ?>
</div>
</div>
</div>
</section>
技は現状選択できませんが、自ポケモンが正常に引き継がれているかを確認するために用意しています。
逃げるアクションはリセットと同様の形式で、actionキーのhidden要素に対してにげる(retreat)をセットして送るだけのフォームを用意しておきます。フォームのactionについてですが、にげるは前の画面(index.php)へ移管するためのものなので、今回はルートを指定しています。
※もしにげるの判定を実装する場合は、一度battle.phpに対してリクエストを送り、判定の結果成功であればindex.phpへ返却するという処理が必要になります。
それでは、にげるのアクションが選択されたときの判定を、indexのコントローラー(Controller.php)に追加しましょう。
コントローラー(/Classes/Controller.php)
/**
* アクション
*
* @param string $action(method_name)
* @param mixed $param
* @return void
*/
private function action($action, $param)
{
// リセットの処理
if($action === 'reset' || is_null($this->pokemon)){
// 初期化
$this->pokemon = null;
$_POST = [];
$_SESSION = [];
return;
}
// にげるの処理
if($action === 'retreat'){
$this->setMessage('逃げ切れた', 'success');
unset($_SESSION['enemy']);
return;
}
// 呼び出せるメソッドか判別
if(is_callable([$this->pokemon, $action])){
// メソッド実行結果を$resultに格納
$result = $this->pokemon
->$action($param);
switch ($action) {
// 経験値の取得
case 'setExp':
$this->pokemon = $result;
break;
}
// Pokemonクラスに溜まったメッセージを取得
$this->setMessage($this->pokemon->getMessages());
}else{
$this->setMessage('このアクションは使用できません', 'error');
}
}
処理自体は単純です。retreatのアクションが起こった際は別処理で、メッセージをセットしてからセッションに溜まったenemyをunset(削除)しています。これで、自ポケモンは引き継がれた状態でバトルから抜け出すことができます。
以下、敵ポケモンの表示を追加したバトル画面の最終コードです。
バトル画面(/battle.php)
<?php
require_once(__DIR__.'/Classes/Controller/BattleController.php');
require_once(__DIR__.'/Resources/Lang/Translation.php');
session_start();
$controller = new BattleController();
?>
<!DOCTYPE html>
<html lang="jp" dir="ltr">
<head>
<meta charset="utf-8">
<title>PHPポケモン-バトル-</title>
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" href="Resources/Assets/css/style.css">
</head>
<body>
<header>
<div class="container">
<section>
<div class="row">
<div class="col-12">
<h1>PHPポケモン-バトル-</h1>
</div>
</div>
</section>
</div>
</header>
<main>
<div class="container">
<section>
<div class="row">
<?php # 敵ポケモン詳細 ?>
<div class="col-6">
<p><?=$controller->enemy->getName()?> Lv:<?=$controller->enemy->getLevel()?></p>
</div>
<div class="col-6">
<img src="/Resources/Assets/img/pokemon/dots/<?=get_class($controller->enemy)?>.gif" alt="<?=$controller->enemy->getName()?>">
</div>
</div>
</section>
<section>
<div class="row">
<div class="col-12 col-sm-6 mb-5">
<h2 class="mb-3">メソッドの実行</h2>
<?php $_SESSION['pokemon'] = $controller->pokemon->export(); # 自ポケモンの情報をセッションに格納 ?>
<?php $_SESSION['enemy'] = $controller->enemy->export(); # 敵ポケモンの情報をセッションに格納 ?>
<?php # 覚えている技 ?>
<table class="table table-bordered table-hover mb-3">
<thead class="thead-light">
<tr>
<th scope="col">使える技</th>
<th scope="col">タイプ</th>
<th scope="col">PP</th>
</tr>
</thead>
<tbody>
<?php foreach($controller->pokemon->getMove() as $move): ?>
<tr>
<th scope="row" class="w-50"><?=$move->getName()?></th>
<td><?=$move->getType()->getName()?></td>
<td><?=$move->getPp()?>/<?=$move->getPp()?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<form action="/" method="post">
<div class="input-group mb-3">
<input type="hidden" name="action" value="retreat">
<input class="btn btn-danger" type="submit" value="逃げる">
</div>
</form>
</div>
<div class="col-12 col-sm-6 mb-5">
<h2 class="mb-3">実行結果</h2>
<div class="result-box border p-3 mb-3">
<?php foreach($controller->getMessages() as list($msg, $status)): ?>
<?php if($status == 'error') $class = 'text-danger'; ?>
<?php if($status == 'success') $class = 'text-success'; ?>
<p class="<?=$class ?? ''?>"><?=$msg?></p>
<?php endforeach; ?>
</div>
</div>
</div>
</section>
</div>
</main>
</body>
</html>
※複数のポケモンをやり取りすることになったので、画像を追加しました。とはいっても、ドット絵をお借りして表示しているだけです。
あとは、にげるボタンを押して、正常に前の画面へ戻ることができれば完了です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「野生ポケモン遭遇編」をご紹介しました。
画面移管は適切に行えば、その分無駄な判定処理が少なく済みます。ですが、そのためにどのようにデータを渡せば良いかが重要になります。
現在プログラミング学習に取り組んでいる方は、ぜひ参考にしてくださいね。