プログラミング

戦闘不能による交代編 PHPポケモン84

PHP PHPポケモン ポケモン
戦闘不能による交代編 PHPポケモン84

戦闘不能による交代

ポケモンが戦闘不能になった際、もし手持ちに戦える状態のポケモンが残っていれば「交代」か「逃げる」の2択になります。今までは手持ちポケモンが1匹のみで判定を行っていたので、今回は交代の選択肢も含めて勝負の判定の見直しをしていきます。

 

パーティーを含めた勝負判定

味方または相手のポケモンがひんし状態になると、コントローラーのjudgmentメソッドで勝ち負けの分岐を行っています。ここに、パーティーを含めた判定処理を加え、もしまだ戦える状態であれば選択肢が出るように新しい分岐を追加します。

 

バトルコントローラー用トレイト(/App/Traits/Controller/BattleControllerTrait.php
/**
* バトル結果判定
* @return void
*/
private function judgment(): void
{
    // 味方がひんし状態になった
    if(battle_state()->isFainting('friend')){
        // 戦闘可能なパーティーを確認
        if(player()->isFightParty()){
            // パーティーが残っている
            if(battle_state()->isFainting('enemy')){
                // 相手が瀕死状態 → バトル終了
                $this->judgmentWin();
            }else{
                // 相手が瀕死状態ではない → ポケモン交代の確認
                $msg_id = issueMsgId();
                setMessage('次のポケモンを使いますか?', $msg_id);
                // レスポンスデータをセット
                setResponse([
                    'toggle' => 'modal',
                    'target' => '#'.$msg_id.'-modal'
                ], $msg_id);
                // モーダル用のレスポンスをセット
                setModal([
                    'id' => $msg_id,
                    'modal' => 'change-or-run'
                ]);
                waitForceModal($msg_id);
            }
        }else{
            // 全滅(負け)
            $this->judgmentLose();
        }
    }else if(battle_state()->isFainting('enemy')){
        // 相手がひんし状態になった(味方はひんし状態ではない)
        // 勝ち
        $this->judgmentWin();
    }
}
 
/**
* バトル結果(負け)
* @return void
*/
private function judgmentLose()
{
    // 全滅
    setMessage(player()->getName().'は、目の前が真っ暗になった');
    // バトル終了判定用メッセージの格納
    setEmptyMessage('battle-end');
}
 
/**
* バトル結果(勝ち)
* @return void
*/
private function judgmentWin()
{
    // 経験値の計算
    $party = player()->getParty();
    $order = battle_state()->getOrder();
    // パーティー取得
    $exp = $this->calExp(friend(), enemy());
    // 経験値をポケモンにセット
    $party[$order]->setExp($exp);
    // 努力値を獲得
    $party[$order]->setEv(enemy()->getRewardEv());
    // もしポケモンが「へんしん状態」であれば変更後の状態を引き継ぎ
    if(friend()->checkSc('ScTransform')){
        friend()->judgmentTransform($party[$order]);
    }
    // 散らばったお金の取得
    $money = battle_state()->getMoney();
    if($money){
        setMessage(player()->getName().'は、'.$money.'円拾った');
        player()->addMoney($money);
    }
    // バトル終了判定用メッセージの格納
    setEmptyMessage('battle-end');
}

 

もし味方ポケモンが瀕死状態になり、パーティーに戦える状態のポケモンが残っていれば、「逃げる」または「次のポケモンを選ぶ」の選択肢を表示したモーダルを起動させています。

 

モーダルは以下の通りです。

 

交代または逃げるの選択モーダル(/Resources/Partials/Battle/Modals/change-or-run.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-body">
                <p class="mb-0">次のポケモンを選びますか?</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-sm btn-success" data-toggle="modal" data-target="#party-modal">ポケモンを選ぶ</button>
                <button type="button" class="btn btn-sm btn-danger" data-submit_remote="run">逃げる</button>
            </div>
        </div>
    </div>
</div>

 

強制表示モーダル

選択しなければモーダルは原則閉じれないようにしていますが、もし更新等をされた場合は再度判定処理が行われてしまいます。これでは、画面の更新を行えば逃げられない相手であっても回数を重ねることで逃げられるようになり、ゲーム性が失われてしまいます

これを防ぐためにも、強制的に選択を問うモーダルは「強制表示モーダル」として登録、更新後はモーダルを強制起動させる必要があります。

そのために、モーダルセット後に以下のメソッドを呼び出しています。

waitForceModal(識別ID);

 

強制表示させるとしても、その場で強制状態にすれば更新などイレギュラーな読み込み以外でもメッセージを無視して表示されてしまいます。それを防ぐためにも、通常セット後には強制表示を待機状態として用意、画面の読み込みが全て終わったあとに待機状態から強制表示へと切り替えます。

 

レスポンスクラス(/Classes/Response.php
/**
* 強制表示モーダルの初期化
* @return void
*/
public function initForceModal(): void
{
    unset($_SESSION['__data']['force_modal']);
}
 
/**
* 強制表示モーダルのセット
* @param id:string
* @return boolean
*/
public function setForceModal($id): bool
{
    // 強制表示させるモーダルを取得
    $key = array_search($id, array_column($this->modals, 'id'));
    // 見つかればセッションへ格納
    if($key !== false){
        $_SESSION['__data']['force_modal'] = $this->modals[$key];
        // ID重複回避のためモーダル内から取り除く
        unset($this->modals[$key]);
        return true;
    }
    return false;
}
 
/**
* 強制表示モーダルを待機状態にする(更新等された際に強制表示)
* @param id:string
* @return void
*/
public function waitForceModal($id): void
{
    $this->wait_force_modal = $id;
}
 
/**
* 強制表示モーダルを待機状態にする(更新等された際に強制表示)
* @param id:string
* @return boolean
*/
public function setWaitForceModal(): bool
{
    // 待機中の強制表示モーダルがあれば、セッションへ格納
    if($this->wait_force_modal){
        $this->setForceModal($this->wait_force_modal);
        $this->wait_force_modal = '';
        return true;
    }
    // 待機中なし
    return false;
}
 
/**
* 強制表示モーダルの存在確認
* @return boolean
*/
public function isForceModal(): bool
{
    if(isset($_SESSION['__data']['force_modal'])){
        return true;
    }
    return false;
}
 
/**
* 強制表示モーダルの取得
* @return array
*/
public function getForceModal(): array
{
    return $_SESSION['__data']['force_modal'] ?? [];
}
 
/**
* 強制表示モーダルの確認
* @return boolean
*/
public function isForceModalTarget($target): bool
{
    if(
        isset($_SESSION['__data']['force_modal']['existing_modal']) &&
        $_SESSION['__data']['force_modal']['existing_modal'] === $target
    ){
        return true;
    }
    return false;
}

 

クラス内保管では再読み込み時にデータが失われてしまうため、セッションを活用しています。待機状態で登録したモーダルは、画面最終でセッションへ移動させる必要があるので、コアファイルの最終部分で置き換え用のメソッド(setWaitForceModal)を起動しています。

これで、もし再読み込みをされても強制モーダルを起動することで選択肢を問うことができます。

 

強制モーダルはフッターで存在チェックをしてから読み込み、存在する場合はjsで強制起動させましょう。

 

フッター(/Resources/Partials/Layouts/Foot/footer.php
# 強制モーダルの読み込み
if(isForceModal()){
    $modal = getForceModal();
    // 既存モーダルを使用しない場合は読み込み
    if(isset($modal['modal'])){
        include($root_path.'/Resources/Partials/'.getPageName(true).'/Modals/'.$modal['modal'].'.php');
    }
    echo '<input type="hidden" id="force-modal" value="'.($modal['existing_modal'] ?? '#'.$modal['id'].'-modal').'">';
}

 

共通JS/Public/Assets/common.js
/**
 * 強制モーダルの起動
 * @function modal
 */
var showForceModalInit = function(){
    $(document).ready(function() {
        var force_modal = $('#force-modal');
        if(force_modal.length){
            $(force_modal.val()).modal('show');
        }
    });
}

 

戦闘からの離脱

選択肢の1つである「逃げる」は、戦えるポケモンを選ばずにバトルを終了させることができます。ただし、通常時の逃げると同様で逃走判定が行われ、失敗すれば次のポケモンを選出しなければなりません。

このときの逃げる判定は、ひんし状態になったポケモンのステータスを参考に算出するため、RunServiceを少しカスタマイズすることで実装します。

 

逃げるサービス(/App/Services/Battle/RunService.php
/**
* @return void
*/
public function execute()
{
    // にげるのカウントを進める
    battle_state()->run();
    if($this->checkRun()){
        // 逃走成功
        setMessage('上手く逃げ切れた');
        // バトル終了判定用メッセージの格納
        setEmptyMessage('battle-end');
    }else{
        // 逃走失敗
        $msg_id = issueMsgId();
        setMessage('逃げられない!', $msg_id);
        if(friend()->isFight()){
            // 相手のターン処理
            $this->enemyTurn();
        }else{
            // ひんし状態での逃走失敗
            setResponse([
                'toggle' => 'modal',
                'target' => '#party-modal'
            ], $msg_id);
            setModal([
                'id' => $msg_id,
                'existing_modal' => '#party-modal' # 既存モーダルの使用
            ]);
            // 強制表示モーダルを待機状態にする
            waitForceModal($msg_id);
            // 判定不要処理
            battle_state()->judgeFalse();
        }
    }
    // バトルポケモンが瀕死状態なら、強制モーダルを初期化
    if(!friend()->isFight()){
        initForceModal();
    }
}

 

もし味方が瀕死状態でこのサービスが呼び出された際は、ひんし状態での2択による処理ということが判別できます。その際は逃走失敗後に相手の行動を行わず、ポケモン選択のモーダルを強制表示待機状態でセットして返却しています。

 

サービス終了後、コントローラーでは瀕死状態をチェックして判定処理を行っています。このまま返却すれば再度判定処理が実施されてしまうので、回避用にバトル状態クラスへ判定不要フラグを追加、状態を確認してjudgementを制御しましょう。

 

バトル状態クラス(/Classes/BattleState.php
/**==================================================================
* 判定確認用フラグ
==================================================================**/
 
/**
* 判定不要にする処理
* @return void
*/
public function judgeFalse(): void
{
    $this->judgement = false;
}
 
/**
* 要判定にする処理
* @return void
*/
public function judgeTrue(): void
{
    $this->judgement = true;
}
 
/**
* 判定有無の確認
* @return boolean
*/
public function isJudge(): bool
{
    return $this->judgement;
}

 

次のポケモンを選ぶ

最後に今回の本題となるポケモンの選出についてです。ポケモンを選ぶためのモーダルは、パーティーモーダルをそのまま使用しています。

交代処理は通常時と同じくChangeServiceを活用できるように、こちらも味方が瀕死状態かどうかを確認することで、相手の行動が行われないようにします。

 

ポケモン交代サービス(/App/Services/Battle/ChangeService.php
/**
* @return void
*/
public function execute()
{
    // バリデーション
    if(!$this->validation()){
        return;
    }
    // 瀕死チェック後に交代処理を行う(friendのポケモンが入れ替わるため)
    if(!friend()->isFight()){
        // 瀕死状態からの交代
        $this->change();
        // モーダル初期化
        initForceModal();
    }else{
        // 通常の交代処理
        $this->change();
        // 相手のターン処理
        $this->enemyTurn();
    }
}

  

それでは、ひんし状態から交代の流れを確認してみましょう。

 

ひんし後の判定から交代まで正常に機能していますね。これでポケモン交代の一連の流れが完成です。

 

まとめ

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

今回のPHPポケモンでは、「戦闘不能による交代」の実装方法をご紹介しました。

WEBプログラミングでフォームを活用する際には、画面移管による初期状態の生成が厄介なポイントです。これを解決するためには、全体の構成に気をつけることの他に、JSを主軸としたSPA(シングルページアプリケーション)による構築が候補となります。

現在プログラミング学習に取り組んでいる方は、ぜひ参考にしてみてくださいね。

 

注目の記事

PHPポケモン「オートローダー編」16
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「オートローダー編」16

  今までは技やタイプを一括requireという荒業で対応していましたが、フシギダネ系列の技を実装した際に「こんなん全部読み込んでられるか!」と流石になったので、簡易ながらオートローダーを実装していきます。 そして、実装したらしたで色々と問題も浮かび上がってきたので、このあたりは回を進めて行きなが...

フリーランスの仕事の取り方教えます!この3つを押さえておけばOKです【企業も応用可】
フリーランス
フリーランス,独立,起業
フリーランスの仕事の取り方教えます!この3つを押さえておけばOKです【企業も応用可】

  仕事ってどうやってとればいいの?   独立したい、起業したいと考えている人の多くが、仕事はどうやってとればいいのかと悩んで足踏みしています。 実は、基本的な3つのポイントさえ知っていれば、継続して仕事を受注することは簡単です。 今回は自分が実際にやっていることを例に「フリーランスなら...

捕獲処理実装編 PHPポケモン 80
プログラミング
PHP,PHPポケモン,ポケモン
捕獲処理実装編 PHPポケモン 80

捕獲処理の作成 前回モンスターボールのクラスを作成したので、今回は捕獲判定までの一連の処理を仕上げていきます。サービス自体は他のアイテムと一緒にするためItemServiceを呼び出し、その中で使用されたアイテムを判断して分岐を作ります。   バトル中のアイテムサービス(/App/Services/Battle/ItemService.ph...

AIが人類にもたらす驚異!深層学習が与える影響とは
ネットワーク
AI,ディープフェイク,深層学習
AIが人類にもたらす驚異!深層学習が与える影響とは

  海外の記事でAIについて記述した興味深いものが掲載されました。   今回は「AIが人類にもたらす驚異!深層学習が与える影響とは」について、上記サイトを参考にまとめましたのでご紹介します。 ※直訳ではありません、あくまで記事の内容を参考にして自らの考えを記述したものです     AIの驚異と...

レベニューシェアとは?利益報酬・共同事業に潜む罠
フリーランス
レベニューシェアとは?利益報酬・共同事業に潜む罠

  レベニューシェアという言葉を聞いたことがありますか?   ビジネスの世界にいる人なら、意味は知らなくてもやったことがある方が意外と多いはずです。特にフリーランスの人や、プログラミングやデザインといったスキルを持っている人はレベニューシェアでは重宝されるため多い傾向があります。ここ最近...

ビジュアル作り込み編(序) PHPポケモン66
プログラミング
PHP,PHPポケモン,ポケモン
ビジュアル作り込み編(序) PHPポケモン66

ビジュアルの作り込み 最近は内部の作り込みが多かったので、今回のPHPポケモンでは見た目を少しだけ作り込んでいきます。とはいっても、機能自体がそこまで揃っていないため、あくまで仮の見た目となります。 ある程度見た目が整っていると、プレイする側のモチベーションや楽しみも増えると思ったので、こちらは並...

連続の技習得編 オブジェクトをセッションへ格納 PHPポケモン57
プログラミング
PHP,PHPポケモン,ポケモン
連続の技習得編 オブジェクトをセッションへ格納 PHPポケモン57

セッション経由でのオブジェクト引き継ぎ 技習得の処理が整ってきたので、ここで連続技習得・連続レベルアップ時にも問題なく動作するように作り込んでいきます。ですが、現状のモーダルをレスポンスやメッセージと同様に、そのまま引き継いだとしてもエラーが発生します。 その原因がセッション経由でのオブジェク...

熟練者ほど実践するプログラミングが上達する3つの法則
プログラミング
PHP
熟練者ほど実践するプログラミングが上達する3つの法則

  「なかなかプログラミングが上達しない・・・」 「やったことはあるけど覚えられない」   プログラミングを習得しても、勉強と一緒で使っていなければ忘れてしまいます。また、どんどん上達する人や、長い間プログラミングの技術で生計を立てているような熟練者は、日頃からの取り組み方自体が違ってい...

カテゴリ

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 独立 神戸 福祉 秘密鍵 翻訳 自己啓発 英語 見積書 計算機 読書 起業 迷惑メール 配列 銀の弾丸 集客 雑学力