プログラミング

進化直後の技習得編 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進化ポケモンの強さがよく分かる瞬間でした。

 

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

 

注目の記事

YouTuber・ブロガー必見!知る人ぞ知るサムネイルの重要性とは
デザイン
Facebook,Instagram,Twitter,YouTuber,サムネイル,ブロガー
YouTuber・ブロガー必見!知る人ぞ知るサムネイルの重要性とは

  サムネイルって本当に重要? ブログの場合はフリー画像でもいいんじゃない?   そう考えている人はいませんか? 残念ですが、それは大きな間違いです。サムネイルを作り込むことは非常に重要であり、集客ポイントを拡大させるのはもちろん、ブランディングにもつながるのです。   今回は「知る人ぞ...

PHPポケモン「技ポイント(PP)編」36
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「技ポイント(PP)編」36

技ポイント(PP)とは ポケモンではそれそれの技に使用回数が定められています。それが技ポイント(PP)と呼ばれているものです。 PP(ポケモンwiki) https://wiki.ポケモン.com/wiki/PP   技のクラスを実装した際に、それぞれにppというプロパティをもたせて回数をセットしています。これが、対象の技...

config実装編(ドット記法・多次元配列) PHPポケモン 71
プログラミング
PHP,PHPポケモン,ポケモン
config実装編(ドット記法・多次元配列) PHPポケモン 71

configファイルの作成 プログラミングでは設定値というものを使うことが良くあります。量が多い場合はデータベースへ格納して管理する場合も多いですが、わざわざテーブルを用意してまで格納するほどのものでなければ、ファイルに配列として定義してアクセスできる方が便利です。フレームワークではこれらをconfigフ...

迷惑メールはなぜ届く?amazonや楽天を騙る悪質メールへの対処法とは
ネットワーク
amazon,スパム,メール,楽天
迷惑メールはなぜ届く?amazonや楽天を騙る悪質メールへの対処法とは

「いきなり迷惑メールが届くようになった」 「Amazonや楽天を装ったメールはどうやって見分ければいいの?」   知らない人からいきなり連絡が届いたり、登録もしていないようなサービスからメールが届けば、それは詐欺メールかも知れません。 スマホやパソコンが一般的に普及して、ネットでの買い物やサービスを利用...

初心者向けのブログで稼ぐ方法【アフィリエイト編:Google AdSense】
SEO対策
Google AdSense,アフィリエイト,クリック単価,クリック数,ブログ,広告収入
初心者向けのブログで稼ぐ方法【アフィリエイト編:Google AdSense】

  ブログを始めたほとんどの人が アフィリエイトで稼ぎたい   という強い思いを持っているのではないでしょうか。しかし現実は厳しく、広告の審査さえ通らず挫折してしまうといったことは多いです。 中には審査が通っているが、全然広告収入が得られないという人もいるでしょう。 毎日ブログを書いているの...

毎日継続をするためのコツ
雑記
毎日継続をするためのコツ

定期的にコラムを書きたくなるので、今回は「毎日継続をするためのコツ」というテーマで自分が意識していることや、感じたことを書き綴っていきます。 決して開発や業務で追われていたり、PHPポケモンの大幅見直しを迫られているわけではありません。   毎日継続するために  ブログや学習など、毎日継続...

プログラミングとは?現役システムエンジニアが教える裏事情
プログラミング
システムエンジニア,プログラマー
プログラミングとは?現役システムエンジニアが教える裏事情

  プログラミングってよくわからない? 実際に何をやっているの?   最近注目されているSE(システムエンジニア)やPG(プログラマー)という職業ですが、「そもそもプログラミングとは?」といった疑問を抱えている方も多いですね。 今回は、そういった方へ向けて「プログラミングの基礎知識と裏事情」...

HPバーアニメーション 後編 フロント側の対応 PHPポケモン 44
プログラミング
PHP,PHPポケモン,ポケモン
HPバーアニメーション 後編 フロント側の対応 PHPポケモン 44

HPバーアニメーション それでは前回に続き、HPバーのアニメーションづくりをしていきましょう。前回、メッセージに合わせてレスポンスを返却するというサーバー側の仕組みを作成しました。なので、今回はそれをフロント側で受け取り、タイミングよくアニメーションで再現します。   フロント側(js)の処理 前回...

カテゴリ

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