プログラミング

PHPポケモン「バトルシステム編〜経験値の獲得〜」29

PHP PHPポケモン ポケモン
PHPポケモン「バトルシステム編〜経験値の獲得〜」29

経験値の獲得

今まではポケモンに直接経験値を与えるというチートびっくりの仕様でしたが、バトルシステムも終盤に差し掛かってきたので「倒したポケモンから経験値を取得する」というごく当たりまえの仕様を導入していきます。

 

基礎経験値の設定

では、経験値の計算式に入る前に、必要なパラメーターを1つ用意しましょう。それは「基礎経験値」についてです。

 

毎度ながらポケモンwikiさんご協力(というより参考)の元、実装していきます。

ポケモンにはそれぞれ基礎経験値というものが割り当てられており、そのポケモンを倒した際にその値を元に計算がなされます。同じレベルでも、キャタピーを倒すよりトランセルを倒した方が経験値が高いというのは、この基礎経験値が影響しているためです。

 これはポケモンそれぞれに割り当てる必要があるので、各ポケモンのクラスにbase_exというプロパティを追加して、初期値に表の値をセットしていきましょう。

 

フシギダネ(/Classes/Pokemon/Fushigidane.php
/**
* 基礎経験値
* @var integer
*/
protected $base_exp = 64;

 

サンドバック野生ポケモンとして固定出現してくださるフシギダネさんに基礎経験値である64を割り当てました。上書きすることはない値のため、取得用メソッドのみGet格納トレイトに追加しましょう。

 

Get格納トレイト(/Traits/Pokemon/GetTrait.php
/**
* 基礎経験値を取得する
* @return integer
*/
public function getBaseExp()
{
    return $this->base_exp;
}

 

これで経験値の計算に必要な値が揃いました。

 

獲得経験値の計算

次に経験値の計算です。

経験値の計算方法は、世代を経るごとに大きく修正が加えられています。ダメージ計算などとは違い、旧式の計算方法を再採用したり、さらに新計算方法に戻すなど時代の変化に合わせながら実験的に導入されているようにも感じさせます。

 

PHPポケモンでは、最新世代(第8世代)を参考にカスタムします。まずはwikiに掲載された経験値の仕様を確認してみましょう。

 

 

第五世代、第七世代、第八世代

こちらでは、倒したポケモンのレベルも経験値を変化させるパラメータとして登場する。

経験値 = (EXP × A × レベル補正^2.5 + 1) × B × C × D

 

  • EXP : 倒されたポケモンのレベル × 倒されたポケモンの基礎経験値 ÷ 5
    レベル補正 = (2L + 10) / (L + Lp + 10)
  • L : 倒されたポケモン
  • Lp : 倒したポケモン
  • A : (第五世代のみ)トレーナー戦なら1.5、それ以外は1。第七世代では常に1
  • B : デルパワー・ロトポンの効果。けいけんちパワー+1.2++1.5+++2.00.80.660.5。けいけんポンは1.5
  • C : 他言語版と交換したポケモンは1.7、同言語と交換したポケモンは1.5、おやが自分であれば1
  • D : しあわせタマゴを持っていれば1.5、それ以外は1

 

経験値を貰えるポケモンが複数匹いる場合、 

  • 第五世代 : EXP × A」をその匹数で割り、その値を「EXP × A」の代わりに使ってそれ以降の計算を行う。
  • 第七世代 : 匹数で割ることはなく、貰えるポケモンそれぞれに上記の計算を行う。

 

まず、Aの値についてですが、トレーナー戦か野生かで経験値の獲得量に変化があるようです。これは第5世代のみ導入されていた計算方式のため、関係なく1をセットするものとして不要とします。

 

次にBCDについてです。デルパワーなど経験値補正仕様はもちろん実装せず、ポケモンの交換も今の所実装予定はなく、持ち物も現段階はスルーする予定なのですべて不要とします。

 

複数匹いる場合の割り振り処理についてですが、最新世代では所有ポケモン全員に獲得経験値が割り当てられるという仕様が採用されていました。ですが、これに関しては採用せず登場したポケモンだけが経験値をもらえるという方式を採用予定です。現在は複数匹所有のロジックがまだ出来ていませんので、一旦保留としましょう。

 

以上を踏まえ、今回採用する経験値の計算式は以下の通りです。

経験値 = (EXP × レベル補正^2.5 + 1)

 

それでは、前回追加したひんし判定(checkFainting)のメソッド内に経験値計算と獲得処理を追加しましょう。

 

チェック格納トレイト(/Traits/Battle/CheckTrait.php
/**
* ひんし判定
*
* @param object $pokemon
* @return boolean
*/
protected function checkFainting($pokemon)
{
    if($pokemon->getSa() === 'SaFainting'){
        // ひんし状態
        $this->setMessage($pokemon->getPrefixName().'は倒れた');
        if($pokemon->getPosition() === 'friend'){
            // 味方がひんし状態になった
            $this->setMessage('目の前が真っ暗になった');
        }else{
            // 相手をひんし状態にした
            // 経験値の計算
            $exp = $this->calExp($this->pokemon, $this->enemy);
            // 経験値をポケモンにセット(返り値をpokemonに格納)
            $this->pokemon = $this->pokemon
            ->setExp($exp);
            // ポケモンに溜まったメッセージを取得
            $this->setMessage($this->pokemon->getMessages());
        }
        // バトル終了判定用メッセージの格納
        $this->setMessage(' ', 'battle-end');
        return true;
    }else{
        // ひんし状態ではない
        return false;
    }
}

 

相手ポケモンをひんし状態にした後、取得経験値をcalExpというメソッドを使い算出し、setExpを使って勝利ポケモンに経験値を与えています。

 

ではcalExpという経験値計算用のメソッドをバトルコントローラー内に作成しましょう。

 

バトルコントローラー(Classes/Controller/BattleController.php
/**
* 経験値の計算
* (EXP × LM^2.5 + 1)
*
* @var EXP 倒されたポケモンのレベル × 倒されたポケモンの基礎経験値 ÷ 5
* @var LM レベル補正 (2L + 10) / (L + Lp + 10)
* @var L 倒されたポケモン($lose)のレベル
* @var Lp 倒したポケモン($win)のレベル
*
* @param object $win Pokemon
* @param object $lose Pokemon
* @return integer
*/
protected function calExp($win, $lose)
{
    // EXP
    $exp = $lose->getLevel() * $lose->getBaseExp() / 5;
    // レベル補正
    $lm = (2 * $lose->getLevel() + 10) / ($lose->getLevel() + $win->getLevel() + 10);
    // 経験値の計算結果を整数(切り捨て)で返却
    return (int)($exp * $lm ** 2.5 + 1);
}

 

ダメージ計算同様、作成した式に対して必要数値を当てはめていき、算出結果を整数として返却しています。これでバトルポケモンに合わせた経験値計算が実装できました。後ほど出力結果をみてみましょう。

  

経験値バーの実装

バトル中の経験値計算が完成したので、第2世代から採用された「経験値バー」についても作成していきましょう。バーのデザインは、HP同様にBootstrapのプログレスを採用します。

 

割合の算出

 経験値バーの算出に必要なのは「現在のレベルで必要になる経験値をどれだけ満たしているか」です。

 

Get格納トレイト(/Traits/Pokemon/GetTrait.php
/**
* 現在のレベルから次のレベルまでの経験値達成率
* @return integer
*/
public function getPerCompNexExp()
{
    if($this->level >= 100){
        return 100;
    }
    // 現在のレベルので経験値達成率を%の数値で返却(int)
    // 現在のレベルで必要な経験値の超過分(余り)
    $surplus = $this->exp - ($this->level ** 3);
    // 現在のレベルから次のレベルに必要な経験値量
    $need = ((($this->level + 1) ** 3) - ($this->level ** 3));
    // 割合計算(%の数値で返却)
    return $surplus / $need * 100;
}

 

大分考えたのですが、上記式を採用しました。

まず、レベルが100であれば算出は不要のため100(%)を返却します。0でも構いません。

 

まず、現在の達成率(現在のレベルで必要な経験値の超過分)を求めるために

現在の取得経験値 ― 現在のレベルで必要な経験値

の値を$surplusに格納しました。

 次に、割合の分母となる値(現在のレベルから次のレベルまでに必要な経験値)を求めるために、

次のレベルに必要な経験値 ― 現在のレベルに必要な経験値

の値を$needに格納しました。

 最後に割合を求める式として

$surplus / $need * 100

の値を返却しています。

 

べき乗の加算量を求める簡単な式があれば、お問い合わせで教えてください。高校でまともに数学を勉強していない自分には、現状これが精一杯でした。 

あとは、算出した割合をプログレスのwidthにセットするだけです。最大値は100、最小値には0、現在の値にはwidthと同じ値をセットしておきます。

 

バトル画面(/battle.php
<?php # 経験値バー ?>
<div class="progress" style="height:4px;">
    <div class="progress-bar bg-primary" role="progressbar" style="width:<?=$pokemon->getPerCompNexExp()?>%;" aria-valuenow="<?=$pokemon->getPerCompNexExp()?>" aria-valuemin="0" aria-valuemax="100"></div>
</div>

 

プログレスの設置場所はHPバーの下です。

それでは経験値の獲得と合わせて出力結果を確認してみましょう。

 

 

 

 

 

無事ポケモンを倒すことで経験値を取得できました。これでバトルによる経験値獲得処理は完成です。

  

お詫び(不備修正)

第29回にもなると、そこそこ不備も見つかったので修正報告がてらお詫びします。おそらく今後も不備修正はボロボロ出てくることになると思われるので、その辺りはプログラミングの醍醐味学習の一環としてお楽しみ下さい。とりあえずサーセン。

  

数値(計算結果)について

まず、ガバガバプログラミング言語のPHPを使っている関係上、数値の処理でそこそこ不備が見つかっています。例えば、HPで小数点込みの値が表示されるなどです。この辺りは引数で受け取る際に型指定するなどを入念にしていくことで対策します。

 

例:引数の型指定 
/**
* 残りHPの計算
*
* @param string $param
* @param integer $val (default:0)
* @return integer
*/
public function calRemainingHp($param, int $val=0)

 

おかしなレベルアップ

必要経験値を満たせていないのにレベルアップしてしまうということに今回気づきました。確認したところ、経験値の取得処理で「次のレベルまでに必要な経験値」を取得経験値加算後に行なっていたことが原因でした。

 

Set格納トレイト(/Traits/Pokemon/SetTrait.php
/**
* 経験値をセット(取得)する
* @param integer $exp
* @return object
*/
public function setExp($exp)
{
    if(!is_numeric($exp)){
        // 入力値のチェック
        $this->setMessage('数値を入力してください', 'error');
        return $this;
    }
    // 次のレベルに必要な経験値を取得
    $next_exp = $this->getReqLevelUpExp();
    // 経験値を加算
    $this->exp += (int)$exp;
    $this->setMessage($this->getNickname().'は経験値を'.$exp.'手に入れた!', 'success');
    // レベル上限の確認
    if($this->level >= 100){
        return $this;
    }
    if($next_exp <= $exp){
        $levelup = true;
        /**
        * 次のレベルに必要な経験値を超えている場合
        */
        $this->actionLevelUp();
        while($this->getReqLevelUpExp() < 0){
            $this->actionLevelUp();
        }
    }
    // 進化判定
    if(isset($levelup) && isset($this->evolve_level) && ($this->evolve_level <= $this->level)){
        return $this->evolve();
    }else{
        return $this;
    }
}

 

その他諸々修正しています。

 

攻撃の流れ

攻撃の流れについてですが、今までattackメソッド完了後にひんし判定を行なっていましたが、その場合状態異常になってからひんしになるということが発生していました。

例:ひのこ→やけどした→倒れた

 

なので、再度見直してattack処理の中でひんし判定までの一連の流れを行うように修正しました。

 

攻撃用トレイト(/Trait/Battle/AttackTrait.php
/**
* 攻撃
* (攻撃→ダメージ計算→ひんし判定)
*
* @param object $atk_pokemon
* @param object $def_pokemon
* @param object $move
* @return boolean (true:相手を戦闘不能にした)
*/
protected function attack($atk_pokemon, $def_pokemon, $move)
{
    // 攻撃メッセージを格納
    $this->setMessage($atk_pokemon->getPrefixName().'は'.$move->getName().'を使った!');
    // タイプ相性チェック
    $type_comp_msg = $this->checkTypeCompatibility($move->getType(), $def_pokemon->getTypes());
    // 「こうかがない」の判定(命中率と威力がnullではなく、タイプ相性補正が0の場合)
    if(!is_null($move->getAccuracy()) && !is_null($move->getPower()) && ($this->m === 0)){
        // こうかがない
        $this->setMessage($def_pokemon->getPrefixName().'には効果が無いみたいだ');
        return;
    }
    // 命中判定
    $hit = $this->checkHit($move->getAccuracy());
    if(!$hit){
        // 攻撃失敗
        $this->setMessage('しかし攻撃は外れた!');
        return;
    }
    // 必要ステータスの取得
    $stats = $this->getStats($move->getSpecies(), $atk_pokemon, $def_pokemon);
    // ダメージ計算
    if($move->getSpecies() !== 'status'){
        /**
        * 物理,特殊技
        */
        if(!is_null($move->getPower())){
            // 急所判定(固定ダメージ技は判定不要)
            $critical = $this->checkCritical($move->getCritical());
            if($critical){
                $this->setMessage('急所に当たった!');
            }
        }
        // 乱数補正値の計算
        $this->calRandNum();
        // タイプ一致補正の計算
        $this->calMatchType($move->getType(), $atk_pokemon->getTypes());
        // ダメージ計算
        $damage = $this->calDamage(
            $atk_pokemon->getLevel(),   # 攻撃ポケモンのレベル
            $stats['a'],                # 攻撃ポケモンの攻撃値
            $stats['d'],                # 防御ポケモンの防御値
            $move->getPower(),          # 技の威力
            $this->m,                   # 補正値
        );
        // やけど補正
        if(($move->getSpecies() === 'physical') && ($atk_pokemon->getSa() === 'SaBurn')){
            // 物理且つやけど状態ならダメージを半減
            $damage *= 0.5;
        }
        // タイプ相性のメッセージを返却
        $this->setMessage($type_comp_msg);
    }else{
        /**
        * 変化技
        */
        $damage = 0;
    }
    // ダメージ計算
    $def_pokemon->calRemainingHp('sub', $damage);
    // ひんしチェック
    if($this->checkFainting($def_pokemon)){
        // 相手を「ひんし」状態にした
        return true;
    }else{
        // 相手は「ひんし」状態ではない
        // 追加効果
        $move->effects($atk_pokemon, $def_pokemon);
        // 追加効果のメッセージをセット
        $this->setMessage($move->getMessages());
        return false;
    }
}

 

ただ、反動技(とっしん等)で両者が力尽きた場合などが加味されておらず、この辺りは近々まとめて行く予定です。一旦は応急処置として考えておいてください。

 

いきあたりばったりで開発を始めるとこういうことになるので注意しましょう。(戒め)

 

まとめ

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

今回のPHPポケモンでは「バトルによる経験値獲得」について、経験値の計算方法などをご紹介しました。

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

 

注目の記事

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

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

PHPポケモン「バトルシステム編〜経験値の獲得〜」29
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「バトルシステム編〜経験値の獲得〜」29

経験値の獲得 今まではポケモンに直接経験値を与えるというチートびっくりの仕様でしたが、バトルシステムも終盤に差し掛かってきたので「倒したポケモンから経験値を取得する」というごく当たりまえの仕様を導入していきます。   基礎経験値の設定 では、経験値の計算式に入る前に、必要なパラメーターを1つ用...

get_template_partで引数を渡す方法(WordPress5.5以降)
プログラミング
PHP,WordPress
get_template_partで引数を渡す方法(WordPress5.5以降)

WordPress5.5へのバージョンアップで、大きく機能が追加されました。中には変更に戸惑っている人もいるかも知れませんが、個人的にはエンジニアの要望を大きく取り入れて自由度がアップした印象があります。 今回はその中でも、多くの方が待ち望んでいた「get_template_part」の変更点についてご紹介します。 ge...

EC-CUBE4内にWordPressを設置(共存)する方法
SEO対策,プログラミング
EC-CUBE4,PHP,Symfony,Twig,WordPress
EC-CUBE4内にWordPressを設置(共存)する方法

今回使用したバージョン EC-CUBE4.0.5 WordPress5.6 ※EC-CUBE4、WordPressのカスタマイズは自己責任でお願いします。また、現在稼働中のサイトで試す際には、必ずバックアップを取ってから行なうようにしてください。   EC-CUBE4とは ネットショップを作るとなれば、様々なサービスが出回っ...

ポケモン預かりシステム編 ボックスの作成 PHPポケモン 86
プログラミング
PHP,PHPポケモン,ポケモン
ポケモン預かりシステム編 ボックスの作成 PHPポケモン 86

ポケモン預かりシステムの実装 今回は、前回ざっくりと仕様決めをした「ポケモン預かりシステム」を実装していきます。ボックス内では操作する項目が多いため、ボックス自体に1つの画面を用意して、できる限りPHPによる制御だけで完結できるように作成していきます。   ボックスクラスの作成 それではまず、今...

ピカチュウから学ぶオブジェクト指向 〜レベルアップ編〜 5
プログラミング
PHP,PHPポケモン,オブジェクト指向,ポケモン
ピカチュウから学ぶオブジェクト指向 〜レベルアップ編〜 5

  第3回でレベルシステムを導入し、第4回では経験値システムの導入をしたので、今回はそれを合わせたレベルアップのシステムを導入します。 第1回から作成しているコードを使用しているので、もし最初から学習したい人は第1回の入門編をご覧ください。     レベルアップシステムの導入   レベル...

独立するならWordPress理解しておけばOK!プログラミングでフリーランスはこれ一つで成り立ちます
プログラミング
PHP,WordPress,フリーランス,独立
独立するならWordPress理解しておけばOK!プログラミングでフリーランスはこれ一つで成り立ちます

  プログラミングでフリーランスを目指すには、どの言語始めればいいの?   プログラミングの学習を始めたのに、それをどう活かせばよいか分からず、いざフリーランスで活動しようと思ってもイメージできずに断念してしまう人は多いです。 言語にも向き不向きがあるため、フリーランスとして活動するために向...

連続攻撃技と一撃必殺技編 PHPポケモン39
プログラミング
PHP,PHPポケモン,ポケモン
連続攻撃技と一撃必殺技編 PHPポケモン39

連続攻撃技とは 追加効果だけでは処理できない技が、初代に限定していても数多くあります。その一つが「連続攻撃技」です。  連続攻撃技 https://wiki.ポケモン.com/wiki/連続攻撃技 連続攻撃技はさらに4パターンに分かれる。 攻撃回数が2回固定であるもの 攻撃回数が3回固定であるもの 攻撃回...

カテゴリ

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