プログラミング

PHPポケモン「タイプ実装編」15

PHP PHPポケモン ポケモン
PHPポケモン「タイプ実装編」15

ポケモンのタイプについて

 2020年剣盾シリーズでのポケモンでは、全18タイプが実装されています。初代では15タイプ(あく、はがね、フェアリーを除く)からスタートして、たった3つのタイプしか増えていない、と感じる方もいるかも知れませんが、この追加に関してもバトルの歴史を大きく動かしてきたのです。また、タイプ相性についても世代を重ねるごとに改変されています。

 

PHPポケモンでは、現在リリースされている18タイプを参考に作成していきます。ポケモンだけではなく、技のタイプについても同様です。

  • ポケモンが覚える技:初代
  • 種族値:最新
  • 技効果:最新
  • タイプ:最新

 

クラスの作成

技やポケモンに比べると情報量は少ないと言えますが、相性などを設定する関係上、タイプに関してもそれぞれクラスを作成し、親となる「タイプ(type)」というクラスを継承させる仕様で進めていきます。

 

子クラス

 まずは子クラスです。手始めにでんき(Electric)を作成しましょう。

 

でんきタイプ(/Classes/Type/Electric.php
<?php
require_once(__DIR__.'/../Type.php');
 
// でんきタイプ
class Electric extends Type
{
 
    /**
    * 正式名称
    * @var string
   */

    protected $name = 'でんき';
 
    /**
    * 攻撃技で使用したときの判定
    */
 
    /**
    * こうかばつぐん
    * @var integer
    */
    protected $excellent = ['Water', 'Flying'];
 
    /**
    * こうかいまひとつ
    * @var integer
    */
    protected $not_very = ['Electric', 'Grass', 'Dragon'];
 
    /**
    * こうかがない
    * @var integer
    */
    protected $doesnt_affect = ['Ground'];
 
}

 ※親クラスは想定で準備しています

 

技の相性判定をするためには、その関係性を持たせて置く必要があります。今回は「実装するタイプクラスで攻撃した場合」の相性をプロパティとして設定しています。

/**
* こうかばつぐん
* @var integer
*/
protected $excellent = ['Water', 'Flying'];

 

例えば、でんきタイプの技は、みず(Water)とひこう(Flying)に相性がよく「こうかばつぐん」です。ダメージの計算上は2倍のダメージ量を与えることができます。もし攻撃した側のexcellentプロパティに受け手側のタイプが含まれているかどうかをチェックすることで判定します。

 

もちろん相性が悪いタイプもあります。その第1段階をnot_varyのプロパティに設定します。

/**
* こうかいまひとつ
* @var integer
*/
protected $not_very = ['Electric', 'Grass', 'Dragon'];

 

でんきタイプの攻撃は、でんき(Electric)とくさ(Grass)とドラゴン(Dragon)の3タイプに相性が悪く、通常の0.5倍のダメージ量しか与えることができません。

 

相性が悪いタイプについては、2段階で構成されており、もう一つをdoesnt_affectのプロパティに設定します。

/**
* こうかがない
* @var integer
*/
protected $doesnt_affect = ['Ground'];

 

でんきタイプの攻撃は、じめん(Ground)には全く効果がありません。0倍のダメージ量です。もし相手のタイプが、みず・じめんの2つを備えていた場合、有利タイプがあったとしてもダメージは与えられません。

 

ポケモンは最大2つのタイプを備えているため、ダメージの判定は以下の6通りから構成されることになります。 

4倍・2倍・1倍・0.5倍・0.25倍・0倍

 

設定例として御三家で使用する「みず・ほのお・くさ・どく」の4タイプ分のサンプルコードを載せておきます。残りの13タイプは相性表を参考に作成してみてください。

ポケモンwiki(第6世代以降を参照)

 

みずタイプ(/Classes/Type/Water.php
<?php
require_once(__DIR__.'/../Type.php');
 
// みずタイプ
class Water extends Type
{
 
    /**
    * 正式名称
    * @var string
    */
    protected $name = 'みず';
 
    /**
    * 攻撃技で使用したときの判定
    */
 
    /**
    * こうかばつぐん
    * @var integer
    */
    protected $excellent = ['Fire', 'Ground', 'Rock'];
 
    /**
    * こうかいまひとつ
    * @var integer
    */
    protected $not_very = ['Water', 'Grass', 'Dragon'];
 
    /**
    * こうかがない
    * @var integer
    */
    protected $doesnt_affect = [];
 
}

 

ほのおタイプ(/Classes/Type/Fire.php
<?php

require_once(__DIR__.'/../Type.php');
 
// ほのおタイプ
class Fire extends Type
{
 
    /**
    * 正式名称
    * @var string
    */
    protected $name = 'ほのお';
 
    /**
    * 攻撃技で使用したときの判定
    */
 
    /**
    * こうかばつぐん
    * @var integer
    */
    protected $excellent = ['Grass', 'Ice', 'Bug', 'Steel'];

    /**
    * こうかいまひとつ
    * @var integer
    */
    protected $not_very = ['Fire', 'Water', 'Rock', 'Dragon'];
 
    /**
    * こうかがない
    * @var integer
    */
    protected $doesnt_affect = [];
 
}

 

くさタイプ(/Classes/Type/Grass.php
<?php

require_once(__DIR__.'/../Type.php');
 
// くさタイプ
class Grass extends Type
{
 
    /**
    * 正式名称
    * @var string
    */
    protected $name = 'くさ';
 
    /**
    * 攻撃技で使用したときの判定
    */
 
    /**
    * こうかばつぐん
    * @var integer
    */
    protected $excellent = ['Water', 'Ground', 'Rock'];
 
    /**
    * こうかいまひとつ
    * @var integer
    */
    protected $not_very = ['Fire', 'Grass', 'Poison', 'Flying', 'Bug', 'Dragon', 'Steel'];
 
    /**
    * こうかがない
    * @var integer
    */
    protected $doesnt_affect = [];
 
}

 

どくタイプ(/Classes/Type/Poison.php
<?php

require_once(__DIR__.'/../Type.php');

// どくタイプ
class Poison extends Type
{
 
    /**
    * 正式名称
    * @var string
    */
    protected $name = 'どく';

    /**
    * 攻撃技で使用したときの判定
    */
 
    /**
    * こうかばつぐん
    * @var integer
    */
    protected $excellent = ['Grass', 'Fairy'];
 
    /**
    * こうかいまひとつ
    * @var integer
    */
    protected $not_very = ['Poison', 'Ground', 'Rock', 'Ghost'];
 
    /**
    * こうかがない
    * @var integer
    */
    protected $doesnt_affect = ['Steel'];
 
}

 

親クラス

 次に親クラスになるType.phpを作成しましょう。

 

タイプ(/Classes/Type.php
<?php
 
// タイプ
abstract class Type
{
 
    /**
    * インスタンス作成時に実行される処理
    *
    * @return void
    */
    public function __construct()
    {
        //
    }
 
    /**
    * タイプ名の取得
    *
    * @return string
    */
    public function getName()
    {
        return $this->name;
    }
 
    /**
    * 攻撃で有利なタイプ
    *
    * @return array
    */
    public function getAtkExcellentTypes()
    {
        return $this->excellent;
    }
 
    /**
    * 攻撃で相性が悪いタイプの取得
    *
    * @return array
    */
    public function getAtkNotVeryTypes()
    {
        return $this->not_very;
    }
 
    /**
    * 攻撃で全く効果が無いタイプの取得
    *
    * @return array
    */
    public function getAtkDoesntAffectTypes()
    {
        return $this->doesnt_affect;
    }

}

 

タイプクラスもインスタンス化する必要がないため、abstractを宣言しています。

今回はgetNameのプロパティしか使用しませんが、残りの関係タイプも取得できるようにしておきましょう。

 

ポケモンへの実装

 それではポケモンにタイプを割り当てしていきましょう。今回もピカチュウを例に実装します。

 

ピカチュウ(/Classes/Pokemon/Pikachu.php
<?php
 
require_once(__DIR__.'/../Pokemon.php');
require_once(__DIR__.'/Raichu.php');
 
// ピカチュウ
class Pikachu extends Pokemon
{
 
    /**
    * 正式名称
    * @var string(min:1 max:5)
    */
    protected $name = 'ピカチュウ';

    /**
    * タイプ
    * @var array
    */
    protected $types = ['Electric'];

 

ピカチュウに対して、typesというプロパティを割り当てました。ピカチュウは1タイプだけですが、フシギダネなど2タイプを持つポケモンもいるため、配列で用意します。

 

次にタイプの取得用メソッド(getTypes)をGetトレイトに作成しましょう。

 

Get格納トレイト(/Traits/Pokemon/GetTrait.php
/**
* タイプの取得
*
* @param string|array|object $return
* @var void
*/
public function getTypes($return='object')
{
    /**
    * タイプ名の取得用関数
    * @param object
    * @var string
    */
    function getTypesName($obj){
        return $obj->getName();
    }
    // array_mapで配列内のタイプクラスをインスタンス化
    $types = array_map([$this, 'getInstance'], $this->types);
    switch ($return) {
        case 'string':
        // array_mapでタイプ名の配列にしたものを、implodeで文字列に変換
        $types = implode(',', array_map('getTypesName', $types));
        break;
        case 'array':
        // array_mapでタイプ名の配列にして返却
        $types = array_map('getTypesName', $types);
        break;
    }
    return $types;
}

 

引数で返却する型を指定できるようにしておきます。タイプはそのまま取得すればクラス名が入った配列です。しかし、出力画面で使用するためには、格納されている各タイプがインスタンス化されているかクラスで設定した名称が取得できなければなりません。状況に合わせて様々な型を受け取れるように、仮でstringarrayobjectの3つを用意しました。

 

それではメソッド内の中腹部分から見てみましょう。

// array_mapで配列内のタイプクラスをインスタンス化
$types = array_map([$this, 'getInstance'], $this->types);

 

まずは、配列に格納されているクラスを全てインスタンス化しなければなりませんので、前回技のインスタンス化をした要領でarray_mapをかけています。コールバック関数を使い回すため、今回はgetInstanceというメソッドを新しいトレイトに作成しました。

 

インスタンス化用トレイト(/Traits/InstanceTrait.php
<?php
trait InstanceTrait
{
    /**
    * インスタンス化関数
    * @param string $class_name
    * @return object
    */
    protected function getInstance($class_name){
        if(class_exists($class_name)){
            return new $class_name();
        }
    }
 
}

 

前回の技取得のコールバック関数で使用したgetMoveInstanceの関数と内容は同じです。こちらのトレイトをポケモンクラスで読み込んでおきましょう

 

Getトレイトの記述に戻ります。次に返り値を引数に合わせて返却するため、switchを使用します。

switch ($return) {
    case 'string':
    // array_mapでタイプ名の配列にしたものを、implodeで文字列に変換
    $types = implode(',', array_map('getTypesName', $types));
    break;
    case 'array':
    // array_mapでタイプ名の配列にして返却
    $types = array_map('getTypesName', $types);
    break;
}
return $types;

 

objectの場合は、そのままを返却するため省略しています。文字列(string)であれば、「くさ,どく」のような形式で返却したいので、インスタンス化したタイプから名前を抽出し、それをimplodeを使って文字列に直します。ここで名前を抽出するために、最初に記述したタイプ名の取得関数を使用します。

/**
* タイプ名の取得用関数
* @param object
* @var string
*/
function getTypesName($obj){
    return $obj->getName();
}

 

受け取ったタイプのオブジェクト(インスタンス)から名前を取得して返却しています。array_mapの返り値は以下のようになっています。

# ピカチュウの場合
['でんき']
 
# フシギダネの場合
['くさ', 'どく']

 

文字列(string)の場合は作成できた配列をimplode、配列希望の場合はそのまま返却しています。

 

それではタイプをポケモンの詳細取得メソッド(getDetails)に追加しましょう。

 

Get格納トレイト(/Traits/Pokemon/GetTrait.php
/**
* 詳細を取得する
* @return integer
*/
public function getDetails()
{
    return [
        '正式名称' => $this->getName(),
        'ニックネーム' => $this->getNickName(),
        'タイプ' => $this->getTypes('string'),
        '現在のレベル' => $this->getLevel(),
        '現在の経験値' => $this->getExp(),
        '次のレベルまで' => $this->getReqLevelUpExp(),
    ];
}

 

出力結果は以下の通りです。

 

 

 

 

技への実装

 

前回実装した技にもタイプが割り振られています。なので、技のタイプ取得用メソッドにも同様の処理を記述します。

 

技クラス(/Classes/Move.php
<?php
require_once(__DIR__.'/../Traits/InstanceTrait.php');
 
// 技
abstract class Move
{
    use InstanceTrait;
 
    /**
    * インスタンス作成時に実行される処理
    *
    * @return void
    */
    public function __construct()
    {
        //
    }
 
--省略
 
    /**
    * タイプの取得
    *
    * @return object
    */
    public function getType()
    {
        return $this->getInstance($this->type);

    }

 

まずは先程作成した、インスタンス化用のトレイトを読み込んでおきます。ポケモンと違い、タイプが配列ではないので、そのままgetInstanceのメソッドにタイプのプロパティ($this->type)をかけてあげるだけでタイプのインスタンスを返すことができます。

 

今回は名前の取得は出力画面側で対応します。

 

出力用ファイル(/index.php
<?php # 覚えている技 ?>
<table class="table table-bordered table-hover">
    <thead class="thead-light">
        <tr>
            <th scope="col">覚えている技</th>
            <th scope="col">タイプ</th>
            <th scope="col">PP</th>
        </tr>
    </thead>
    <tbody>
        <?php foreach($controller->pokemon->getMove() as $move): ?>
            <tr>
                <th scope="row" class="w-50"><?=$move->getName()?></th>
                <td><?=$move->getType()->getName()?></td>
                <td><?=$move->getPp()?>/<?=$move->getPp()?></td>
            </tr>
        <?php endforeach; ?>
    </tbody>
</table>

 

タイプ用に名称横に1列追加しました。タイプ名の取得は、$move->getType()->getName()のように、メソッドをつなぎ合わせていきながら出力しています。

 

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

 

 

それぞれに割り当てたタイプが出力されていますね。これでタイプシステムの実装が完了です。

  

まとめ

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

今回のPHPポケモンは「タイプ実装編」についてご紹介しました。

技、タイプが揃えば、バトルシステムに必要な要素が整いました。よりポケモンらしくなったとも言えるでしょう。

ゲームやポケモン好きな人プログラミング学習中の方は、ぜひ参考にしてくださいね。

 

注目の記事

進化の石編(構成) PHPポケモン 102
プログラミング
PHP,PHPポケモン,ポケモン
進化の石編(構成) PHPポケモン 102

進化の石 ピカチュウさんもそろそろ進化したがっているので、β版の公開に向けて進化の石を実装していきます。しかし、イーブイなど特別な進化先や条件を持ったポケモンを考慮すると、少し実装が手間取りそうだったので、今回は構成部分のみのまとめとなっておりますので、ご了承ください。   アイテムクラスの作...

【Laravel7】バリデーションメッセージの日本語化【6系対応】
プログラミング
Laravel,Linux,PHP
【Laravel7】バリデーションメッセージの日本語化【6系対応】

  Laravelのバリデーションメッセージは標準だと英語で返ってきてしまいますね。 1つずつ変更する方法もありますが、言語ファイルを作成して一括変更するほうが開発時間の短縮に繋がります。   今回は「Laravel7のバリデーションメッセージを日本語化する方法」をご紹介します。Laravel6系でも同じ方法ででき...

戦闘用アイテム編 プラスパワー PHPポケモン96
プログラミング
PHP,PHPポケモン,ポケモン
戦闘用アイテム編 プラスパワー PHPポケモン96

戦闘用アイテムとは バトル中に使用できるアイテムはいくつかありますが、その中でも「バトル専用」のアイテムがあります。それが戦闘用アイテムであり、主にドーピングと呼ばれるものです。 アイテムカテゴリとして、プレイヤー対象(スプレーなど)、敵ポケモン対象(ボール類)、味方対象(キズぐすり)の3つに...

なぜプロは有線のマウスやキーボードを選ぶのか?【有線VS無線】
雑記
Bluetooth
なぜプロは有線のマウスやキーボードを選ぶのか?【有線VS無線】

  無線が普及する現代、何故有線のマウスやキーボードは売れているのか   いろんなものが製品の進化と共に無線化している一方、有線の需要も高く、とくにプロなど上層で活躍する人は有線を選択するケースが少なくありません。 今回は、そんな有線と無線の違いや、それぞれのメリットについて解説していき...

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

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

Toastr(トースト)活用編 PHPポケモン 100
プログラミング
JavaScript,PHP,PHPポケモン,ポケモン
Toastr(トースト)活用編 PHPポケモン 100

記念すべき第100回目です!   色々考えましたが、100回目だからと言って特別な内容ではなく、いつもの流れの延長での開発進行となります。ご了承ください。 今回は、何人かのプレイユーザーの声も参考にしながら、ユーザビリティをあげるための機能追加を進めていきます。   Toastr(トースト)と...

PHPポケモン(α)攻略wiki「最初のポケモン」
雑記
PHPポケモン,wiki,ポケモン
PHPポケモン(α)攻略wiki「最初のポケモン」

リリースから一ヶ月、遂にPHPポケモン(α)の攻略Wiki(仮)が公開です!   というのは大嘘で、内部の大幅変更の関係上、今回はPHPポケモンをプレイするにあたってのオススメなどをまとめて見た次第です。 ちなみに、バトルシステム自体は本家に沿って作成しているので、種族値や技性能に精通している人はブラウザ...

PHPポケモン「バトルシステム編 〜バトル終了判定〜」28
プログラミング
JavaScript,jQuery,PHP,PHPポケモン,ポケモン
PHPポケモン「バトルシステム編 〜バトル終了判定〜」28

バトル終了判定 今回はバトル終了判定を実装しましょう。今までは「にげる」による戦闘離脱のみで、ひんし状態でも殴り合うことが出来たので、それを解消するためにも戦闘結果による判定を導入します。   ひんし状態の監視 まずは「ひんし」の監視です。現在は交代ポケモンどちらか一方がひんし状態になれば、そ...

カテゴリ

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