プログラミング

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

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

 

注目の記事

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

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

売れるECサイトになるために必要な3つの戦略
マーケティング
ECショップ,コンサルティング
売れるECサイトになるために必要な3つの戦略

  ECサイトで全く売れない・・・   ネットショップのオープンが手軽で安価になり、クレジット決済も主流の今ECサイトを立ち上げるお店も増えてきました。 しかし期待感とは裏腹に、思ったような売上が出なかったり、お客さんが1人も獲得できていないケースも少なくありません。   今回はそういった「...

PHPポケモン「アクション制御編」27
プログラミング
JavaScript,jQuery,PHP,PHPポケモン,ポケモン
PHPポケモン「アクション制御編」27

  今回のPHPポケモンでは主に画面の作り込みをしていきます。 とは言っても、ガッチリCSSを書いてよりゲームらしい見た目にするわけではなく、あくまで「ゲームシステムを再現するため」だけに整えていくのが目的です。   ということで、今回はPHPよりもBootstrapさんとjQueryさんに活躍してもらいます。   ...

定数と静的変数 ピカチュウとイーブイで学ぶオブジェクト指向
プログラミング
PHP,PHPポケモン,イーブイ,オブジェクト指向,ピカチュウ,ポケモン
定数と静的変数 ピカチュウとイーブイで学ぶオブジェクト指向

PHPポケモンも順調に開発が進んでいると思いきや、ふとした気づきが自分の理解力を思い知らせることとなった今日このごろです。 プログラミングは奥が深く、しっかりと段階を追って理解を進めていけば、「これ・・・便利やんけ!」ってなることがかなり多いということがわかります。   それでは、かの有名な黄色い...

フリーランスが見積書を作るときに押さえておきたい3つのポイント+α
フリーランス
フリーランス,仕事依頼,独立,見積書
フリーランスが見積書を作るときに押さえておきたい3つのポイント+α

  仕事の依頼がきたけど、どれぐらいの金額を提示すればいいかわからない   駆け出しのフリーランスや、これから独り立ちしようとしている人に多い悩みです。 今回はそういった方のために「フリーランスが見積書を作るときに押さえておきたい3つのポイント+α」についてご紹介します。     時給...

成功に近い3つの思考「楽して稼ぐ」「知識オタク」「資産形成は無駄」
雑記
成功に近い3つの思考「楽して稼ぐ」「知識オタク」「資産形成は無駄」

  「楽して稼ぎたい」   人間誰しも、そう考えているはずです。これは正しく、成功するためには必要な思考です。 それを「楽に稼ぐ方法なんてない」と無理やり押さえつけてしまう人は、完全に本質が見えておらず、その大半に「楽して稼げない自分を認められてない」というマイナス因子が含まれてい...

ポケモン図鑑編 PHPポケモン 88
プログラミング
PHP,PHPポケモン,ポケモン
ポケモン図鑑編 PHPポケモン 88

ポケモン図鑑とは ポケモンに出会ったり、仲間にしたりすると、ポケモン図鑑のデータがどんどんと埋まっていきます。PHPポケモンでもこの仕組みを実現させるために、ポケモン図鑑を作成していきましょう。   クラスによる管理 ポケモン図鑑はクラス管理をしていきます。プレイヤー1人に対して1つのポケモン図...

HPバー色変更編(アニメーション) PHPポケモン53
プログラミング
PHP,PHPポケモン,ポケモン
HPバー色変更編(アニメーション) PHPポケモン53

HPバーの色変更 残りHPの割合に合わせて色クラスをセットしていましたが、ダメージを受けた際の判定処理(動的は変更)が未実装でしたので、今回はコチラを対応します。   残数(割合)の判定 HPの色判定は、HTMLの描画時とJSによるHP変動時に行います。animateメソッド前や後に行うと変更のズレが生じるため、a...

カテゴリ

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