プログラミング

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ポケモンでは「バトルによる経験値獲得」について、経験値の計算方法などをご紹介しました。

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

 

注目の記事

ピカチュウから学ぶオブジェクト指向 〜ステータス導入編〜 6
プログラミング
PHP,PHPポケモン,オブジェクト指向,ポケモン
ピカチュウから学ぶオブジェクト指向 〜ステータス導入編〜 6

  PHPをピカチュウ(ポケモン)から学ぶ大人気コーナー、第6回目は「ステータス機能の導入編」です。   前回(第5回)で終了段階でのサンプルコードを公開しているので、もし本記事から始める人はぜひそちらを参考にしてください。    ※お詫び   調べたところによると、ポケモンの経験...

連続の技習得編 オブジェクトをセッションへ格納 PHPポケモン57
プログラミング
PHP,PHPポケモン,ポケモン
連続の技習得編 オブジェクトをセッションへ格納 PHPポケモン57

セッション経由でのオブジェクト引き継ぎ 技習得の処理が整ってきたので、ここで連続技習得・連続レベルアップ時にも問題なく動作するように作り込んでいきます。ですが、現状のモーダルをレスポンスやメッセージと同様に、そのまま引き継いだとしてもエラーが発生します。 その原因がセッション経由でのオブジェク...

ポケモン預かりシステム編 PHPポケモン 85
プログラミング
PHP,PHPポケモン,ポケモン
ポケモン預かりシステム編 PHPポケモン 85

ポケモン預かりシステムとは ポケモンは手持ち(パーティー)に6匹しか入れることができません。そのため、ポケモンを捕まえた際にその上限に達していれば、ボックスへ転送するという仕組みをPHPポケモンでも実装していきます。これが、ポケモン預かりシステムです。 今回は前段階であるボックスの仕様決めをメイン...

3日坊主にならないために
雑記
ブログ,プログラミング
3日坊主にならないために

  プログラミングに挑戦してみたが、途中で挫折した人 ブログを書き始めたが、まったく続かない人   継続することの大切さは分かっても、なかなか難しいものです。 しかしそれは、取り組み方を見直すだけで、実は簡単に解決できてしまうものなのです。 今回は、そんな「3日坊主」と呼ばれる人が、そ...

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

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

【Youも明日からデザイナー】デザインセンスを磨くコツ3つ
デザイン
YouTube,サムネイル,バナー
【Youも明日からデザイナー】デザインセンスを磨くコツ3つ

  デザイナーにセンスは必要か?   この問いに、私は必ず「必要ない」と答えます。確かに、センスを磨くことは大切ですが、それがあたかも才能のように表現するのは間違っていると思っているからです。 デザインは誰にでもできます。そしてオリジナリティは各自が必ず持っています。だからこそ、なりたい...

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

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

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

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

カテゴリ

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