プログラミング

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

 

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

 

注目の記事

SNSだけじゃダメ!PV数アップのためにSEO対策する理由とは
SEO対策
Twitter
SNSだけじゃダメ!PV数アップのためにSEO対策する理由とは

  「SNSで集客しているけど中々伸びなくなってきた」 「たまにPV数がアップするけど安定しない」 「本当に月何十万も稼げるぐらいPVは伸びるの?」   PV数を稼ぐためにSNSを駆使したり、中には広告を使って集客しているサイトもあるでしょう。ですが、それだけでは疲弊しながらユーザーを獲得しているに...

へんしん編 PHPポケモン 74
プログラミング
PHP,PHPポケモン,ポケモン
へんしん編 PHPポケモン 74

へんしんとは 今回はサムネイルに合わせて、特別技の1つ「へんしん」を実装します。  へんしん https://wiki.ポケモン.com/wiki/へんしん   へんしんを使うことで、相手ポケモンをコピーすることができますが、その全てをコピーするわけではありません。コピーできる項目とそうでない項目は以下の通りで...

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

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

パーティーの並び替え編 PHPポケモン 82
プログラミング
PHP,PHPポケモン,ポケモン
パーティーの並び替え編 PHPポケモン 82

パーティーの並び替え ポケモンをバトルに選出する際に欠かせないのが「パーティーの並び替え」です。パーティーの先頭(ひんし状態でない)がポケモンでは自動的に選択されるため、戦闘前に並び替えをしておく必要があります。 ゲーム上では簡単に見える処理ですが、これがPHPで行うとなれば少し厄介な問題が出てき...

稼ぐためには必ず知っておきたい100日継続法【100日坊主になりなさい】
雑記
稼ぐためには必ず知っておきたい100日継続法【100日坊主になりなさい】

  YouTubeやnoteで収益を上げたい   今やレッドオーシャンと呼ばれるそれらは、多くの人が挑戦して諦めてしまい、結局は上層が勝ち続けるという構造が揺らぎません。 しかし、多くの人は諦めるのが早すぎて、実際に結果が出るかも知れないものを断念しているのがほとんどです。 今回は、そういった人た...

ポケモン預かりシステム編 システムの実装 PHPポケモン 87
プログラミング
PHP,PHPポケモン,ポケモン
ポケモン預かりシステム編 システムの実装 PHPポケモン 87

ポケモン預かりシステムの実装 システムの仕様とクラスも整ってきたので、いざ実装をしていきましょう。 前回までに作成した項目で、いくつか変更になったものがあるので、まずはじめに挙げておきます。   シャットダウン機能 ボックスの選択を解除するというものでしたが、こちらを不採用にしました。ボックスは...

20代の独立が成功のカギ【学生→フリーランス・起業は危険です】
フリーランス
フリーランス,独立,起業
20代の独立が成功のカギ【学生→フリーランス・起業は危険です】

  終身雇用のほとんどが崩壊している今、学生の頃から独立や起業を考えている人は多いですが、安易な決断は危険です。 独立するには早すぎるのも良いとは言えず、また遅すぎることもそれなりにリスクです。 SNSやメディアでも学生起業などが騒がれていますが、それに影響されてしまうのはかなり危険なことです...

進化の石編(構成) PHPポケモン 102
プログラミング
PHP,PHPポケモン,ポケモン
進化の石編(構成) PHPポケモン 102

進化の石 ピカチュウさんもそろそろ進化したがっているので、β版の公開に向けて進化の石を実装していきます。しかし、イーブイなど特別な進化先や条件を持ったポケモンを考慮すると、少し実装が手間取りそうだったので、今回は構成部分のみのまとめとなっておりますので、ご了承ください。   アイテムクラスの作...

カテゴリ

SEO対策 イベント デザイン ネットワーク ビジネスモデル フリーランス プログラミング マーケティング ライティング 動画編集 雑記

タグ

5G Adobe AfterEffects AI ajax amazon Animate api artisan atom Automator AWS Bluetooth CSS CVR description EC-CUBE4 ECショップ ESLint Facebook feedly foreach fortify function Google Google AdSense Honeycode htaccess HTML IEEE 802.11ax Illustrator Instagram IoT JavaScript jetstream jQuery jQuery UI keyword LAN Laravel Linux MacBook MAMP meta MLM MySQL NoCode note OS OSI参照モデル Paypal Photoshop PHP phpMyAdmin PHPポケモン PremierePro rss 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 独立 神戸 福祉 秘密鍵 翻訳 自己啓発 英語 見積書 計算機 認証 読書 起業 迷惑メール 配列 銀の弾丸 集客 雑学力