プログラミング

PHPポケモン「バトルシステム編 〜バトル終了判定〜」28

JavaScript jQuery PHP PHPポケモン ポケモン
PHPポケモン「バトルシステム編 〜バトル終了判定〜」28

バトル終了判定

今回はバトル終了判定を実装しましょう。今までは「にげる」による戦闘離脱のみで、ひんし状態でも殴り合うことが出来たので、それを解消するためにも戦闘結果による判定を導入します。

 

ひんし状態の監視

まずは「ひんし」の監視です。現在は交代ポケモンどちらか一方がひんし状態になれば、その時点でバトルが終了します。なので、攻撃→ダメージ計算→ひんし判定の流れを1セットとして処理を行い、その結果がtrue(相手をひんし状態にした)であれば処理を終了するという流れを作成します。

 

バトルコントローラー(/Classes/Controller/BattleController.php
/**
* たたかう
*/
case 'fight':
// 自ポケモンの技をインスタンス化
$p_move = $this->getInstance($param);
// 行動順の判定
if($this->checkFirstMove($p_move, $e_move)){
    // 先行
    // 自ポケモンの攻撃
    $e_fainting = $this->actionFightToFainting($this->pokemon, $this->enemy, $p_move);
    if($e_fainting){
        // 相手をひんし状態にした
        break;
    }
    // 敵ポケモンの攻撃
    $p_fainting = $this->actionFightToFainting($this->enemy, $this->pokemon, $e_move);
    if($p_fainting){
        // 味方がひんし状態になった
        break;
    }
}else{
    // 後攻
    // 敵ポケモンの攻撃
    $p_fainting = $this->actionFightToFainting($this->enemy, $this->pokemon, $e_move);
    if($p_fainting){
        // 味方がひんし状態になった
        break;
    }
    // 自ポケモンの攻撃
    $e_fainting = $this->actionFightToFainting($this->pokemon, $this->enemy, $p_move);
    if($e_fainting){
        // 相手をひんし状態にした
        break;
    }
}
$this->setMessage('行動を選択してください');
break;

 

攻撃からの一連の流れをactionFightToFaintingというメソッドにまとめました。

 

バトルコントローラー(/Classes/Controller/BattleController.php
/**
* 攻撃→ダメージ計算→ひんし判定
*
* @param object $atk
* @param object $def
* @param object $move
* @return boolean
*/
private function actionFightToFainting($atk, $def, $move)
{
    // 攻撃処理
    $result['damage'] = $this->attack($atk, $def, $move);
    // ダメージ計算
    $def->calRemainingHp('sub', $result['damage']);
    // ひんしチェック
    if($this->checkFainting($def)){
        // 倒した
        return true;
    }else{
        // 倒せていない
        return false;
    }
}

 

引数に合わせて行動を行い、その結果をtruefalseで返却します。trueを受け取ればそのタイミングで処理を終了させるため、fightの分岐でbreakを行います。これで戦闘不能になったのに相手に攻撃をしてしまうという流れを回避することができます。

 

次にactionFightToFaintingメソッド内で呼び出しているcheckFaintingのメソッドについてです。こちらで防御側のポケモンがひんしかどうかを判定します。check関係のメソッドが多くなってきたので、まとめてトレイトに格納しましょう。

 

Check格納トレイト(/Traits/Battle/CheckTrait.php
<?php
// チェック関係格納トレイト
trait CheckTrait
{
 
    /**
    * にげる判定
    * F = (A × 128 / B) + 30 × C
    * Fを256で割った値 → 逃走成功率
    * @var A 味方ポケモンのすばやさ(ランク補正有り)
    * @var B 相手ポケモンのすばやさ(ランク補正無し)
    * @var C 逃走を試みた回数
    * @return boolean
    */
    protected function checkRun()
    {
        // 味方の素早さを取得(ランク補正有り)
        $a = $this->pokemon
        ->getStats('Speed', true);
        // 相手の素早さを取得(ランク補正無し)
        $b = $this->enemy
        ->getStats('Speed');
        // 逃走を試みた回数
        $c = $this->run;
        // 計算式への当てはめ
        $f = ($a * 128 / $b) + 30 * $c;
        // 確率計算
        if(round($f / 256, 2) * 100 >= mt_rand(0, 100)){
            return true;    # 逃走成功
        }else{
            return false;   # 逃走失敗
        }
    }
 
    /**
    * 先手の判定
    *
    * @param object 自ポケモンの技 $p_move
    * @param object 敵ポケモンの技 $e_move
    * @return boolean (pokemon > enemy):true (pokemon < enemy):false
    */
    protected function checkFirstMove($p_move, $e_move)
    {
        /**
        * 優先度の比較
        */
        // 判定
        if($p_move->getPriority() > $e_move->getPriority()){
            // 優先度が高い
            return true;
        }elseif($p_move->getPriority() < $e_move->getPriority()){
            // 優先度が低い
            return false;
        }
        /**
        * すばやさの比較
        */
        // 自ポケモンの素早さ(補正あり実数値)
        $p_speed = $this->pokemon
        ->getStats('Speed', true);
        // 敵ポケモンの素早さ(補正あり実数値)
        $e_speed = $this->enemy
        ->getStats('Speed', true);
        // 判定
        if($p_speed > $e_speed){
            // 素早さが上回っている
            return true;
        }elseif($p_speed < $e_speed){
            // 素早さが下回っている
            return false;
        }elseif($p_speed === $e_speed){
            // 同速(50%の乱数)
            if(random_int(0, 1)){
                return true;
            }else{
                return false;
            }
        }
    }
 
    /**
    * ひんし判定
    *
    * @param object $pokemon
    * @return boolean
    */
    protected function checkFainting($pokemon)
    {
        if($pokemon->getSa() === 'SaFainting'){
            // ひんし状態
            $this->setMessage($pokemon->getPrefixName().'は倒れた');
            if($pokemon->getPosition() === 'friend'){
                // 味方がひんし状態になった
                $this->setMessage('目の前が真っ暗になった');
            }else{
                // 相手をひんし状態にした
                // 経験値取得
                $this->setMessage('経験値をゲットした');
            }
            // バトル終了判定用メッセージの格納
            $this->setMessage(' ', 'battle-end');
            return true;
        }else{
            // ひんし状態ではない
            return false;
        }
    }

}

 

それではひんし判定の処理について見ていきましょう。

/**
* ひんし判定
*
* @param object $pokemon
* @return boolean
*/
protected function checkFainting($pokemon)
{
    if($pokemon->getSa() === 'SaFainting'){
        // ひんし状態
        $this->setMessage($pokemon->getPrefixName().'は倒れた');
        if($pokemon->getPosition() === 'friend'){
            // 味方がひんし状態になった
            $this->setMessage('目の前が真っ暗になった');
        }else{
            // 相手をひんし状態にした
            // 経験値取得
            $this->setMessage('経験値をゲットした');
        }
        // バトル終了判定用メッセージの格納
        $this->setMessage(' ', 'battle-end');
        return true;
    }else{
        // ひんし状態ではない
        return false;
    }
}

 

引数でチェックするポケモンを受け取り、その状態異常の状態からひんし状態かどうかを判別します。もし味方がひんし状態であれば「目の前が真っ暗になった」、相手がひんし状態であれば「経験値をゲットした」といったメッセージを返却しています。

※経験値計算処理は今回作成しません

 

どちらかがひんし状態になってすぐにバトル終了(画面移管)をするわけにはいきません。なので、バトルが終了したということをフロント側で受け取れるように空(空白が必要)メッセージにバトル終了を判定するためのパラメーターとしてbattle-endをセットして返却しておきます。

  

バトル終了処理

 バトル終了処理は、前回実装したjQueryのメッセージアクションを活用します。まずはメッセージの出力部分から修正していきましょう。

 

バトル画面(/battle.php
<div class="message-box border p-3 mb-3">
    <?php foreach($controller->getMessages() as $key => list($msg, $status)): ?>
        <?php $class = $key === $controller->getMessageFirstKey() ? 'active' : ''; ?>
        <?php $last_class = $key === $controller->getMessageLastKey() ? 'last-message' : ''; ?>
        <p class="result-message <?=$class?> <?=$last_class?> <?=$status ?? ''?>"><?=$msg?></p>
    <?php endforeach; ?>
    <span class="message-scroll-icon">▼</span>
</div>

 

ステータスをクラス名に書き出す仕様に変更しました。これでjQueryのでhasClassを使って判定することができます。前回idに格納していたlast-messageもクラスに変更しています。

※idにする必要性を感じなかったためです

  

リモートフォームの活用

bodyの最下部にjsでリモート操作する用の隠しフォームを用意しましょう。

<?php # 遠隔操作用隠しフォーム ?>
<form action="" method="post" id="remote-form">
    <input type="hidden" name="action" id="remote-form-action">
</form>

 

それではjsファイルにバトル終了判定を追記しましょう。

 

メッセージ用js/Resources/Assets/js/Battle/message.js
/**
* 画面読み込み時の関数
* @function ready
* @return void
**/
var startInit = function(){
    // 現在のメッセージ
    var now = $('.result-message.active');
    if((now.length === 0) || now.hasClass('last-message')){
        doLastMsg();
        return;
    }
    doNotLastMsg();
}
 
/**
* メッセージボックスクリック時の関数
* @function click
* @return void
**/
var clickMsgBoxInit = function(){
    $('.message-box').click(function(){
        // 現在のメッセージ
        var now = $('.result-message.active');
        // 最終メッセージかどうか確認
        if((now.length === 0) || now.hasClass('last-message')){
            doLastMsg();
            return;
        }
        // 現在のメッセージのactiveを解除
        now.removeClass('active');
        // 次のメッセージにactiveを付与
        var next = now.next();
        next.addClass('active');
        /**
        * メッセージのステータスに合わせた分岐
        **/
        // バトル終了
        if(next.hasClass('battle-end')){
            $('#remote-form-action').val('end');
            return $('#remote-form').submit();
        }
        // 最終メッセージ
        if(next.hasClass('last-message')){
            doLastMsg();
            return;
        }
        // どれにも該当しない
        doNotLastMsg();
    });
}

 

last-messageの判定をhasClassに変更し、その判定の前にバトル終了判定をするためbattle-endの分岐を追加しました。

もしbattle-endのクラスが付与されているメッセージに進んだら、先程作成したリモート操作用フォームのinput actionendをセットしてsubmit(送信)してくれるという仕組みです。

 

PHPポケモンという名称ですが、この辺りをPHPだけで再現するのは非常に手間なのでガッツリjsjQuery)だよりです。縛り開発はDBだけで十分です。

 

最後にendアクションの分岐をコントローラーに追加しましょう。バトル終了処理はポケモンのインスタンス化など一連の流れがすべて不要になるので、コンストラクタの最初に記述します。

 

バトルコントローラー(/Classes/Controller/BattleController.php
/**
* @return void
*/
public function __construct()
{
    // バトル終了
    if(isset($_POST['action']) && ($_POST['action'] === 'end')){
        $this->endBattle();
    }
    // 親コンストラクタの呼び出し
    parent::__construct();
    // 自ポケモンの格納
    $this->myPokemon($_SESSION['pokemon']);
    // 敵ポケモンの格納
    if(isset($_SESSION['enemy'])){
        $this->enemyPokemon($_SESSION['enemy']);
    }else{
        $this->enemyPokemon();
    }
    // ランク(バトルステータス)の引き継ぎ
    if(isset($_SESSION['rank'])){
        $this->pokemon
        ->setRank($_SESSION['rank']['pokemon']);
        $this->enemy
        ->setRank($_SESSION['rank']['enemy']);
    }
    // にげるの実行回数を引き継ぎ
    if(isset($_SESSION['run'])){
        $this->run = $_SESSION['run'];
    }
    // アクションが選択された
    if(isset($_POST['action'])){
        // アクションメソッドの実行
        $this->action(htmlspecialchars($_POST['action']), htmlspecialchars($_POST['param'] ?? null));
    }
 
}
 
-- 省略
 
/**
* バトル終了
*
* @return void
*/
private function endBattle()
{
    unset($_SESSION['enemy']);
    unset($_SESSION['rank']);
    unset($_SESSION['run']);
    header("Location: ./home.php", true, 307);
    exit;
}

 

ホームコントローラーにも、endアクションで移管してきた際の処理を追加しておきましょう。

ホームコントローラー(/Classes/Controller/HomeController.php
/**
* アクション
*
* @param string $action(method_name)
* @param mixed $param
* @return void
*/
private function action($action, $param)
{
    // リセットの処理
    if($action === 'reset' || is_null($this->pokemon)){
        header("Location: ./index.php", true, 307) ;
        exit;
    }
    // にげるの処理
    if($action === 'run'){
        $this->setMessage('上手く逃げ切れた', 'success');
        return;
    }
    // バトル終了
    if($action === 'end'){
        if($this->pokemon->getRemainingHp() <= 0){
            // ひんし状態ならHPを全回復させる
            $this->pokemon
            ->calRemainingHp('reset');
        }
        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');
    }
}

 

ひんし状態のままでは困るので、にげる判定で使用していた全回復処理を移し替えました。実際にバトルで動きを確認してみましょう。

 

 

 

 

 

無事バトルを終了することができました。あとは経験値の処理を作成し、特殊な技の判定を追加すればポケモンのバトルを成立させることができます。

  

まとめ

いかがだったでしょうか。

今回のPHPポケモンは「バトル終了判定」の実装方法についてご紹介しました。

これでバトル一連の流れが完成したことになります。大分遊べるレベルになったのではないでしょうか。

ゲームづくりに興味がある人、現在プログラミング学習に取り組んでいる方は、ぜひ参考にしてみてくださいね。

 

注目の記事

たった10分!?読むだけでプログラミングが上達する3原則
プログラミング
jQuery,プログラミング学習,初心者
たった10分!?読むだけでプログラミングが上達する3原則

  プログラミングがなかなか身につかない   学習をしているけど、自分で書くとなれば思うようにいかなかったり、覚えたはずなのにその使い方や応用方法がわからない人のほとんどが、作り方そのものが間違っている傾向にあります。   今回は、プログラミング初学者や、なかなかスキルアップができない人...

PHPポケモン「バトルシステム編 〜バトル終了判定〜」28
プログラミング
JavaScript,jQuery,PHP,PHPポケモン,ポケモン
PHPポケモン「バトルシステム編 〜バトル終了判定〜」28

バトル終了判定 今回はバトル終了判定を実装しましょう。今までは「にげる」による戦闘離脱のみで、ひんし状態でも殴り合うことが出来たので、それを解消するためにも戦闘結果による判定を導入します。   ひんし状態の監視 まずは「ひんし」の監視です。現在は交代ポケモンどちらか一方がひんし状態になれば、そ...

PHPポケモン「コントローラー編」〜POSTとSESSIONの活用〜 10
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「コントローラー編」〜POSTとSESSIONの活用〜 10

  今回のPHPポケモンでは、今まで作った機能用のコントローラーになるインターフェースを作成します。ポケモンやメソッドを選択できるようにして、よりゲーム性の高いアプリケーションを実装しましょう。   第1回から学習したい方はコチラ     コントローラーの実装   それでは実装したアクション...

SEが心がけるべき3つの習慣
プログラミング
Automator,JavaScript,エンジニア,システムエンジニア,プログラマー,プログラミング
SEが心がけるべき3つの習慣

  ネット社会、在宅ワークが主流になってきた今、SEという仕事に憧れを頂いている人は多くなりました。 単価の良さも、魅力の一つです。そして、技術が普及してきたことにあわせて、便利なソフトやアプリが簡単に手に入るようになり、一昔前と比べると技術の習得も容易になりました。   しかし、多くの人が...

両隣のポケモン取得編(配列の隣の要素)PHPポケモン 92
プログラミング
PHP,PHPポケモン,ポケモン
両隣のポケモン取得編(配列の隣の要素)PHPポケモン 92

両隣のポケモンを判別する パーティーの中からID指定でポケモンを特定するためのメソッドは実装されていましたが、その両隣にどんなポケモンが控えているのかを判別する手段がありませんでしたね。 なので、今回は両隣のポケモンを判別するためのメソッドを準備して活用していきましょう。   パーティー まずは...

Toastr(トースト)活用編 PHPポケモン 100
プログラミング
JavaScript,PHP,PHPポケモン,ポケモン
Toastr(トースト)活用編 PHPポケモン 100

記念すべき第100回目です!   色々考えましたが、100回目だからと言って特別な内容ではなく、いつもの流れの延長での開発進行となります。ご了承ください。 今回は、何人かのプレイユーザーの声も参考にしながら、ユーザビリティをあげるための機能追加を進めていきます。   Toastr(トースト)と...

HPバー色変更編(アニメーション) PHPポケモン53
プログラミング
PHP,PHPポケモン,ポケモン
HPバー色変更編(アニメーション) PHPポケモン53

HPバーの色変更 残りHPの割合に合わせて色クラスをセットしていましたが、ダメージを受けた際の判定処理(動的は変更)が未実装でしたので、今回はコチラを対応します。   残数(割合)の判定 HPの色判定は、HTMLの描画時とJSによるHP変動時に行います。animateメソッド前や後に行うと変更のズレが生じるため、a...

WordPressで作ったサイトで実装するワンランク上のSEO対策
SEO対策
PHP,WordPress,プログラミング
WordPressで作ったサイトで実装するワンランク上のSEO対策

  WordPressでSEOに強いサイトを運営したい   近年、ブログを採用せずともWordPressを使用したサイト作りが増えてきました。 その理由には更新の手軽さはもちろん、優秀なプラグインが揃っていることでSEO対策に強いサイト作りが簡単だということが大きいです。   今回は、WordPressのブログやサイトで役立...

カテゴリ

SEO対策 イベント デザイン ネットワーク ビジネスモデル フリーランス プログラミング マーケティング ライティング 動画編集 雑記

タグ

5G Adobe AfterEffects AI ajax amazon Animate api artisan atom Automator AWS Bluetooth CSS CVR description EC-CUBE4 ECショップ ESLint Facebook feedly foreach function Google Google AdSense Honeycode htaccess HTML IEEE 802.11ax Illustrator Instagram IoT JavaScript jQuery jQuery UI keyword LAN Laravel Linux MacBook MAMP meta MLM MySQL NoCode note OS OSI参照モデル Paypal Photoshop PHP phpMyAdmin PHPポケモン PremierePro rss SEO SEO対策 Sequel Pro Skype SNS SSH Symfony TCP/IP title Toastr Trait Twig Twitter UCC V系 WAN WebSub Wi-Fi wiki Windows WordPress XAMPP xml Xserver YouTube YouTuber Zoom アーティスト アウトプット アクセス層 アニメーション アフィリエイト イーブイ インターネット インプット エンジニア オブジェクト指向 お金配り クリック単価 クリック数 コミュニケーション能力 コロナ コンサルティング サムネイル システムエンジニア スタートアップ スタイルシート スパム データベース ディープフェイク デザイナー デザイン テレワーク ナンパ ニュース ネットワークモデル ノマドワーク バナー ピカチュウ ビジネス フィード フリーランス ブロガー ブログ プログラマー プログラミング プログラミング学習 プログラミング教育 プロトコル ホームページ制作 ポケモン マークアップ マーケティング メール リモートワーク レンダリング 三井住友 三宮 仕事依頼 児童デイ 児童デイサービス 児童発達支援 公開鍵 初心者 助成金 勉強法 営業 広告 広告収入 必勝マニュアル 放課後等デイサービス 朝活 楽天 深層学習 無線LAN 独立 神戸 福祉 秘密鍵 翻訳 自己啓発 英語 見積書 計算機 読書 起業 迷惑メール 配列 銀の弾丸 集客 雑学力