プログラミング

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ポケモンは「タイプ実装編」についてご紹介しました。

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

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

 

注目の記事

フォームはもう古い?サイトのCVRを高くするチャットシステムとは
マーケティング
CVR,ECショップ
フォームはもう古い?サイトのCVRを高くするチャットシステムとは

  サイトのコンバージョン率を上げたい お問い合わせフォームから連絡が来ない   ちょっとWebサイトやネットショップを立ち上げても中々思うような結果につながらない時代になりました。数多くのサイトが出回っていることはもちろん、ユーザーの閲覧頻度が増えて目が肥えているというのも大きな理由の1...

これをしてはいけません!「よくわかるSEO対策」エンジニアのための基礎知識編
SEO対策
htaccess,HTML,JavaScript,SEO,エンジニア,プログラミング
これをしてはいけません!「よくわかるSEO対策」エンジニアのための基礎知識編

  近年ではWebサイト制作会社や個人事業主はかなり増えてきました。 会社によっては力を入れている部分は異なり、主に「デザイン」「機能(システム)」「SEO」という3つに分けられます。 飽和しているのでは無いかと囁かれている中、この3つすべてを揃えた事業者は意外と少なく、個人となれば更に少なくなります。...

3日坊主にならないために
雑記
ブログ,プログラミング
3日坊主にならないために

  プログラミングに挑戦してみたが、途中で挫折した人 ブログを書き始めたが、まったく続かない人   継続することの大切さは分かっても、なかなか難しいものです。 しかしそれは、取り組み方を見直すだけで、実は簡単に解決できてしまうものなのです。 今回は、そんな「3日坊主」と呼ばれる人が、そ...

経験値取得アニメーション編(動画有り) PHPポケモン 47
プログラミング
PHP,PHPポケモン,ポケモン
経験値取得アニメーション編(動画有り) PHPポケモン 47

経験値取得アニメーションの実装 最近は技の実装が続いていたので、気分転換にフロント側の演出づくりをしていきます。その中でも今回実装するのは「経験値取得アニメーション」です。 経験値バーはポケモンの第2世代から追加実装された演出です。初代では次のレベルにアップするまでの数値を、わざわざポケモンの...

進化直後の技習得編 PHPポケモン 65
プログラミング
PHP,PHPポケモン,ポケモン
進化直後の技習得編 PHPポケモン 65

進化直後の技習得 パーティー機能を導入に合わせて、至る場所を修正することになり、合わせて未実装だった機能を導入していきます。 見た目にはわからない部分や、とある条件が重ならなければ起こらない部分の作り込みが多いため、プレイユーザー目線からすると少し面白みが無いかも知れません。 ですが、そういっ...

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

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

へんしん編 PHPポケモン 74
プログラミング
PHP,PHPポケモン,ポケモン
へんしん編 PHPポケモン 74

へんしんとは 今回はサムネイルに合わせて、特別技の1つ「へんしん」を実装します。  へんしん https://wiki.ポケモン.com/wiki/へんしん   へんしんを使うことで、相手ポケモンをコピーすることができますが、その全てをコピーするわけではありません。コピーできる項目とそうでない項目は以下の通りで...

食に関する考察 自炊と節約は成立するのか?
雑記
食に関する考察 自炊と節約は成立するのか?

スキル関係の記事が多めの当ブログですが、今回は「食」をテーマに触れていきます。突き詰めていけば食も立派なスキルであり、奥が深いものです。更に、生活の基盤となるため多くの人がこの問題に直面することであり、健康とも直結するため仕事などにおけるパフォーマンスにも大きく関係します。   これから一人暮ら...

カテゴリ

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