プログラミング

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ポケモンの大幅見直しを迫られているわけではありません。   毎日継続するために  ブログや学習など、毎日継続...

知らなきゃ損!表記ゆれに強いSEO対策とは「オーガニック検索ユーザーを増やそう」
SEO対策
description,keyword,meta,title
知らなきゃ損!表記ゆれに強いSEO対策とは「オーガニック検索ユーザーを増やそう」

  「なかなかオーガニック検索の割合が増えない」 「どういったSEO対策をすればいいかわからない」   ブログやサイト運営者の方で、思うように成果が出ないと悩んでいる人は、まだまだSEO対策が十分ではない可能性があります。そして、SEO対策の中でも知らないと損する一つが「表記ゆれ」への対応です。 ...

経験値取得アニメーション編(動画有り) PHPポケモン 47
プログラミング
PHP,PHPポケモン,ポケモン
経験値取得アニメーション編(動画有り) PHPポケモン 47

経験値取得アニメーションの実装 最近は技の実装が続いていたので、気分転換にフロント側の演出づくりをしていきます。その中でも今回実装するのは「経験値取得アニメーション」です。 経験値バーはポケモンの第2世代から追加実装された演出です。初代では次のレベルにアップするまでの数値を、わざわざポケモンの...

デザインとブランディングが生み出す本当の価値とは
デザイン
UCC
デザインとブランディングが生み出す本当の価値とは

  商品やHPなど様々なところで価値を提供している「デザイン」ですが、それがもつ本当の意味や価値というものは意外と知られていません。 一般的にはイメージを作る・伝えるということで要求されるものですが、突き詰めた先には人間の深層心理に働きかけるブランディングという要素が潜んでいるのです。   今...

【完全未経験OK】プログラミングの始め方 〜学習方法を解説します!〜
プログラミング
CSS,HTML,JavaScript,MAMP,PHP,XAMPP,フリーランス,プログラミング,独立,起業
【完全未経験OK】プログラミングの始め方 〜学習方法を解説します!〜

  プログラミングって難しい   そういう人は多いですね。しかしそんなことは有りません。 言語という点で比較すれば、英語やフランス語など第二言語を学ぶ方が難しいと言えます。   プログラミングの需要は年々高まり、今や最高潮とも言える域まで来ています。 なぜそこまで需要が高いのか?   ...

人に相談しても期待はするな【行動もどきって?成功する人と失敗する人の違いとは】
雑記
自己啓発
人に相談しても期待はするな【行動もどきって?成功する人と失敗する人の違いとは】

  「とにかく行動しろ」 「いろんな人に会え」 「どんどん外注しろ」   どれも覚えておきたい教訓ではありますが、その本質が見抜けなければ逆効果になります。 行動であっても、それが行動もどきになっている人は多く、人に会って人生が変わるということも受け身であれば全く意味がありません。外注に...

ひとのものをとったらどろぼう!編 PHPポケモン 99
プログラミング
PHP,PHPポケモン,ポケモン
ひとのものをとったらどろぼう!編 PHPポケモン 99

ひとの ものを とったら どろぼう! ポケモンの中でも有名なセリフの1つです。モンスターボールを投げることでポケモンを捕まえることができますが、既に別トレーナーが所有しているポケモンを捕まえることはできません。 初代から、トレーナー戦でモンスターボールを投げると「ひとの ものを とったら どろぼう!...

なぜ(・・? あなたはMacを使うのか?
雑記
AWS,Linux,MacBook,OS,Windows
なぜ(・・? あなたはMacを使うのか?

  あなたが使っているPCはなんですか?   たまに聞かれることがあります。 そこで「Macを使っています」と答えると「何故?」という次の問いが返ってくることがあります。   あなたがもしMacを使っているのであれば、このときになんと答えますか?   今回のテーマは、「何故Macを使っているの?」と...

カテゴリ

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