プログラミング

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

 

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

 

注目の記事

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

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

オブジェクト指向有効活用編 PHPポケモン 93
プログラミング
PHP,PHPポケモン,ポケモン
オブジェクト指向有効活用編 PHPポケモン 93

オブジェクト指向の有効活用 β版に向けたPHPポケモンの構成見直し、今回は「オブジェクト指向」の役割について、より理解を深めつつ、保守性も良くなるように整えていきます。   機能を持たせる 様々なプロパティを定数や静的変数へ以降していますが、今回は「静的メソッド」の活用範囲を増やしていきます。まず...

フリーランスなら心がけておきたい3つのルール【仕事と遊びは両立させろ】
フリーランス
フリーランス,独立
フリーランスなら心がけておきたい3つのルール【仕事と遊びは両立させろ】

  フリーランスになっても不安がいっぱい   会社というものに縛られないというのは楽なイメージがありますが、それ相応の不安がついてまわります。 その結果、会社員へと舞い戻ってしまうと再度そこから抜け出すことは非常に困難です。   今回は、現在活動している人や、これから独立しようとしている...

動画にカラオケテロップを入れる編集方法【AfterEffectsで色変わりの文字】
動画編集
Adobe,AfterEffects
動画にカラオケテロップを入れる編集方法【AfterEffectsで色変わりの文字】

  動画に声と同じタイミングでテロップを入れたい カラオケのような文字はどうやっていれればいいの?   一見簡単に見えるものも、いざ導入しようとすればどうやればいいかわからない、そんなこと多いのではないでしょうか? 今回はAdobe AfterEffectsを使った方法をご紹介します。些細な編集が動画のク...

放物線アニメーション編 PHPポケモン 81
プログラミング
PHP,PHPポケモン,ポケモン
放物線アニメーション編 PHPポケモン 81

ボールアニメーション 前回までに作成した捕獲判定処理を使って、ボールのアニメーションを作成します。 捕獲演出は以下の通りです。  味方側から相手に向かってボールを投げる 相手ポケモンの前でボールを開く 捕獲判定で算出した揺れ回数分ボールを揺らす   捕まえた際は、ボールの揺れをストップ...

HPバーアニメーション前編 サーバー側の対応 PHPポケモン 43
プログラミング
PHP,PHPポケモン,ポケモン
HPバーアニメーション前編 サーバー側の対応 PHPポケモン 43

動きのあるHPバーづくり それではデモ公開に先立ち、HPバーの作り込みをしていきたいと思います。 現在のPHPポケモンは、ダメージ計算などが終わった結果をすべて返却しているため、技選択をして次の画面に移行すると、HPが減った状態でスタートしていました。これでは、どの技でどれぐらいのダメージを与え、状態変...

アーカイブのディスクリプションを管理画面で設定する方法【SEOに強いWordPressブログ・サイト作り】
プログラミング
PHP,SEO,WordPress
アーカイブのディスクリプションを管理画面で設定する方法【SEOに強いWordPressブログ・サイト作り】

  WordPressで作ったサイトやブログはSEO対策がしやすいという利点があり、より検索に強いサイトへ仕上げることができます。 ですが、SEO対策に特化しているテーマでもアーカイブページのディスクリプション設定ができないものは多く、別で設定する必要があるものがほとんどです。   今回は、より検索で強く...

ダメージ固定技編(ちきゅうなげ・カウンター) PHPポケモン 41
プログラミング
PHP,PHPポケモン,ポケモン
ダメージ固定技編(ちきゅうなげ・カウンター) PHPポケモン 41

ダメージ固定技とは PHPポケモンでも作成したダメージ計算機能ですが、ポケモンの技の中にはそれを必要としない技がいくつかあります。それが「固定ダメージ技」です。 ポケモンwiki(ダメージ固定技) https://wiki.ポケモン.com/wiki/ダメージ固定技 ステータスに依存せず、わざ自体にダメージ量が決...

カテゴリ

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