プログラミング

戦闘不能による交代編 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(シングルページアプリケーション)による構築が候補となります。

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

 

注目の記事

仕事用PCは2年で買い替えろ!その理由とは?
フリーランス
MacBook
仕事用PCは2年で買い替えろ!その理由とは?

  「あなたはパソコンをどのタイミングで買い替えますか?」   私は先日、2015年モデルのMacbookPro15インチから最新モデルのMacbookPro13インチに買い替えました。その理由は、メモリが32GBになったことや、15インチが持ち運びという点で見れば向いていないと判断したということ、そこそこの年数が経...

なぜ(・・? あなたはMacを使うのか?
雑記
AWS,Linux,MacBook,OS,Windows
なぜ(・・? あなたはMacを使うのか?

  あなたが使っているPCはなんですか?   たまに聞かれることがあります。 そこで「Macを使っています」と答えると「何故?」という次の問いが返ってくることがあります。   あなたがもしMacを使っているのであれば、このときになんと答えますか?   今回のテーマは、「何故Macを使っているの?」と...

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

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

【Laravel】1対1リレーションをわかりやすく解説(hasOne)
プログラミング
Laravel,PHP
【Laravel】1対1リレーションをわかりやすく解説(hasOne)

  Laravelの1対1リレーションのhasOneについて、公式マニュアルでは専用単語ばかりでどうしてもわかりにくいと感じてしまっている方へ向けて、わかりやすく解説しました。 ※例で紹介しているコードについては、一部英語を日本語表記で使用している部分もありますので、コピペで使用する方は必要に応じて置...

PHPポケモン「わざ編〜わるあがき〜」35
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「わざ編〜わるあがき〜」35

わるあがき そろそろ技のPPを実装段階にきたので、その前に「わるあがき」という技を作成しましょう。「わるあがきって何?」という人のために、どういった技なのか簡単に説明します。 全ポケモン使用可能。ただし、レベルアップなどで普通のわざとして覚えることはできず、自分の技がすべて選択不能になった場合...

フリーランス向けの営業コミュ力向上マニュアル
フリーランス
コミュニケーション能力,フリーランス,営業
フリーランス向けの営業コミュ力向上マニュアル

  せっかくの技術があっても、フリーランスで生計が立てられない 生計は立てられていても、技術レベルに比べて収入が見合っていない   そういった人は非常に多いです。 共通しているのは、営業力の弱さです。   営業は仕事に置いては基本であり究極です。 しかし、フリーランスになる方の多くは技術...

ブラウザで遊べる「PHPポケモン」
プログラミング
PHP,PHPポケモン,ポケモン
ブラウザで遊べる「PHPポケモン」

PHPポケモン 約1ヶ月半をかけて作り込んできたPHPポケモンですが、ある程度遊べるぐらいのレベルになったので、みなさまにも体験・楽しんでいただけるよう本日(2020年10月12日)より一般公開します。   PHPポケモンへのリンクは本記事の最後に用意しておりますので、プレイする前に注意事項等に目を通し...

非公開ディレクトリ画像表示編 PHPポケモン 91
プログラミング
PHP,PHPポケモン,ポケモン
非公開ディレクトリ画像表示編 PHPポケモン 91

非公開ディレクトリの画像を表示する 今回は、β版に向けての取り組みの1つとして、表示させる画像のアクセス先を非公開ディレクトリに変更します。 現在は公開ディレクトリ(Public)内のAssetsフォルダ内に配置していますが、これをルート直下においているStorageに移動させるのが目的となります。   gifのbas...

カテゴリ

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