プログラミング

PHPポケモン「技ポイント(PP)編」36

PHP PHPポケモン ポケモン
PHPポケモン「技ポイント(PP)編」36

技ポイント(PP)とは

ポケモンではそれそれの技に使用回数が定められています。それが技ポイント(PP)と呼ばれているものです。

PP(ポケモンwiki

 

技のクラスを実装した際に、それぞれにppというプロパティをもたせて回数をセットしています。これが、対象の技を使える基本最大回数です。もしすべての技の使用回数がなくなってしまうと、技を使うことができなくなるため前回実装した「わるあがき」が発動します。

 

PPを管理するためにも、現在ポケモンに対して格納している技(move)のプロパティの格納形式を、以下のような多次元連想配列に変更します。

 

ポケモンクラスの技プロパティ
$move = [
    0 => [
        'class' => 技クラス名(string),
        'remaining' => 残り回数(integer),
        'correction' => 補正値(integer),
    ],
];

 

classキーの値には、今まで値として格納していた技クラス名が入ります。では追加された残りの2つを見ていきましょう。

 

残り回数

remainingキーに割り当てられている値は、技の残り回数です。「でんきショック」であれば、基本最大使用回数が30回なので、全回復状態で1度技を使えば、残りは29回となります。この数を格納して置かなければ、あと何回使用できるかがチェックできませんよね。

技を習得した時点では、残り回数はその技の最大数が格納されます。でんきショックであれば、覚えた段階の残り回数は30回となります。

 

補正値

correctionキーに割り当てられている値は、技の最大回数に対する補正値です。ポイントアップなどのアイテムを使うと、技の上限回数を増やすことができます。

最大PPの増え方には3段階あり、1段階ごとに元のPP1/5増え、最大まで上げれば元のPP8/5(=1.6)となる

 

補正値の初期値は0です。現段階では補正値を増やす手段はありませんが、こちらも今後実装するものと考え用意しました。残り回数の算出も、補正値の概念が存在するものとして作成していきます。

 

 

それでは、ポケモンの技プロパティが変更したことによって修正しなければならない箇所を1つずつ対応していきましょう。まずは技クラスからです。

 

技クラス(/Classes/Move.php
/**
* 使用回数の取得
*
* @param integer $correction 補正値
* @return integer
*/
public function getPp(int $correction=0)
{
    return $this->pp + (int)(floor($this->pp / 5) * $correction);
}

 

使用回数の取得メソッド(getPp)に補正値の計算を追加しました。引数に補正値をセットすると、最大回数に補正値x20%数を加算して返却しています。ポケモンの技回数は5区切りのため、小数点以下の数値が出ることはありませんが、念の為切り捨て処理を行なっています。

 

次に技の習得処理を修正します。

 

Set格納トレイト(/Traits/Pokemon/SetTrait.php
/**
* 初期技をセットする
* @return void
*/
protected function setDefaultMove()
{
    foreach($this->level_move as list($level, $move)){
        if($level <= $this->level){
            // 現在レベル以下の技であれば習得
            $this->setMove(new $move);
        }else{
            // 現在レベルを超えていれば処理終了
            break;
        }
    }
}
 
/**
* 技を覚える
* @return object Move
*/
protected function setMove($move)
{
    $this->move[] = [
        'class' => get_class($move),
        'remaining' => $move->getPp(),
        'correction' => 0,
    ];
    if(count($this->move) > 4){
        // 技が4つを超過していれば、一番上を忘れさせる
        unset($this->move[0]);
        // 技の添字を採番する
        $this->move = array_values($this->move);
    }
}

 

ポケモンが持つmoveプロパティの構造が変更になったので、それに合わせた形式でセットするようにsetMoveメソッドを変更しました。引数は今までクラス名(string)で受け取っていましたが、オブジェクトで受け取る仕様に変更しました。remainingには先程作成したgetPpを引数無しで格納し、補正値であるcorrectionには0をセットしています。

 

setMovedefaultMoveメソッド内で呼び出しているので、引数にオブジェクトを渡せるように、newをつけておきましょう。

 

次に覚えている技を取得するメソッド(getMove)を修正します。

 

Get格納トレイト(/Traits/Pokemon/GetTrait.php
/**
* 覚えている技の一覧を取得する
* @param integer $num
* @param string
* @return array
*/
public function getMove($num=null, $param='')
{
    if(is_null($num)){
        // 全返却
        if($param === 'array'){
            // 配列(加工不要)で返却
            return $this->move;
        }else{
            // array_mapで配列内の技クラスをオブジェクト化して返却
            return array_map(function($move){
                // 無名関数
                return [
                    'class' => new $move['class'],
                    'remaining' => $move['remaining'],
                    'correction' => $move['correction'],
                ];
            }, $this->move);
        }
    }else{
        // 番号指定で返却
        $move = $this->move[$num] ?? $this->move[0];
        if($param === 'array'){
            // 配列(加工不要)で返却
            return $move;
        }else{
            // オブジェクトにして返却
            return new $move['class'];
        }
    }
 
}

 

最後に技の一覧出力方法を修正して、残りPPが確認できるようにしておきましょう。

 

ホーム画面詳細モーダル(Resources/Partials/Home/Modals/details.php
<div class="tab-pane fade show" id="move" role="tabpanel" aria-labelledby="move-tab">
    <?php # 覚えている技 ?>
    <table class="table table-bordered table-sm table-hover">
        <thead class="thead-light">
            <tr>
                <th scope="col">覚えている技</th>
                <th scope="col">タイプ</th>
                <th scope="col">PP</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach($pokemon->getMove() as $move): ?>
                <tr class="move-detail-link" data-target="#move_<?=get_class($move['class'])?>-content">
                    <th scope="row" class="w-50"><?=$move['class']->getName()?></th>
                    <td><?=$move['class']->getType()->getName()?></td>
                    <td><?=$move['remaining']?>/<?=$move['class']->getPp($move['correction'])?></td>
                </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
    <?php # 技説明 ?>
    <div class="overflow-auto p-3 border" style="height:160px;">
        <?php foreach($pokemon->getMove() as $key => $move): ?>
            <div class="move-detail-content <?php if(array_key_first($pokemon->getMove()) == $key) echo 'active'; ?>" id="move_<?=get_class($move['class'])?>-content">
                <h6><?=$move['class']->getName()?></h6>
                <hr>
                <p><?=$move['class']->getDescription()?></p>
            </div>
        <?php endforeach; ?>
    </div>
</div>

 

 

初期状態では技ポイントが減っていないので、数値から判断することは出来ませんが、エラーが出ていないことが確認できればOKです。

詳細と同じように、バトル画面でのPP表示も残数が出力されるよう変更しておきましょう。

 

バトルシステムへの導入

それでは、バトルシステムにPPを導入していきます。通常、すべての技PPが0回であれば技選択ができず、「たたかう」を選んだ時点でわるあがきが発動しますが、まずは技PPが減る処理と、使用時に技ポイントが残っているかどうかを確認して、なければ「わるあがき」が発動するという処理を実装しましょう。

  

使用可不可の判定

 まずは技の使用可不可の判定です。こちらを行動チェックの直後に追加しましょう。

 

攻撃用トレイト(/Traits/Battle/AttackTrait.php
/**
* 攻撃
* (攻撃→ダメージ計算→ひんし判定)
*
* @param object $atk_pokemon
* @param object $def_pokemon
* @param object $move
* @return void
*/
protected function attack($atk_pokemon, $def_pokemon, $move)
{
    // 行動チェック(状態異常・状態変化)
    if(!$this->checkBeforeSa($atk_pokemon) || !$this->checkBeforeSc($atk_pokemon)){
        // 行動失敗
        return;
    }
    // わざの使用可不可判定
    if(!$this->checkEnabledMove($move, $atk_pokemon)){
        $this->setMessage($atk_pokemon->getPrefixName().'は出すことのできる技がない');
        // わるあがきをセット
        $move = new Struggle;
    }
    // チャージチェック
    if($move->charge($atk_pokemon)){
        // チャージターンならメッセージを格納して行動終了
        $this->setMessage($atk_pokemon->getMessages());
        $atk_pokemon->resetMessage();
        return;
    }

 

checkEnabledMoveというメソッドを使い、使える技かどうかを確認しています。ここで使えない技だと判定された場合は、わるあがきをセットして以降の処理を進めていきます。

 

では、新しく作成したcheckEnabledMoveメソッドの処理を見てみましょう。

 

チェック用トレイト(/Traits/Battle/CheckTrait.php
/**
* 技の使用可不可判定
*
* @param object $move Move
* @param object $pokemon Pokemon
* @return boolean (true: 使用可, false:使用不可(わるあがき))
*/
protected function checkEnabledMove(object $move, object $pokemon)
{
    $move_class = get_class($move);
    if($move_class === 'Struggle'){
        // わるあがき
        return false;
    }
    // ポケモンの技一覧
    $move_list = $pokemon->getMove(null, 'array');
    // 選択された技の添番を取得
    $num = array_search(
        $move_class,
        array_column($move_list, 'class'),
    );
    // PP残数の確認
    if($move_list[$num]['remaining'] > 0){
        // 使用可能
        // チャージターンは残PPそのまま
        if(!$this->checkChargeTurn($pokemon, $move)){
            // 残PPをマイナス1
            $pokemon->calRemainingPp('sub', 1, $num);
        }
        return true;
    }else{
        // 使用不可
        return false;
    }
}
 
/**
* チャージターンかどうかの確認
*
* @param object $pokemon
* @param object $move
* @return boolean
*/
protected function checkChargeTurn($pokemon, $move)
{
    // チャージ技ではない
    if(!$move->getChargeFlg()){
        return false;
    }
    // 状態変化を取得
    $sc = $pokemon->getSc();
    // 現在未チャージ状態
    if(!isset($sc['ScCharge'])){
        // チャージターン
        return true;
    }
    // 残チャージターン数が1超過
    if($sc['ScCharge']['turn'] > 1){
        // チャージターン
        return true;
    }
    // チャージターンではない
    return false;
}

 

最初に技が「わるあがき」かどうかをチェックしています。これは技選択がされなかった場合にわるあがきが選択された状態で処理に入るため、最初にチェックをして該当すればfalseを返却し、そのままわるあがきを実行してもらいます。

 

その後、技ポイントのチェックをして使用回数が残っていれば、残りPPをマイナス1して使用可(true)、もし残数が残っていなければ使用不可(false)を返却しています。ただし、チャージ技の場合、チャージターンに技ポイントが引かれてしまうと1回の使用でPPが2減少してしまうため、checkChargeTurnというメソッドを使ってこのターンがチャージターンかどうかを確認しています。

 

※多次元配列のキーを使った検索方法(array_searchとarray_columnの組み合わせ)は以下の記事にまとめているので参考にしてください

【PHP】可変長引数とは「点(ドット)3つ」 多次元連想配列の検索 【PHP】可変長引数とは「点(ドット)3つ」 多次元連想配列の検索

可変長引数とは  引数の数が決まっていない、状況に応じて複数の引数を指定したいときに、関数の引数で指定する点(ドット)3つのことです。PHP5.6以降で使用することができます。  PHPマニュアル 可変長引数リスト https://www.php.net/manual/ja/functions.arguments.php#functions.variable-arg-list ...

  

残りポイントの計算

次に、残りPPを変更するために使っているcalRemainingPpメソッドの処理を見ていきましょう。こちらは残りHPを取得する処理と同じように、引数を指定することで加算とリセットができるようにしています。

 

計算用トレイト(/Traits/Pokemon/CalculationTrait.php
/**
* 残りPPの計算
*
* @param string $param
* @param integer $val (default:0)
* @param integer $num (default:null)
* @return integer
*/
public function calRemainingPp(string $param, int $val=0, $num=null)
{
    switch ($param) {
        // リセット処理
        case 'reset':
        if(is_null($num)){
            // すべてのPPを全回復
            foreach($this->getMove() as $key => $move){
                $this->move[$key]['remaining'] = $move['class']->getPp($move['correction']);
            }
        }else{
            // 指定された技PPを全回復
            $this->move[$num]['remaining'] = $this->move[$num]
            ->getPp($this->move[$num]['correction']);
        }
        break;
        // 減算処理
        case 'sub':
        if(is_null($num)){
            // すべてのPPに減算処理
            foreach($this->move as $key => $move){
                $this->move[$key]['remaining'] -= $val;
                if($this->move[$key]['remaining'] < 0){
                    // 最小値の処理
                    $this->move[$key]['remaining'] = 0;
                }
            }
        }else{
            // 指定された技PPに減算処理
            $this->move[$num]['remaining'] -= $val;
            if($this->move[$num]['remaining'] < 0){
                // 最小値の処理
                $this->move[$num]['remaining'] = 0;
            }
        }
        break;
        // 加算処理
        case 'add':
        if(is_null($num)){
            // すべてのPPに加算処理
            foreach($this->getMove() as $key => $move){
                $this->move[$key]['remaining'] += $val;
                if($this->move[$key]['remaining'] > $move['class']->getPp($move['correction'])){
                    // 最大値の処理
                    $this->move[$key]['remaining'] = $move['class']->getPp($move['correction']);
                }
            }
        }else{
            // 技をインスタンス化
            $move = new $this->move[$num];
            $this->move[$num]['remaining'] += $val;
            if($this->move[$num]['remaining'] > $move->getPp($this->move[$num]['correction'])){
                // 最大値の処理
                $this->move[$num]['remaining'] = $move->getPp($this->move[$num]['correction']);
            }
        }
        break;
    }
}

 

リセットが選択された場合はすべての技PPを全回復(補正値を含めた最大PPをセット)、加算と減算では指定された値の計算結果をそれぞれセットしています。残りHPの計算処理とは異なり、どの技のPPを変更するかを指定できなければならないため、第3引数では技番号(添え番)を受け取っています。

分岐の関係上、記述量が多くなっていますが、処理自体は加算減算後に上限下限を確認しているという至って簡単な処理となっています。

 

それでは、実際に技を使って確認してみましょう。

 

 

 

 

 

 

 

 

戦闘終了後、使った技のPPが使用回数分減っていることが確認できました。これでPPシステムの実装は完了です。

 

まとめ

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

今回のPHPポケモンでは「技ポイント(PP)システムの導入方法」をご紹介しました。

PHPポケモンではDBを使用しないため、クラスのプロパティを活用していますが、DB構造などが変更になればそれだけ修正しなければならない箇所が多いということがわかりますね。それだけ開発では設計が重要なのです。

現在プログラミングを学習中の方は、ぜひ参考にしてみてくださいね。

 

注目の記事

PHPポケモン「2進化ポケモン実装編」8
プログラミング
PHP,PHPポケモン,プログラミング学習,ポケモン
PHPポケモン「2進化ポケモン実装編」8

  記念すべき?第8回目で遂にタイトル変更です。 (旧)ピカチュウから学ぶオブジェクト指向 (新) PHPポケモン   機能増設によりオブジェクト指向云々より、PHP学習がメインになったので泣く泣く変更です。(今の所)順調に続いているのも、多くの方?が見てくれているおかげです。感謝感激雨ア...

【変数とは】初心者が最短でPHPを使えるようになるための実践的な学び方
プログラミング
HTML,PHP,プログラミング学習
【変数とは】初心者が最短でPHPを使えるようになるための実践的な学び方

  ※PHP初心者へ向けた内容となりますので、ある程度HTMLの知識がある方を対象とした内容になります。予めご了承ください。    Webプログラミングを学ぶ方はHTML、そしてCSSを学び、そしてJavascriptやPHPという順に学んでいくひとが多いでしょう。 私も実際に、似たような手順で学んでいきました。   ...

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

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

フリーランスのための値段交渉術!案件はこうやって見極めろ
フリーランス
フリーランスのための値段交渉術!案件はこうやって見極めろ

  「これもっと安くならない?」 「他の人はこれぐらいの金額でやってくれるよ」   こういった値切り交渉を受けたことがある人もいるのではないでしょうか?技術を提供するフリーランスであれば、金額を落とすということは自分の価値を下げているということを理解しておかなければなりません。 値段交渉...

XserverにSequel ProでSSH接続する方法を4ステップでわかりやすく解説
ネットワーク
phpMyAdmin,Sequel Pro,SSH,Xserver,データベース,公開鍵,秘密鍵
XserverにSequel ProでSSH接続する方法を4ステップでわかりやすく解説

  AWSなどが注目される中、Xserver(エックスサーバー)は操作やセットアップが簡単で、ポートフォリオや業務、個人ブログ(WordPess)で使用している方に需要が高いサービスです。 そしてMacのPCを使っている方はデータベースの管理ツールとして、無料で使えるSequel Proが人気があり、多くのユーザーが使用し...

捕獲処理実装編 PHPポケモン 80
プログラミング
PHP,PHPポケモン,ポケモン
捕獲処理実装編 PHPポケモン 80

捕獲処理の作成 前回モンスターボールのクラスを作成したので、今回は捕獲判定までの一連の処理を仕上げていきます。サービス自体は他のアイテムと一緒にするためItemServiceを呼び出し、その中で使用されたアイテムを判断して分岐を作ります。   バトル中のアイテムサービス(/App/Services/Battle/ItemService.ph...

独立してから心がけていること【社会人時代と比較して】
フリーランス
フリーランス,独立
独立してから心がけていること【社会人時代と比較して】

  今回は自分が独立してから心がけていることの中から、ある程度上手くいっていることや、オススメできるようなことを簡単に感想付きでまとめてみました。 社会人時代と比較しながらの内容なので、これからフリーランスで生きていこうと思っている人や、社会人という生活にストレスを感じている人は是非参考に...

フィールド効果技編(しろいきり) PHPポケモン 50
プログラミング
PHP,PHPポケモン,ポケモン
フィールド効果技編(しろいきり) PHPポケモン 50

フィールド効果技とは ポケモンの技の中には、ポケモンに対して状態変化や異常を与えるもの以外に、フィールド自体に効果を持たせるものがいくつかあります。PHPポケモンでは未実装ですが、そういったフィールド効果技はポケモンを交代したとしても場に効果が残り続けます。  場の状態(ポケモンwiki) https:/...

カテゴリ

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