プログラミング

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

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

 

注目の記事

WordPressのJSファイル読み込みで覚えておきたい便利ワザを2つ紹介します
プログラミング
jQuery,PHP,WordPress
WordPressのJSファイル読み込みで覚えておきたい便利ワザを2つ紹介します

  JSファイルを読み込むときに、deferやasyncを付与したい・・・ get_template_directory_uri()をJSファイル内で使用したい・・・   WordPressには便利な関数が沢山用意されていますが、その全てが万能だということはありません。 今回はSEO対策でも必要になるdeferやasyncをスクリプトタグに付与させる...

ブラウザで遊べる「PHPポケモン」
プログラミング
PHP,PHPポケモン,ポケモン
ブラウザで遊べる「PHPポケモン」

PHPポケモン 約1ヶ月半をかけて作り込んできたPHPポケモンですが、ある程度遊べるぐらいのレベルになったので、みなさまにも体験・楽しんでいただけるよう本日(2020年10月12日)より一般公開します。   PHPポケモンへのリンクは本記事の最後に用意しておりますので、プレイする前に注意事項等に目を通し...

【関数とは】初心者が最短でPHPを使えるようになるための実践的な学び方
プログラミング
function,PHP
【関数とは】初心者が最短でPHPを使えるようになるための実践的な学び方

  PHPを実践で使えるレベルまで押し上げるための初心者向け講座、第3回目は「関数」です。   第1回の変数、第2回の配列、そして今回の関数の3つをマスターできていれば、いざ業務に望んでも、ある程度通用すると思っておいて良いでしょう。  ※オブジェクト指向やクラスの理解、データベースの知識など、...

CSSとの意外な関係「よくわかるSEO対策」スタイルシート編
SEO対策
CSS,スタイルシート,レンダリング
CSSとの意外な関係「よくわかるSEO対策」スタイルシート編

   今回の「よくわかるSEO対策」はスタイルシート(CSS)編です。   多くの人が 「SEO対策なのに、CSSの説明をするの?」 と思うかも知れませんが、これには意外な関係性があったのです。   現在CSSを学んでいる人、そしてCSSの書き方ならマスターしているといった人でも、SEOのことまでを考慮した記述ができて...

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

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

会話スキルに自信がない人必見!会議やミーティングで失敗しないコツとは
雑記
Skype,Zoom
会話スキルに自信がない人必見!会議やミーティングで失敗しないコツとは

  話下手なので会議で置物状態 Zoomミーティングは発言しづらい 会議の時間が退屈で無駄   そんな悩みや不満を抱えている方はいませんか? 確かに会議は退屈ですし、話下手な人からすれば嫌な時間の1つかも知れませんね。 ですが、立ち回りのポイントを3つ押さえておくだけで、無駄・退屈だと感じて...

たった2日で200万円!フリーランスが簡単に仕事を受注できる方法とは
マーケティング
コロナ,フリーランス,ホームページ制作,助成金
たった2日で200万円!フリーランスが簡単に仕事を受注できる方法とは

  仕事の依頼が全然来ない・・・ 営業しても話を聞いてくれない・・・   その多くが営業力以上に、営業をすべきタイミングがわかっていない人がほとんどです。 実は助成金等を活用することで、行政書士などの職業以外でも仕事を受注することは可能になります。   今回は筆者が、たった2日で200万...

OSI参照モデルとTCP/IP 〜ネットワークモデルとは〜【第3回 ド素人のためのネットワーク講座】
ネットワーク
OSI参照モデル,TCP/IP,ネットワークモデル,プロトコル
OSI参照モデルとTCP/IP 〜ネットワークモデルとは〜【第3回 ド素人のためのネットワーク講座】

  ド素人のためのネットワーク講座! 栄えある第3回は「ネットワークモデル」についてです。   横文字や英字が多くなってきたり、歴史的経緯が関係してきたりとややこしくなってくる部分ですが、ネットワークを理解するためには押さえておきたいポイントです。   プログラミングやシステムエンジニアとし...

カテゴリ

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