プログラミング

PHPポケモン「バトルシステム編〜HP計算〜」26

PHP PHPポケモン ポケモン
PHPポケモン「バトルシステム編〜HP計算〜」26

HP計算

これまでに実装したダメージ計算ですが、計算はできていてもお互いに相手ポケモンのHPを削ることはできませんでした。なので、今回は実際のバトルのように、HPに対してダメージを与えるという仕組みを作成していきます。

 

残りHP

ここで必要になるのが「残りHP」という概念です。今までステータス上のHPは存在していましたが、現在どれぐらい残りがあるのかまでは用意していませんでした。なので、これをポケモンに対して持たせ、且つ状態異常などとともにステータスの引き継ぎ対象としましょう。

  

プロパティの設定

 まずは残りHPを格納するためのプロパティをポケモンクラスに用意します。

 

ポケモンクラス(/Classes/Pokemon.php
/**
* 残りHP
* @var integer
*/
protected $remaining_hp;

 

こちらも取得用のメソッドとしてGet格納トレイトにgetRemainingHpを作成しておいてください

 

プロパティを作成したら、引き継ぎ処理にも追加しておきましょう。今回引き継ぎ処理を簡易化させました。

 

ポケモンクラス(/Classes/Pokemon.php
/**
* 現在インスタンスを出力(引き継ぎ用)
*
* @return array
*/
public function export()
{
    return [
        'class_name' => get_class($this),       # クラス名
        'nickname' => $this->nickname,          # ニックネーム
        'level' => $this->level,                # レベル
        'ev' => $this->ev,                      # 努力値
        'iv' => $this->iv,                      # 個体値
        'exp' => $this->exp,                    # 経験値
        'move' => $this->move,                  # 技
        'sa' => $this->sa,                      # 状態異常
        'remaining_hp' => $this->remaining_hp,  # 残りHP
    ];
}
 
/**
* 能力引き継ぎ処理
*
* @param array $before
* @return void
*/
protected function takeOverAbility($before)
{
    foreach($before as $key => $val){
        $this->$key = $val;
    }
}

 

exportには追加になった残りHPの項目を増やしています。

能力引き継ぎの処理についてですが、それぞれ値を指定するのではなく、foreachで回していきながらそれぞれキー通りのプロパティに設定するという仕様です。進化時の引き継ぎ処理としてオブジェクトの分岐をしていましたが、こちらはオブジェクトではなくexportした配列を引数として渡す仕様に、ポケモンのコンストラクタ内を変更しました。

 

ポケモンクラス(/Classes/Pokemon.php__construct内)
/**
* 進化した際の処理
* @var object $before
*/
case 'object':
// 進化前のポケモンと一致しているかチェック
if(is_a($before, $this->before_class ?? null)){
    $this->takeOverAbility($before->export());
    // メッセージの引き継ぎ
    $this->setMessage($before->getMessages());
    $this->setMessage($this->name.'に進化した', 'success');
    $this->checkMove();
}
break;

 

計算用メソッドの作成

 次に、計算用のメソッドを作成しましょう。上限値と下限値が決まっているため、原則としては直接プロパティに値をセットするようなことはしません。

計算用メソッドもポケモンクラスで使用しますが、addRanksubRankなど計算系のメソッドが多くなってきたので、新しく計算用メソッドの格納トレイトを作成しましょう。

 

計算用トレイト(/Traits/Pokemon/CalculationTrait.php
<?php
trait CalculationTrait
{
 
    /**
    * ランクの加算
    *
    * @param string $param
    * @param integer $val (min:1, max:12)
    * @return string
    */
    public function addRank($param, $val)
    {
        // 変化ランクに合わせたメッセージ
        $msg = [
            1 => '上がった',
            2 => 'ぐーんと上がった',
            3 => 'ぐぐーんと上がった',
            12 => '最大まで上がった',
        ];
        // 既にランクが最大であればfalseを返却
        if($this->rank[$param] === 6){
            return $this->name.'の'.transJp($param).'はもう上がらない';
        }
        // 加算処理
        $this->rank[$param] += $val;
        // 最大値は6
        if($this->rank[$param] > 6){
            $this->rank[$param] = 6;
        }
        return $this->name.'の'.transJp($param).'が'.$msg[$val] ?? $msg[3];
    }
 
    /**
    * ランクの減算
    *
    * @param string $param
    * @param integer $val (min:1, max:3)
    * @return string
    */
    public function subRank($param, $val)
    {
        // 変化ランクに合わせたメッセージ
        $msg = [
            1 => '下がった',
            2 => 'がくっと下がった',
            3 => 'がくーんと下がった',
        ];
        // 既にランクが最低であればfalseを返却
        if($this->rank[$param] === -6){
            return $this->name.'の'.transJp($param).'はもう下がらない';
        }
        // 減算処理
        $this->rank[$param] -= $val;
        // 最低値は-6
        if($this->rank[$param] < -6){
            $this->rank[$param] = -6;
        }
        return $this->name.'の'.transJp($param).'が'.$msg[$val] ?? $msg[3];
    }
 
    /**
    * 残りHPの計算
    *
    * @param string $param
    * @param integer $val (default:0)
    * @return integer
    */
    public function calRemainingHp($param, $val=0)
    {
        switch ($param) {
            // リセット処理
            case 'reset':
            // 最大HPをセット
            $this->remaining_hp = $this->getStats('HP');
            if(isset($this->sa['SaFainting'])){
                // ひんしの場合は解除
                unset($this->sa['SaFainting']);
            }
            break;
            // 即死処理
            case 'death':
            $this->remaining_hp = 0;
            break;
            // 減算処理
            case 'sub':
            $this->remaining_hp -= $val;
            break;
            // 加算処理
            case 'add':
            $this->remaining_hp += $val;
            // 最大HPを超えないようにする
            if($this->remaining_hp > $this->getStats('HP')){
                $this->remaining_hp = $this->getStats('HP');
            }
            break;
        }
        // HPが0以下になった場合の処理
        if($this->remaining_hp <= 0){
            // 状態異常をひんしに書き換え
            $this->sa = ['SaFainting' => ''];
            $this->remaining_hp = 0;
        }
        // 残りHPを返却
        return $this->remaining_hp;
    }
}

 

作成したトレイトはポケモンクラスで読み込んでおいてください

 

それでは新しく追加した、calRemainingHpのメソッドを見ていきましょう。

/**
* 残りHPの計算
*
* @param string $param
* @param integer $val (default:0)
* @return integer
*/
public function calRemainingHp($param, $val=0)

 

第1引数でどういった計算をするかを指定します。今回準備したのは初期化(reset)即死(death)減算(sub)加算(add)の4つです。

第2引数にはが入ります。subであればダメージ量addであれば回復量です。

 

次に処理内の分岐を見ていきましょう。

switch ($param) {
    // リセット処理
    case 'reset':
    // 最大HPをセット
    $this->remaining_hp = $this->getStats('HP');
    if(isset($this->sa['SaFainting'])){
        // ひんしの場合は解除
        unset($this->sa['SaFainting']);
    }
    break;
    // 即死処理
    case 'death':
    $this->remaining_hp = 0;
    break;
    // 減算処理
    case 'sub':
    $this->remaining_hp -= $val;
    break;
    // 加算処理
    case 'add':
    $this->remaining_hp += $val;
    // 最大HPを超えないようにする
    if($this->remaining_hp > $this->getStats('HP')){
        $this->remaining_hp = $this->getStats('HP');
    }
    break;
}

 

第1引数で受け取った$paramの値に対して分岐をかけていきます。

最初の初期化(reset)処理は、ポケモン生成時や全回復をする際に使用します。現在は用意されていませんが、ポケモンセンターやボックスへ入れて再度取り出すなどした際、「かいふくのくすり」などを選択した際に使用する予定です。

// リセット処理
case 'reset':
// 最大HPをセット
$this->remaining_hp = $this->getStats('HP');
break;

 

2つ目の即死(death)処理は、一撃必殺などダメージに関係なくHPを0にする際に使用します。

// 即死処理
case 'death':
$this->remaining_hp = 0;
break;

 

3つ目の処理は減算(sub)処理です。ダメージを受けた際に使用します。数値がマイナスになれば0に戻すという処理をしなければなりませんが、この処理内では行わずに最終的に処理します。

// 減算処理
case 'sub':
$this->remaining_hp -= $val;
break;

 

4つ目の処理は加算(add)処理です。アイテムによる回復や「じこさいせい」など回復技による処理を行う際に使用します。

// 加算処理
case 'add':
$this->remaining_hp += $val;
// 最大HPを超えないようにする
if($this->remaining_hp > $this->getStats('HP')){
    $this->remaining_hp = $this->getStats('HP');
}
break;

 

最大HPを超えてしまわないように、加算後に数値のチェックを行なっています。

 

次に分岐後の共通処理について見ていきましょう。

// 復活判定(ひんしからの回復)
if(isset($this->sa['SaFainting']) && ($this->remaining_hp > 0)){
    unset($this->sa['SaFainting']);
}
// ひんし判定
if($this->remaining_hp <= 0){
    // 状態異常をひんしに書き換え
    $this->sa = ['SaFainting' => null];
    $this->remaining_hp = 0;
}
// 残りHPを返却
return $this->remaining_hp;

 

まず最初に、復活判定を行います。もしひんし状態からの回復がなされた場合、状態異常にセットしている「ひんし」を解除しなければなりません。これはresetaddのどちらかで必要になるため、分岐後にチェックしています。

 

次に、HPが0になった場合のひんし判定を行います。もし残りHPが0以下であれば、状態異常をひんし(SaFainting)に上書きをして、残りHPに対して0をセットしました。こうすることで、マイナスの値が入ることはありません。

 

最後に返り値として残りHPを返却します。こちらは使用しないこともありますが、ダメージ判定後にHPがどうなったかを確認する際に活用できるように指定しました。

 

ダメージ計算

 それではダメージ計算に対して、作成した残りHPの減算処理を実装しましょう。

 

バトルコントローラー(/Classes/Controller/BattleController.php
/**
* アクション
*
* @param string $action
* @param mixed $param
* @return void
*/
private function action($action, $param)
{
    // 敵ポケモンの技をインスタンス化
    $e_move = $this->getInstance($this->aiSelectMove());
    switch ($action) {
        /**
        * にげる
        */
        case 'run':
        // $this->run++;
        if($this->checkRun()){
            unset($_SESSION['enemy']);
            unset($_SESSION['rank']);
            unset($_SESSION['run']);
            header("Location: ./home.php", true, 307);
            exit;
        }
        $this->setMessage('逃げられない!');
        // 敵ポケモンの攻撃
        $p_damage = $this->attack($this->enemy, $this->pokemon, $e_move);
        break;
        /**
        * たたかう
        */
        case 'fight':
        // 自ポケモンの技をインスタンス化
        $p_move = $this->getInstance($param);
        // 行動順の判定
        if($this->checkFirstMove($p_move, $e_move)){
            // 先行
            // 自ポケモンの攻撃
            $e_damage = $this->attack($this->pokemon, $this->enemy, $p_move);
            $this->enemy
            ->calRemainingHp('sub', $e_damage);
            // 敵ポケモンの攻撃
            $p_damage = $this->attack($this->enemy, $this->pokemon, $e_move);
            $this->pokemon
            ->calRemainingHp('sub', $p_damage);
        }else{
            // 後攻
            // 敵ポケモンの攻撃
            $p_damage = $this->attack($this->enemy, $this->pokemon, $e_move);
            $this->pokemon
            ->calRemainingHp('sub', $p_damage);
            // 自ポケモンの攻撃
            $e_damage = $this->attack($this->pokemon, $this->enemy, $p_move);
            $this->enemy
            ->calRemainingHp('sub', $e_damage);
        }
        break;
    }
}

 

それぞれダメージ計算終了後に残りHPの減算処理を行なっています。変化技などを使いダメージが0であれば0の減算が行われることになります。

実際のバトルでは、HPが0になった時点でバトルが終了しますが、バトル終了のアクション自体がまだ出来ていないので、一旦このままで進めていきましょう。

 

現状はHPの回復手段がありません。なので、もしHPが0でバトルが終了すれば全回復するようにホーム画面のコントローラーに簡易策としてリセット処理を入れておきましょう。

 

ホームコントローラー(/Classes/Controller/HomeController.php
/**
* アクション
*
* @param string $action(method_name)
* @param mixed $param
* @return void
*/
private function action($action, $param)
{
    // リセットの処理
    if($action === 'reset' || is_null($this->pokemon)){
        header("Location: ./index.php", true, 307) ;
        exit;
    }
    // にげるの処理
    if($action === 'run'){
        $this->setMessage('逃げ切れた', 'success');
        if($this->pokemon->getRemainingHp() <= 0){
            // ひんし状態ならHPを全回復させる
            $this->pokemon
            ->calRemainingHp('reset');
        }
        return;
    }
    // 呼び出せるメソッドか判別
    if(is_callable([$this->pokemon, $action])){
        // メソッド実行結果を$resultに格納
        $result = $this->pokemon
        ->$action($param);
        switch ($action) {
            // 経験値の取得
            case 'setExp':
            $this->pokemon = $result;
            break;
        }
        // Pokemonクラスに溜まったメッセージを取得
        $this->setMessage($this->pokemon->getMessages());
    }else{
        $this->setMessage('このアクションは使用できません', 'error');
    }
}

 

レベルアップ・進化時の残りHP

 次にレベルアップ、進化時の残りHPの計算処理を実装します。

ポケモンではレベルアップすれば、HPの上昇値に合わせてHPが回復します。これは進化した際も同じです。こうすることで、レベルアップしたのにHPが減っているという現象を防ぐことができます。

 

ポケモンクラス(/Classes/Pokemon.php
/**
* レベルアップ処理
*
* @return void
*/
protected function actionLevelUp()
{
    // 現在のHPを取得
    $before_hp = $this->getStats('HP');
    // レベルアップ
    $this->level++;
    // HPの上昇値分だけ残りHPを加算(ひんし状態を除く)
    if(!isset($this->sa['SaFainting'])){
        $this->calRemainingHp('add', $this->getStats('HP') - $before_hp);
    }
    $this->setMessage($this->getNickName().'のレベルは'.$this->level.'になった!', 'success');
    // 現在のレベルで習得できる技があるか確認
    $this->checkMove();
}
 
/**
* 進化
*
* @return Classes\Pokemon\$after_class
*/
protected function evolve()
{
    if(class_exists($this->after_class ?? null)){
        // 現在のHPを取得
        $before_hp = $this->getStats('HP');
        // 進化ポケモンのインスタンスを生成
        $pokemon = new $this->after_class($this);
        // HPの上昇値分だけ残りHPを加算(ひんし状態を除く)
        if(!isset($pokemon->sa['SaFainting'])){
            $pokemon->calRemainingHp('add', $pokemon->getStats('HP') - $before_hp);
        }
        // 進化後のインスタンスを返却
        return $pokemon;
    }else{
        $this->setMessage('このポケモンは進化できません', 'error');
    }
}

 

レベルアップまたは進化前に現在の最大HPを取得し、その後のステータスとの差分を算出しcalRemainingHpで加算処理を行なっています。ただし例外として、ひんし状態であれば加算処理は不要です。ひんし状態でのレベルアップは「ふしぎなアメ」などアイテムを使った際に起こりますが、これによる復活処理を回避するためです。

※初代では復活した覚えがありますがうろ覚えです

 

rangeを使ったビジュアル

 最後にビジュアルを作成して残りHPがどれぐらいあるかを確認できるようにしましょう。CSSで作る予定でしたがinputのrangeが使えるということに気づいてしまったので、こちらを代用します。

input range(HTMLクイックリファレンス)

 

バトル画面(/battle.php
<section>
    <div class="row mt-3 mb-5">
        <?php # 敵ポケモン詳細 ?>
        <div class="col-6">
            <p><?=$enemy->getName()?> Lv:<?=$enemy->getLevel()?></p>
            <p><?=$enemy->getSaName()?></p>
            <div class="form-group">
                <input type="range" class="form-control-range" min="0" max="<?=$enemy->getStats('HP')?>" value="<?=$enemy->getRemainingHp()?>" style="pointer-events: none;">
            </div>
        </div>
        <div class="col-6 text-center">
            <img src="Resources/Assets/img/pokemon/dots/front/<?=get_class($enemy)?>.gif" alt="<?=$enemy->getName()?>">
        </div>
    </div>
    <div class="row mb-3">
        <?php # 自ポケモン詳細 ?>
        <div class="col-6 text-center">
            <img src="Resources/Assets/img/pokemon/dots/back/<?=get_class($pokemon)?>.gif" alt="<?=$pokemon->getName()?>">
        </div>
        <div class="col-6">
            <p><?=$pokemon->getName()?> Lv:<?=$pokemon->getLevel()?></p>
            <p><?=$pokemon->getSaName()?></p>
            <div class="form-group">
                <input type="range" class="form-control-range" min="0" max="<?=$pokemon->getStats('HP')?>" value="<?=$pokemon->getRemainingHp()?>" style="pointer-events: none;">
                <p class="text-right px-3"><?=$pokemon->getRemainingHp()?> / <?=$pokemon->getStats('HP')?></p>
            </div>
        </div>
    </div>
</section>

 

それでは出力結果を見てみましょう。

 

 

 

持ち手が邪魔ですがほぼ完璧です。

ポケモンでは残りHPが1/2、1/4と減っていくことでゲージの色が変わりますが、そのあたりは後ほど対応します。HPバーは変更されても数値に影響はないので構いませんが、念の為pointer-eventsを使って無効化しました。

 

rangeのminに0maxに最大HPvalueに残りHPをセットするだけで自動計算してくれるという仕組みです。ちなみにですが、ひんし設定はしていますが判定はしていないので、現状お互い死んでも殴り続けることができるというサイコなゲームとなっています。

  

まとめ

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

今回のPHPポケモンは「バトルシステム編〜HP計算〜」についてご紹介しました。

ポケモン好きな人やゲームづくりに興味がある人、現在プログラミング学習に取り組んでいる人は、ぜひ参考にしてみてくださいね。

 

注目の記事

初心者必見!仕事がデキる人のIllustrator活用術3選
デザイン
Adobe,Illustrator,サムネイル
初心者必見!仕事がデキる人のIllustrator活用術3選

  仕事の速い人の大半は、「効率の良い方法」や「便利な使い方」を知っていて使いこなしています。これは、デザインの現場でも同じです。 今回はその中でもIllustratorで知っておくと便利な機能を3つご紹介します。この3つを押さえておくだけで、作業効率は格段にアップするので、これからソフトの使い方を覚...

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

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

ゲームバランス調整編 DateTimeクラスの活用 PHPポケモン 101
プログラミング
PHP,PHPポケモン,ポケモン
ゲームバランス調整編 DateTimeクラスの活用 PHPポケモン 101

ゲームバランスの調整 まだまだ開発途中のPHPポケモンはゲームバランスの調整がほとんどされていません。現段階では機能も揃っていない関係上、完全なゲームバランスを求めて行くことにはあまり意味がありませんが、今後調整するための役割として機能自体は作成しておこうというのが今回の目的です。   トレーナ...

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

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

オブジェクト指向有効活用編 PHPポケモン 93
プログラミング
PHP,PHPポケモン,ポケモン
オブジェクト指向有効活用編 PHPポケモン 93

オブジェクト指向の有効活用 β版に向けたPHPポケモンの構成見直し、今回は「オブジェクト指向」の役割について、より理解を深めつつ、保守性も良くなるように整えていきます。   機能を持たせる 様々なプロパティを定数や静的変数へ以降していますが、今回は「静的メソッド」の活用範囲を増やしていきます。まず...

WordPressをローカルと本番環境で同じ状態にするために理解しておきたい3つのポイントを徹底解説
プログラミング
PHP,phpMyAdmin,WordPress
WordPressをローカルと本番環境で同じ状態にするために理解しておきたい3つのポイントを徹底解説

  WordPressで作ったサイトは通常のサイトと違い、DBが絡んでくるためローカル環境と本番環境を同一の状態で稼働させるには設定や更新されるディレクトリの知識が必要になります。 今回は、WordPressを使ったサイトを作成している人や、開発に挑戦しようとしている人に向けて、ローカルで作ったWordPressのサイ...

PHPポケモン「バトルシステム実装編〜補正値計算・乱数・急所〜」21
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「バトルシステム実装編〜補正値計算・乱数・急所〜」21

バトルシステムの実装  今回は「急所」と「乱数」と「タイプ一致」の判定と補正を実装していきます。 ちなみにですが、ポケモンwikiを熟読したところ、補正値の計算にも順番があり、計算後に小数点の切り捨てや五捨五超入をするなど、そこそこ複雑な計算順序がありましたが、今回はそこまで精密に再現せず、補正値(...

プログラミングとは?現役システムエンジニアが教える裏事情
プログラミング
システムエンジニア,プログラマー
プログラミングとは?現役システムエンジニアが教える裏事情

  プログラミングってよくわからない? 実際に何をやっているの?   最近注目されているSE(システムエンジニア)やPG(プログラマー)という職業ですが、「そもそもプログラミングとは?」といった疑問を抱えている方も多いですね。 今回は、そういった方へ向けて「プログラミングの基礎知識と裏事情」...

カテゴリ

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