ポケモン図鑑とは
ポケモンに出会ったり、仲間にしたりすると、ポケモン図鑑のデータがどんどんと埋まっていきます。PHPポケモンでもこの仕組みを実現させるために、ポケモン図鑑を作成していきましょう。
クラスによる管理
ポケモン図鑑はクラス管理をしていきます。プレイヤー1人に対して1つのポケモン図鑑が与えられるため、プレイヤーのプロパティとして図鑑(pokedex)を持たせ、そこにクラスを格納します。
ポケモン図鑑(/Classes/Pokedex.php)
<?php
$root_path = __DIR__.'/..';
// ポケモン図鑑
class Pokedex
{
/**
* ポケモン図鑑([pokemon_number => int])
* 0: 未発見
* 1: 見つけた
* 2: 捕まえた
* @var array
*/
protected $pokedex = [];
/**
* @return void
*/
public function __construct()
{
//
}
}
ポケモン図鑑へのデータ格納ですが、ボックスと同じくポケモンのオブジェクトをそのまま保管すればシリアライズの負荷が大きくなります。だからと言って大量のデータを突っ込むとしても、後ほど情報が増えた際の処理も面倒です。
なので、図鑑には「未発見」「見つけた」「捕まえた」の3つの判定情報だけを以下のように格納します。
図鑑No(key) => 判定値
判定値
0 → 未発見
1 → 見つけた
2 → 捕まえた
図鑑データの準備
図鑑用のデータですが、ポケモンクラスにそれぞれもたせると管理が大変ですし、図鑑を閲覧する際にわざわざオブジェクトへアクセスする必要があります。その処理を省くためにも、図鑑データはconfigファイルとして別で用意していきます。
ポケモン図鑑config(/Config/pokedex.php)
<?php
return [
1 => ['Fushigidane', 'フシギダネ', 'たねポケモン', '生まれたときから 背中に 植物の タネが あって 少しずつ 大きく 育つ。'],
2 => ['Fushigisou', 'フシギソウ', 'たねポケモン', '背中の つぼみが 大きく 育ってくると 2本脚で 立つことが できなくなるらしい。'],
3 => ['Fushigibana', 'フシギバナ', 'たねポケモン', '2本の ふとい ツルを 振りまわし 戦う。 10階建ての ビルを かるく なぎ倒すほど パワフルだ。'],
4 => ['Hitokage', 'ヒトカゲ', 'とかげポケモン', '熱いものを 好む 性格。 雨に濡れると しっぽの 先から 煙が 出るという。'],
5 => ['Lizardo', 'リザード', 'かえんポケモン', '燃える しっぽを 振りまわし するどい ツメで 相手を 切り裂く 荒々しい 性格。'],
6 => ['Lizardon', 'リザードン', 'かえんポケモン', '岩石も 焼けるような 灼熱の 炎を 吐いて 山火事を 起こすことが ある。'],
7 => ['Zenigame', 'ゼニガメ', 'かめのこポケモン', '長い 首を 甲羅のなかに 引っこめるとき 勢いよく 水鉄砲を 発射する。'],
8 => ['Kameil', 'カメール', 'かめポケモン', '長生きの シンボルと されている。 甲羅に 苔が ついているのは とくに 長生きの カメールだ。'],
9 => ['Kamex', 'カメックス', 'こうらポケモン', '精密な 射撃は 苦手。 31門の 大砲で 撃って撃って 撃ちまくる スタイルで 攻めるのだ。'],
];
0番目にはクラス名、1番目にポケモンの名称、その後ろに図鑑情報を順番に格納しています。
では、図鑑の登録状況を判定するためのメソッドを、ポケモン図鑑クラスに追加しましょう。
/**
* 図鑑の登録状況を確認
* @param number:integer
* @return integer
*/
public function isRegisted(int $number): int
{
return $this->pokedex[$number] ?? 0;
}
isRegistedでは、現在の登録状態を返却しています。もし配列自体が存在していなかったり、0番がセットされていれば未登録としてfalse、1番以上の数値が格納されていればtrueを返却しています。
出会ったことのないポケモンの行は存在しませんが、フシギダネとピカチュウが登録されている場合であれば、その間の2番から24番までの空データを登録する必要があります。その際には0が返ってくるため、存在確認と値の確認の2重チェックが必要です。
見つけた
野生のポケモンと出逢えば、そのポケモン情報が格納されます。捕まえたことは無いけれど、出会ったことがある状態は「1」で判定するため、こちらの値をセットする用のメソッドを追加しましょう。
/**
* 発見
* @param pokemon:object::Pokemon
* @return void
*/
public function discovery(object $pokemon): void
{
// 発見済みの場合は処理中断
if(
!is_a($pokemon, 'Pokemon') ||
($this->pokedex[$pokemon->getNumber()] ?? 0) >= 1
){
return;
}
// 追加
$this->pokedex[$pokemon->getNumber()] = 1;
// 図鑑の歯抜けを空データで埋める
$this->fillSpace();
}
discoveryメソッドでは、ポケモンの登録状態を確認し、存在していなかったり0(未発見)で登録されていれば、1をセットしています。歯抜けになっている部分を0の配列で埋める必要があるのでこちらはfillSpaceメソッドを使って処理をしましょう。
/**
* 図鑑の歯抜けを空データで埋める
* @return void
*/
private function fillSpace()
{
// まずキーを基準に並び替えをする
ksort($this->pokedex);
// 最初と最後のキーを取得
$first = array_key_first($this->pokedex);
$last = array_key_last($this->pokedex);
// 現在の図鑑の最初から最後までの番号の空データを作成
$empty_array = array_fill($first, $last - $first + 1, 0);
// 空配列と図鑑のポケモンの数が同じの場合は埋め処理不要
if(count($empty_array) === count($this->pokedex)){
return;
}
// 配列を加算(array_mergeは番号が採番されるため使用しない)
$this->pokedex += $empty_array;
// 最後に再度並び替えを実行
ksort($this->pokedex);
}
まず初めに並び替え処理をして、配列内を番号順に正します。そこから最初のキーと最後のキーを取り出し、array_fillで必要行分の空(0)データの配列を作成します。
array_fill(PHP.net)
もし配列の個数が等しければ歯抜け処理は不要になるので処理を中断、差分があれば、pokedexプロパティを基準に穴埋めデータを加算します。これで、データが存在していない位置に空データを埋め込んでいます。
最後に、図鑑データが番号順になるように再度ksortで並び替えをすれば完了です。
捕まえた
ポケモンを捕まえたり、進化して新しいポケモンが仲間に加われば、見つけたと同様の処理で2を登録します。
/**
* 登録
* @param pokemon:object::Pokemon
* @return void
*/
public function regist(object $pokemon): void
{
// 発見済みの場合は処理中断
if(
!is_a($pokemon, 'Pokemon') ||
($this->pokedex[$pokemon->getNumber()] ?? 0) >= 2
){
return;
}
// 追加
$this->pokedex[$pokemon->getNumber()] = 2;
// 図鑑の歯抜けを空データで埋める
$this->fillSpace();
}
処理内容自体はほとんど同じで、比較する値と格納する値が変更になっただけです。ただ、引数で判定せず必要な際にメソッドとして呼び出せるように、今回は処理を分けて作成しました。
図鑑情報の取得
最後に図鑑情報の取得方法についてです。登録されている番号をforeachで回しながらconfigにアクセスするとなれば、ポケモン数が増えた際に処理速度に懸念が残るため、今回は図鑑用のデータを生成してから返却するようにします。
/**
* 一覧取得
* @param list:boolean
* @return array
*/
public function getPokedex($list=false): array
{
if($list){
// リスト化して返却
$config = array_slice(
config('pokedex'),
array_key_first($this->pokedex) - 1,
count($this->pokedex)
);
$pokedex = array_map(function($status, $data){
if($status >= 2){
// 捕獲済み
return $data;
}elseif($status === 1){
// 発見済み
// 添え番2以降は未調査データのため「-」に書き換え
$unknown = array_fill(2, array_key_last($data), '-');
// 未調査データを上書きして返却
return array_replace($data, $unknown);
}else{
// 未発見
return array_fill(0, count($data), '-');
}
}, $this->pokedex, $config);
// キーを採番して返却
return array_combine(array_keys($this->pokedex), $pokedex);
}else{
// そのまま返却
return $this->pokedex;
}
}
もし引数無し(デフォルト)のまま呼び出せば、加工なしのデータをそのまま返却しています。
指定があった場合は、図鑑に登録されているデータだけをconfigから取り出し、更に「見つけた」「捕まえた」の状態により閲覧できる範囲を限定して返却しています。
まず、array_sliceを使ってconfigから登録されている最初の番号から登録数だけのデータを取得します。
array_slice(PHP.net)
その後、array_mapを使って対象ポケモンのデータが登録されているかを以下のように分岐させています。
2(捕まえた)
configに登録されているデータをそのまま返却
1(見つけた)
configの2番目以降のデータを閲覧不可(-)に置き換えて返却
0(未発見)
全てを閲覧不可(-)に置き換えて返却
2つの配列でarray_mapを行うため、キーが0番からの添字に置き換わっています。これを番号通りに採番するため、プロパティのpokedexからarray_keysでキーのみを取り出し、array_combineでキーを一括上書きしています。
array_combine(PHP.net)
これでポケモン図鑑情報が取り出せるため、あとはループで必要情報を画面へ描画すれば完成です。
※近日本番環境へ反映予定のため、出力結果は是非プレイで確認してみてください。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「ポケモン図鑑」の作成方法についてご紹介しました。
ポケモンやゲームづくりに興味がある方、現在プログラミングの学習に取り組んでいる方は、ぜひ参考にしてみてくださいね。