プログラミング

進化直後の技習得編 PHPポケモン 65

PHP PHPポケモン ポケモン
進化直後の技習得編 PHPポケモン 65

進化直後の技習得

パーティー機能を導入に合わせて、至る場所を修正することになり、合わせて未実装だった機能を導入していきます。

見た目にはわからない部分や、とある条件が重ならなければ起こらない部分の作り込みが多いため、プレイユーザー目線からすると少し面白みが無いかも知れません。

ですが、そういった例外対応などがシステム開発には時間がかかったりするものです。

 

今回実装する「進化直後の技習得」も、その代表になる1つです。

初代御三家には、進化直後に技を覚えるポケモンはいませんが、進化レベルをスキップして進化させた場合であれば同じ状況を作ることが可能ですので、現状でも必要な機能となります。

 

技習得用サービスの作成

それでは、技習得機能を実装するためのサービスを作成しましょう。

技を習得するためのサービスは、バトル画面用に作成しました。内容は殆ど同じですが、部分的に違ってくる箇所があるため、新しく進化画面用のサービスとして用意します。

 

進化画面用技習得サービス(/App/Services/Evolve/LearnMoveService.php
<?php
$root_path = __DIR__.'/../../..';
// 親クラス
require_once($root_path.'/App/Services/Service.php');
 
/**
* 技の習得処理
*/
class LearnMoveService extends Service
{
 
    /**
    * @var Pokemon:object
    */
    protected $pokemon;
 
    /**
    * @var array
    */
    protected $before_responses;
 
    /**
    * @var array
    */
    protected $request;
 
    /**
    * @param parth:array
    * @param order:integer
    * @param before_response:array
    * @param before_messages:array
    * @param before_modals:array
    * @param request:array
    * @return void
    */
    public function __construct($party, $order, $before_responses, $before_messages, $before_modals, $request)
    {
        $this->pokemon = $party[$order];
        $this->before_responses = $this->unserializeObject($before_responses);
        $this->before_messages = $before_messages;
        $this->before_modals = $this->unserializeObject($before_modals);
        $this->request = $request;
    }
 
    /**
    * @return void
    */
    public function execute()
    {
        // 技の置き換え
        $this->replaceMove();
        // レスポンスの引き継ぎ
        setResponse(
            $this->getUntreatedResponses($this->before_responses, $this->request['id'])
        );
        // メッセージの引き継ぎ
        setMessage(
            $this->getUntreatedResponses($this->before_messages, $this->request['id'], 'message')
        );
        // モーダルの引き継ぎ
        setModal(
            $this->getUntreatedResponses($this->before_modals, $this->request['id'], 'modal'), true
        );
    }
 
    /**
    * @return Pokomon:object
    */
    public function getPokemon()
    {
        return $this->pokemon;
    }
 
    /**
    * 技の置き換え
    * @return void
    */
    private function replaceMove()
    {
        // 忘れる技を取得
        $forget_move = $this->pokemon
        ->getMove($this->request['forget']);
        // 覚えさせる技を取得
        $new_move = new $this->before_responses[$this->request['id']]['move'];
        // 技を覚えさせる
        $this->pokemon
        ->setMove($new_move, $this->request['forget']);
        // メッセージの返却
        setMessage('1 2の ……ポカン!');
        setMessage($this->pokemon->getNickname().'は、'.$forget_move->getName().'の使い方をキレイに忘れた!そして......');
        setMessage($this->pokemon->getNickname().'は新しく、'.$new_move->getName().'を覚えた!');
    }
 
    /**
    * 未処理レスポンス・メッセージ・モーダルの引き継ぎ処理
    * @param response:array
    * @param msg_id:string
    * @param param:string::response|message|modal
    * @return array
    */
    private function getUntreatedResponses(array $responses, string $msg_id, string $param='response')
    {
        $cnt = 1;
        switch ($param) {
            /********
            * メッセージの引き継ぎ
            */
            case 'message':
            $key = array_search(
                $msg_id,
                array_column($responses, 1), # メッセージIDの位置は1番目
                true
            );
            // 対象メッセージを含め3つ目までを削除
            $cnt = 3;
            break;
            /********
            * モーダルの引き継ぎ
            */
            case 'modal':
            $key = array_search(
                $msg_id,
                array_column($responses, 0), # メッセージIDの位置は0番目
                true
            );
            break;
            /********
            * レスポンスの引き継ぎ
            */
            default:
            // メッセージIDのレスポンスが入った位置を取得
            $key = array_search(
                $msg_id,
                array_keys($responses),
                true
            );
            break;
        }
        // 未処理だけを切り出して返却
        return array_splice($responses, $key + $cnt);
    }
 
}

 

更に、技習得サービスへ移行させるための分岐をコントローラーへ追加しましょう。

 

進化画面用コントローラー(/App/Controllers/Evolve/EvolveController.php)
<?php
$root_path = __DIR__.'/../../..';
require_once($root_path.'/App/Controllers/Controller.php');
// サービス
require_once($root_path.'/App/Services/Evolve/EvolveService.php');
require_once($root_path.'/App/Services/Evolve/CancelService.php');
require_once($root_path.'/App/Services/Evolve/DefaultService.php');
require_once($root_path.'/App/Services/Evolve/LearnMoveService.php');
// トレイト
require_once($root_path.'/App/Traits/Controller/EvolveControllerTrait.php');
 
// 進化画面用コントローラー
class EvolveController extends Controller
{
 
    use EvolveControllerTrait;
 
    /**
    * @return void
    */
    protected $process_flg = false;
 
    /**
    * @return void
    */
    public function __construct()
    {
        // 親コンストラクタの呼び出し
        parent::__construct();
        // 引き継ぎ
        $this->takeOver();
        // 分岐処理
        $this->branch();
        // 親デストラクタの呼び出し
        parent::__destruct();
    }
 
    /**
    * @return void
    */
    public function __destruct()
    {
        // 次画面へ送るデータ
        $_SESSION['__data']['party'] = $this->serializeObject($this->party);
        $_SESSION['__data']['before_reponses'] = $this->serializeObject(getResponses());
        $_SESSION['__data']['before_modals'] = $this->serializeObject(getModals());
        $_SESSION['__data']['before_messages'] = getMessages();
        if($this->process_flg){
            $_SESSION['__data']['order'] = $this->order;
        }
        // 親デストラクタの呼び出し
        parent::__destruct();
    }
 
    /**
    * アクションに合わせた分岐
    * @return void
    */
    private function branch()
    {
        // 対象がいなければホーム画面へ移管
        if(is_null($this->order)){
            $this->goToHome();
        }
        // アクションに合わせた分岐
        switch ($_POST['action'] ?? '') {
            /******************************************
            * 進化
            */
            case 'evolve':
            $service = new EvolveService($this->party, $this->order);
            $service->execute();
            // 新しくなったパーティーをセット
            $this->party = $service->getParty();
            // 処理中フラグを引き継ぎ
            $this->process_flg = $service->process_flg;
            break;
            /******************************************
            * 進化キャンセル
            */
            case 'cancel':
            $service = new CancelService($this->party, $this->order);
            $service->execute();
            // ページをリロード
            $this->reload();
            break;
            /******************************************
            * 技の習得
            */
            case 'learn_move':
            // サービス実行
            $service = new LearnMoveService(
                $this->party,
                $this->order,
                $_SESSION['__data']['before_reponses'],
                $_SESSION['__data']['before_messages'],
                $_SESSION['__data']['before_modals'],
                $this->request('param')
            );
            $service->execute();
            break;
            /******************************************
            * 進化確認画面
            */
            default:
            $service = new DefaultService($this->party, $this->order);
            $service->execute();
            break;
        }
       
    }
 
    /**
    * ホーム画面へ移管させる処理
    * @return void
    */
    protected function goToHome()
    {
        unset(
            $_SESSION['__data']['order'],
            $_SESSION['__data']['before_messages'],
            $_SESSION['__data']['before_modals'],
            $_SESSION['__data']['before_responses']
        );
        $_SESSION['__route'] = 'home';
        header("Location: ./", true, 307);
    }
 
    /**
    * リロード処理
    * @return void
    */
    protected function reload()
    {
        unset(
            $_SESSION['__data']['order'],
            $_SESSION['__data']['before_messages'],
            $_SESSION['__data']['before_modals'],
            $_SESSION['__data']['before_responses']
        );
        $_SESSION['__route'] = 'evolve';
        header("Location: ./", true, 307);
    }
 
}

 

技習得用にレスポンスの引き継ぎ処理用パラメーターを追加し、分岐を追加しました。進化直後は対象ポケモンに進化フラグが立っておらず、次のポケモンへ進化が移動してしまったり、技習得処理がされずホーム画面へ移管されてしまいます。それを防ぐために、セッションを通してポケモン番号を引き継いでいます

※ヘッド部分で引き継ぎ処理をしていたセッションは、デストラクタで処理する方法に変更しました。問題なく動作しそうであればこちらで統一予定です。

 

処理中の判定

技を覚えようとしていれば、現在処理中ということをコントローラー内で判定できなければなりません。そのために、$process_flgというプロパティを用意しました。こちらを、進化処理内で作成して返却します。

進化処理をサービスにまとめたので、処理を見ていきましょう。

 

進化サービス(/App/Services/Evolve/EvolveService.php
<?php
$root_path = __DIR__.'/../../..';
// 親クラス
require_once($root_path.'/App/Services/Service.php');
 
/**
 * 進化用サービス
 */
class EvolveService extends Service
{
 
    /**
    * @var array
    */
    private $party;
 
    /**
    * @var integer
    */
    private $order;
 
    /**
    * @var boolean
    */
    public $process_flg = false;
 
    /**
    * @return void
    */
    public function __construct($party, $order)
    {
        $this->party = $party;
        $this->order = $order;
    }
 
    /**
    * @return void
    */
    public function execute()
    {
        // 進化処理
        $this->evolve();
    }
 
    /**
    * パーティープロパティの取得
    *
    * @return array
    */
    public function getParty()
    {
        return $this->party;
    }
 
    /**
    * 進化
    *
    * @return void
    */
    private function evolve()
    {
        // 対象ポケモンの取得
        $before = $this->party[$this->order];
        $after_class = $before->getAfterClass();
        // 対象ポケモンが進化可能な状態か確認
        if(
            $before->getEvolveFlg()
            && class_exists($after_class)
        ){
            // 現在のHPを取得
            $before_hp = $before->getStats('HP');
            // 進化ポケモンのインスタンスを生成
            $after = new $after_class($before);
            // HPの上昇値分だけ残りHPを加算(ひんし状態を除く)
            if(!isset($after->sa['SaFainting'])){
                $after->calRemainingHp('add', $after->getStats('HP') - $before_hp);
            }
            setMessage('おめでとう!'.$before->getNickName().'は'.$after->getName().'に進化した!');
            // 進化後のインスタンスをパーティーにセット
            $this->party[$this->order] = $after;
            // 現在のレベルで習得できる技があるかチェック
            if($after->getLevelMoveCount()){
                $after->checkLevelMove();
                $this->process_flg = true;
            }
            // 空メッセージのセット
            setEmptyMessage();
        }else{
            setMessage('このポケモンは進化できません');
        }
    }
 
}

ポケモンの進化処理後、習得できる技があるかどうかを確認して、あればcheckLevelMoveを呼び出し、処理中フラグをtrueに変更しています。

これで、もし技の習得が介入した場合は処理中だということをコントローラーに伝えることができます

 

ただ、連続で技を習得しようとすると進化サービスを経由しないため処理中フラグが折れてしまいます。だからといって、セッションのオーダーだけを先行させていれば複数ポケモンの進化待ち状態があれば次に進むこともありません

それを防ぐために、ポケモン番号を抽出するためのメソッドにアクションの判定を追加します。

 

進化コントローラー用トレイト(/App/Traits/Controller/EvolveControllerTrait.php
<?php
/**
* 進化コントローラー用トレイト
*/
trait EvolveControllerTrait
{
 
    /**
    * 引き継ぎ処理
    * @return void
    */
    protected function takeOver()
    {
        $this->party = $this->unserializeObject($_SESSION['__data']['party']);
        $this->order = $this->selectEvolveTarget();
    }
 
    /**
    * 進化ポケモンの選出
    *
    * @return object
    */
    protected function selectEvolveTarget()
    {
        // 技習得処理中であればセッションの値を返却
        if(
            isset($_SESSION['__data']['order']) &&
            ($_POST['action'] ?? '') === 'learn_move'
        ){
            return $_SESSION['__data']['order'];
        }else{
            $evolves = array_filter($this->party, function($pokemon){
                return $pokemon->getEvolveFlg();
            });
            // 進化対象のポケモンがいなければ終了
            if(empty($evolves)){
                return null;
            }else{
                return array_key_first($evolves);
            }
        }
    }
 
    /**
    * 味方ポケモン情報の取得
    *
    * @return object
    */
    public function getPokemon()
    {
        return $this->party[$this->order] ?? '';
    }
 
}

 

もしアクションがlearn_moveであればセッションのオーダー値を採用、そうでなければパーティー内の進化フラグが立っているポケモンから抽出するようにしています。

こうすることで、連続で技習得処理が入ったとしても、その処理を終えるまでは次のポケモンに移行したり、進化処理そのものが終了してしまうことはありません。

 

では、おなじみ「フシギダネ」と「カメックス」、威力445の「つるのムチ」ご協力のもと、試してみましょう。

 

今回はテスト用にフシギソウのレベル16で習得できる技に「かげぶんしん」と「あなをほる」を追加しました。問題なく2つの技が処理されていますね。

これで、進化直後の技習得処理が完成です。

 

まとめ

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

今回のPHPポケモンでは、進化直後の技習得処理の実装方法をご紹介しました。

システムの中では地味な部類且つイレギュラーな状況下での処理になりますが、システム開発ではこういったことが多いのも事実です。

 

余談ですが今回のテスト時に驚いたことは、前回に引き続きカメックスの耐久力とフシギダネの貧弱さです。当初レベル21のフシギダネとレベル25のカメックスでレベルアップ検証を行ない、つるのムチの威力を445で検証したところ、なんと高乱数1発でしか倒せないということがわかりました。2進化ポケモンの強さがよく分かる瞬間でした。

 

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

 

注目の記事

教師が勝ち組!?出会い&学習の超正統派マッチングサービスとは【ビジネス企画書】
ビジネスモデル
マーケティング
教師が勝ち組!?出会い&学習の超正統派マッチングサービスとは【ビジネス企画書】

  「出会いがない」   社会人になると多くの人が抱く悩みの1つです。職場の男女比率や年齢層が理由の人もいれば、同じ職場での出会いは求めていない人もいるでしょう。 今回はそんな「出会い」を解決するための企画「出会い&学習の超正統派マッチングサービス」について、企画案と考察をまとめました。   ...

本当に価値のある宣伝方法 〜多くの人が実践している【間違った努力】とは〜
マーケティング
Facebook,note,Twitter,YouTube,集客
本当に価値のある宣伝方法 〜多くの人が実践している【間違った努力】とは〜

  YouTubeやTwitter、Facebookやnoteなど、いろんなサービスを使った集客方法があります。集客という視点ではなく、それ自体に人を集めたいという人も多いでしょう。   フォロワーやチャンネル登録者数を増やすために、多くの人が様々な取り組みをしていますが、その中でもひときわ意味のないことをただ繰り返して...

PHPポケモン「バトルシステム実装編〜タイプ相性の判定〜」デモ&配布有り 19
プログラミング
jQuery,PHP,PHPポケモン,ポケモン
PHPポケモン「バトルシステム実装編〜タイプ相性の判定〜」デモ&配布有り 19

  システムを組むなら、仕様書や設計書はしっかり作りましょう。   ということで、またまたフォルダ移動やページ分けなどを見えないところでやりました。正直説明すると全く進まなくなりそうなので、改修部分は必要最低限にします。 結論、説明しません。(コード配布するので許してください)   そして今...

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

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

PHPポケモン「技クラス実装編」14
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「技クラス実装編」14

  前回せっかくBootstrapを使って見た目を整えたにも関わらず、ビューポートの記述が抜けているという凡ミスが発覚したので修正しています。 サーセン。   今回のPHPポケモンでは本格的な技システムを実装していきます。技システムが整えば、皆さん期待のバトルシステムも間近です。セキュリティ面やファイル構成...

わざマシン編 忘れさせる技の選択 PHPポケモン106
プログラミング
PHP,PHPポケモン,ポケモン
わざマシン編 忘れさせる技の選択 PHPポケモン106

忘れさせる技の選択 わざマシンによる技習得処理を作成しましたが、既に覚えている技が4つあると、モーダルが表示されて選択をしても習得することができません。これは、技習得用のサービスがホーム画面には用意されていないからです。 なので今回は、わざマシンを使った際の技の入れ替え処理を実装していきましょう...

【Laravel7】既存makeテンプレートのカスタマイズ Requestサンプル有り
プログラミング
Laravel,Linux,PHP
【Laravel7】既存makeテンプレートのカスタマイズ Requestサンプル有り

  Laravel7では新しい機能が様々導入されており、Webアプリケーションの開発がよりスムーズなものとなってきています。その中でも、もどかしい場所へ手を届いたと感じさせてくれたのが、既存makeコマンドのstubを簡単にカスタマイズできるようになったことです。   今回は既存make用stubの取得コマンドと、リ...

データ軽量化編 β版へ向けて  PHPポケモン 90
プログラミング
PHP,PHPポケモン,ポケモン
データ軽量化編 β版へ向けて PHPポケモン 90

β版の実装に向けて 大型アップデートにより、ある程度機能改善や実装箇所も増えてきましたが、それと同時に次の段階への移行が本格的に見えてきました。それがβ版です。   PHPポケモンは2020年12月現在α版となっており、完全な試作段階のWEBアプリケーションです。セーブ機能はなく、セッションの有効期...

カテゴリ

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