※前回(第6回)で意味不明な場所に空変数が入っており、ステータスが一部しか出力できないという問題がありました。修正しています。犯人は「$stats = [];」です。(GetTrait.php)
今回はポケモンのゲームでは欠かせない、楽しみの一つとなる「進化システム」を導入していきます。これからPHPポケモンを最初から作りたいという人は、ぜひ第1回から製作工程を楽しみながら挑戦してみてください。
※仕様として増設していく上でイマイチだと感じた点は、回数を重ねながら修正しています。決して見通しが甘いわけではありません。
進化システムの導入
ポケモンのゲームには進化というシステムがあります。ピカチュウであれば、ある条件を満たすことでライチュウというポケモンに進化できるのです。
今回のシステムの場合、進化した時点でピカチュウクラスからライチュウのクラスへ切り替えをする必要があります。そして、切り替えた際にステータスや技の引き継ぎもしなければなりません。
しかし、難しく考える必要はありません。今まで学習した内容を応用するだけで、十分実装が可能です。
ライチュウクラスの作成
まず、進化先となるライチュウのクラスを作成しましょう。
ライチュウのクラス(/Class/Raichu.php)
<?php
require_once('Class/Pokemon.php');
// ライチュウ
class Raichu extends Pokemon
{
/**
* 正式名称
* @var string(min:1 max:5)
*/
protected $name = 'ライチュウ';
/**
* 初期レベル
* @var array
*/
protected $default_level = [
55, 56, 57,
];
/**
* レベルアップで覚える技
* @var array
*/
protected $level_move = [
[1, 'でんきショック'],
[1, 'なきごえ'],
[1, 'でんじは'],
];
/**
* 種族値
* @var array
*/
protected $base_stats = [
'HP' => 60,
'こうげき' => 90,
'ぼうぎょ' => 55,
'とくこう' => 90,
'とくぼう' => 80,
'すばやさ' => 110,
];
/**
* インスタンス作成時に実行される処理
*
* @return void
*/
public function __construct()
{
$this->setLevel();
$this->setDefaultExp();
$this->setDefaultMove();
$this->setIv();
echo '<p>ライチュウをゲットした</p>';
}
}
正式名称、初期レベル、レベルアップで覚える技、種族値をそれぞれライチュウの仕様に変更しています。
※種族値は最新、レベルアップで覚える技は初期のものを採用しています
進化メソッドの実装
次に、進化のメソッドを作成します。ピカチュウの進化条件は「かみなりのいし」を使うことですが、今回はまだアイテムの概念が存在していないため、public権限のメソッドで外部から直接進化させる仕様で作成していきます。
進化条件や進化先はそれぞれ異なるため、進化メソッドはピカチュウのクラスへ実装します。
ピカチュウのクラス(/Class/Pikachu.php)
<?php
require_once('Class/Pokemon.php');
require_once('Class/Raichu.php');
// ピカチュウ
class Pikachu extends Pokemon
{
-- 省略
/**
* 進化 → ライチュウ
*
* @return Class\Raichu
*/
public function evolve()
{
return new Raichu($this);
}
}
まずは新しく作成したライチュウのクラスをrequire_onceで最初に読み込みます。
進化用のメソッド(evolve)では、ライチュウのインスタンスを作成して返却します。進化といっても、ピカチュウのインスタンスをライチュウに変更するというわけではなく、あくまで新しく作ったライチュウのインスタンスに対して、ピカチュウが持っている能力値を引き継ぐという方法で実装します。
・進化のシステム
【イメージ】
ピカチュウのインスタンスをライチュウに変更
【実際】
ピカチュウのインスタンスが持つステータス等を、新しく作ったライチュウのインスタンスに引き継ぐ
能力値を引き継ぐために、new Raichuの引数にピカチュウ自身($this)を渡します。余計なものまで引き継ぎたくなければ、必要な値だけを格納して渡すという方法をとっても構いません。
能力値の引き継ぎ
ピカチュウのクラスに作成したevolveという進化メソッドで、ライチュウのインスタンスを作成しましたが、このままでは「ライチュウをゲットした」というメッセージが出てしまい、ピカチュウ同様に初期値の設定をされてしまいます。そうならないためにも、ライチュウのコンストラクタ(__construct)に引数で判定する分岐を追加しましょう。
ライチュウのクラス(/Class/Raichu.php)
/**
* インスタンス作成時に実行される処理
*
* @param Class\Pikachu|null
* @return void
*/
public function __construct($before=null)
{
if(is_a($before, 'Pikachu')){
// 進化した際の処理
$this->takeOverAbility($pikachu);
echo '<p>ライチュウに進化した</p>';
}else{
// 捕まえた際の処理
$this->setLevel();
$this->setDefaultExp();
$this->setDefaultMove();
$this->setIv();
echo '<p>ライチュウをゲットした</p>';
}
}
デフォルト値をnullにした引数を追加し、その引数で分岐させました。それでは分岐箇所について見てみましょう。
if(is_a($before, 'Pikachu')){
is_aという関数を使用して、第1引数に指定された$beforeが、第2引数のクラス名かどうかを判定しています。このようにクラスを判定しておくことで、他のポケモンからライチュウに進化されないように制限を設けています。
is_a(PHP.net)
進化すれば、引き継ぐ必要のあるピカチュウの能力値をライチュウにセットする必要があります。こちらは進化をした際の共通処理になるので、ポケモンのクラスにtakeOverAbilityという引き継ぎ用のメソッドを追加しておきます。
ポケモンのクラス(/Class/Pokemon.php)
/**
* 進化時の能力引き継ぎ処理
*
* @param object $before 進化前
* @var void
*/
protected function takeOverAbility($before)
{
$this->nickname = $before->nickname; # ニックネーム
$this->level = $before->level; # レベル
$this->ev = $before->ev; # 努力値
$this->iv = $before->iv; # 個体値
$this->exp = $before->exp; # 経験値
$this->move = $before->move; # 技
}
処理はいたって単純です。$this(ライチュウ)に対して$before(ピカチュウ)の情報を順番にセットしています。
ポケモンでは、ニックネーム、レベル、努力値、個体値、経験値、覚えている技が進化しても引き継がれるため、それぞれにセットしています。
それでは、出力して確認してみましょう。
出力ファイル(/index.php)
<?php
require_once('Class/Pikachu.php');
// ピカチュウをゲット
$pikachu = new Pikachu;
echo '<p>現在のレベル:'.$pikachu->getLevel().'</p>';
$details = $pikachu->getDetails();
$stats = $pikachu->getStats();
?>
<hr>
<!--ピカチュウ 詳細-->
<?php foreach($details as $key => $val): ?>
<p><?=$key?>:<?=$val?></p>
<?php endforeach; ?>
<hr>
<!--ピカチュウ ステータス-->
<?php foreach($stats as $key => $val): ?>
<p><?=$key?>:<?=$val?></p>
<?php endforeach; ?>
<hr>
<?php
// ライチュウに進化
$raichu = $pikachu->evolve();
$details = $raichu->getDetails();
$stats = $raichu->getStats();
?>
<hr>
<!--ライチュウ 詳細-->
<?php foreach($details as $key => $val): ?>
<p><?=$key?>:<?=$val?></p>
<?php endforeach; ?>
<hr>
<!--ライチュウ ステータス-->
<?php foreach($stats as $key => $val): ?>
<p><?=$key?>:<?=$val?></p>
<?php endforeach; ?>
ポイントは、ライチュウへ進化した際に新たな変数へ格納することです。
// ライチュウに進化
$raichu = $pikachu->evolve();
前項でも説明したとおり、evolveという進化メソッドを使ってもピカチュウのインスタンス自体がライチュウに変わっているわけではなく、返り値として能力を引き継いだライチュウのインスタンスを返却しています。なので、その結果を新たな変数へ格納するか、$pikachuの変数に上書きして使いましょう。
出力結果は以下の通りです。
# 出力結果
ピカチュウをゲットした
現在のレベル:8
正式名称:ピカチュウ
ニックネーム:ピカチュウ
現在のレベル:8
覚えている技:でんきショック,なきごえ
現在の経験値:512
次のレベルまでに必要な経験値:217
HP:24
こうげき:13
ぼうぎょ:13
とくこう:13
とくぼう:13
すばやさ:21
ライチュウに進化した
正式名称:ライチュウ
ニックネーム:ライチュウ
現在のレベル:8
覚えている技:でんきショック,なきごえ
現在の経験値:512
次のレベルまでに必要な経験値:217
HP:28
こうげき:19
ぼうぎょ:16
とくこう:20
とくぼう:18
すばやさ:24
進化しても能力が引き継がれていますね。そして、ライチュウに進化することで種族値が上がっているので、ステータスは少しアップしていることがわかります。
これで、ピカチュウを無事ライチュウへ進化させることができました。
まとめ
いかがだったでしょうか。
今回は「ピカチュウから学ぶオブジェクト指向 〜進化編〜」をご紹介しました。
ポケモンによって進化条件がことなるので、そういった機能も将来的には実装してみましょう。。
楽しみながらプログラミングを学習(PHP)をしたい人は、ぜひ参考にしてくださいね。