プログラミング

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計算〜」についてご紹介しました。

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

 

注目の記事

ゆびをふる編 PHPポケモン 69
プログラミング
PHP,PHPポケモン,ポケモン
ゆびをふる編 PHPポケモン 69

ゆびをふるとは 今回PHPポケモンで実装する技は「ゆびをふる」です。  ゆびをふる(ポケモンwiki) https://wiki.ポケモン.com/wiki/ゆびをふる   「ゆびをふる大会」というゆびをふるのみを使った大会なども開催されているということもあり、ポケモンの技の中でも初代から長く愛されてきた1つです。で...

フリーランスなら心がけておきたい3つのルール【仕事と遊びは両立させろ】
フリーランス
フリーランス,独立
フリーランスなら心がけておきたい3つのルール【仕事と遊びは両立させろ】

  フリーランスになっても不安がいっぱい   会社というものに縛られないというのは楽なイメージがありますが、それ相応の不安がついてまわります。 その結果、会社員へと舞い戻ってしまうと再度そこから抜け出すことは非常に困難です。   今回は、現在活動している人や、これから独立しようとしている...

プログラミングで躓く人必見!一人前になるためのSDCとは
プログラミング
プログラミング学習
プログラミングで躓く人必見!一人前になるためのSDCとは

  「プログラミング学習を始めたけど中々身につかない」 「挑戦したいけど何から始めればいいかわからない」   プログラミング教育が始まるとともに、プログラミング学習のニーズも日々高まってきています。ですが、興味はあっても中々挑戦までは至らなかったり、始めたは良いものの現実は厳しく躓いてし...

プレイヤーのグローバル化編 PHPポケモン 78
プログラミング
PHP,PHPポケモン,ポケモン
プレイヤーのグローバル化編 PHPポケモン 78

2日ほどwiki作成にいそいそと励んでいましたが、開発をお休みしていたわけではありません。追加機能を実装するに辺り、色々と改善点が挙がってきたので、このタイミングでしっかりと見直しをしました。   本格的なシステム開発では、最初に仕様書や設計書が作成され、それに沿って作成していくことになります...

【Wi-Fi6とは】スマホやPCの買い替えは必要?騙されないための基礎知識
ネットワーク
5G,IEEE 802.11ax,Wi-Fi
【Wi-Fi6とは】スマホやPCの買い替えは必要?騙されないための基礎知識

  本格的に5G普及への取り組みが始まり、Wi-Fi6といった新世代の規格が出たことによって、超情報化社会へ加速しました。 ですが、こういったナンバリングが一般化することによって、わからずに高性能な機器を斡旋されて無駄な購入をさせられたり、わからないことを理由に詐欺的営業を仕掛けてくる悪意ある人...

人員配置計算機〜放課後等デイサービス・児童発達支援〜
プログラミング
JavaScript,児童デイ,児童発達支援,放課後等デイサービス,福祉,計算機
人員配置計算機〜放課後等デイサービス・児童発達支援〜

最近はずっとPHPポケモン開発にかかりっきりでしたが、そろそろ「役立つもの」を作りたくなったので、思いつきで作ってみました。 もちろん「汎用性」のあるものは、既に世の中に存在しているため、ありそうでなさそうなニッチなものを攻めてみます。   そんな中、今回挑んだのは「人員配置計算機」です。 ※実際に...

毎日継続をするためのコツ
雑記
毎日継続をするためのコツ

定期的にコラムを書きたくなるので、今回は「毎日継続をするためのコツ」というテーマで自分が意識していることや、感じたことを書き綴っていきます。 決して開発や業務で追われていたり、PHPポケモンの大幅見直しを迫られているわけではありません。   毎日継続するために  ブログや学習など、毎日継続...

両隣のポケモン取得編(配列の隣の要素)PHPポケモン 92
プログラミング
PHP,PHPポケモン,ポケモン
両隣のポケモン取得編(配列の隣の要素)PHPポケモン 92

両隣のポケモンを判別する パーティーの中からID指定でポケモンを特定するためのメソッドは実装されていましたが、その両隣にどんなポケモンが控えているのかを判別する手段がありませんでしたね。 なので、今回は両隣のポケモンを判別するためのメソッドを準備して活用していきましょう。   パーティー まずは...

カテゴリ

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