プログラミング

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

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

 

注目の記事

英語できたらブログで稼げる 【ネオコピペ】
ライティング
ブログ,翻訳,英語
英語できたらブログで稼げる 【ネオコピペ】

  2010年に楽天が社内公用語の英語化を宣言したのは、多くの人が耳にしたことがあるでしょう。 私からすると、「英語ができることは強み」だという考えから、「これからは英語ができないと行きていけないのでは?」と考えを変えさせられるような、そんな出来事でした。   多言語できるデメリットを見つけるのは難...

バトル状態のクラス化編 PHPポケモン 67
プログラミング
PHP,PHPポケモン,ポケモン
バトル状態のクラス化編 PHPポケモン 67

バトルの状態 PHPポケモンでも様々な技を再現してきましたが、まだまだ未実装のものはたくさんあります。そのほとんどがイレギュラー処理の必要なものだったりします。 それらをしっかりと解決していくためにも、今回は「バトル状態」をひとまとめに管理できるようにシステムの見直しを行います。   ひとまとめに...

忘れさせる技選択 後編(新しい技を習得) PHPポケモン 56
プログラミング
PHP,PHPポケモン,ポケモン
忘れさせる技選択 後編(新しい技を習得) PHPポケモン 56

新しい技を習得 前編に続き、技習得時の処理分岐を作成していきましょう。今回は「新しい技を習得する」です。 前回は覚えようとしている技を諦めるだけだったので、ポケモンのオブジェクトを書き換える必要がありませんでしたね。ですが、新しく覚えようとしている技を既に覚えている技と置き換える場合は、ポケモ...

手っ取り早く情報強者になる簡単な方法
雑記
アウトプット,インプット,ニュース
手っ取り早く情報強者になる簡単な方法

  ニュースや情報番組、討論番組をみると、出演者の方々の情報量の多さに圧倒されることがあります。 また、ユニークな考え方に共感を得る人も多いでしょう。   どうやって、情報を仕入れているのか? なぜそんなことまで知っているのか?   メディアで取り上げられているような人や、活躍している人の多く...

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

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

20代起業家が教える「やっといて良かった」3つのコト
雑記
起業
20代起業家が教える「やっといて良かった」3つのコト

  「起業するために何を準備すべき?」 「やっておいて良かったことはありますか?」   独立や起業をしようと志している人のほとんどが、こういった質問を投げかけてきます。自分も同じような悩みを持った立場の時には似た質問をしていたので、その真意はよくわかります。   今回はそんな悩みを抱えて...

具体的にフリーランスで生きていくには -独立してからの働き方を徹底解説-
フリーランス
フリーランス,独立
具体的にフリーランスで生きていくには -独立してからの働き方を徹底解説-

  安定した仕事に就きたい。。。   多くの人がそう思っていた時代はどんどんと変化して、今やフリーランスでいることの方が安定しているのではないかと言えるような時代です。 そう、もはや会社員でいる人の大半が安定ではなくなってきているのです。 フリーランスでいる人も、根本的に安定という...

EC-CUBE4内にWordPressを設置(共存)する方法
SEO対策,プログラミング
EC-CUBE4,PHP,Symfony,Twig,WordPress
EC-CUBE4内にWordPressを設置(共存)する方法

今回使用したバージョン EC-CUBE4.0.5 WordPress5.6 ※EC-CUBE4、WordPressのカスタマイズは自己責任でお願いします。また、現在稼働中のサイトで試す際には、必ずバックアップを取ってから行なうようにしてください。   EC-CUBE4とは ネットショップを作るとなれば、様々なサービスが出回っ...

カテゴリ

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