PHPポケモン(旧:ピカチュウから学ぶオブジェクト指向)も第9回目となりました。前回GitHubよりコードを配布したので、これから学習しようと考えている人は、ぜひ参考にしてください。
最初からコードの内容について学びたい人は、ぜひ記念すべき第1回から順を追って取り組んでみてください。
レベルアップ進化の導入
前回は進化システムを導入したので、今回は進化条件「レベルアップ」を追加します。
ピカチュウは「かみなりのいし」でのアイテム進化のため、前回作成したフシギダネ一家に対して機能増設を行います。
アクセス修飾子の変更
まずは進化メソッドのアクセス修飾子をpublicからprotectedへ変更しておきましょう。現段階であれば、フシギダネ、フシギソウ、ピカチュウ3箇所です。
フシギダネ(/Classes/Pokemon/Fushigidane.php)
/**
* 進化 → フシギソウ
*
* @return Classes\Pokemon\Fushigisou
*/
protected function evolve()
{
return new Fushigisou($this);
}
※ピカチュウ、フシギソウも同様にアクセス修飾子を変更しておきましょう
進化条件の追加
判定用として、レベルアップが条件のポケモンに進化レベルのプロパティ(evolve_level)をそれぞれ用意します。
フシギダネ(Classes/Pokemon/Fushigidane.php)
/**
* 進化レベル
* @var integer
*/
protected $evolve_level = 16;
フシギソウ(Classes/Pokemon/Fushigisou.php)
/**
* 進化レベル
* @var integer
*/
protected $evolve_level = 32;
次にレベルアップのメソッド(evolve)をクラス内で呼び出します。
レベルアップによる進化なので、レベルアップのメソッド(actionLevelUp)に対して処理を追加したくなりますが、ポケモンの場合はレベルアップが終わった時点で進化が実行されるため、今回は経験値獲得のメソッド(setExp)に対して増設します。
Set格納トレイト(Traits/Pokemon/SetTrait.php)
/**
* 経験値をセット(取得)する
* @param integer $exp
* @return object
*/
public function setExp($exp)
{
$this->exp += $exp;
echo '<p>'.$this->getNickname().'は経験値を'.$exp.'ポイント手に入れた!</p>';
if($this->level >= 100){
// レベルアップ処理は不要
$this->exp += $exp;
return $this;
}
// 次のレベルに必要な経験値を取得
if($this->getReqLevelUpExp() <= $exp){
/**
* 次のレベルに必要な経験値を超えている場合
*/
$this->actionLevelUp();
while($this->getReqLevelUpExp() < 0){
$this->actionLevelUp();
}
}
// 進化判定
if(isset($this->evolve_level) && $this->evolve_level <= $this->level){
return $this->evolve();
}else{
return $this;
}
}
setExpの最後に進化判定を追加しました。まずは条件分岐について確認してみましょう。
if(isset($this->evolve_level) && $this->evolve_level <= $this->level)
レベルアップ進化しないポケモン(ピカチュウ等)はevolve_levelのプロパティが必要ありませんので、エラー回避のためにもまずissetでその存在があるかどうかをチェックします。次に、進化レベルが現在のレベルを満たしているか<=で判定判定します。
※Null合体演算子で判定「$this->evolve_level ?? 1000 <= $this->level」のように、issetを使わず記述量を減らすこともできますが、今回はどういった判定をしているかわかりやすい方法で今回は実装しています。判別できるのであれば、好きに記述してもらって構いません。
返り値について
進化条件を満たしていた場合は、返り値として$this->evolve()を返却しています。満たしていなければ、自分自身($this)を返却します。当初setExpでは返り値はありませんでしたが、進化したオブジェクトを返却する必要があるため、返り値ありに変更しています。
※自分自身を返却するという仕様はあまりきれいな記述方法とは言えませんので、後々修正する予定です。ただ、ポケモンのクラス自体を大分見直しする必要があるため、一旦はこの方法で進めていきます。
では、フシギダネに対して進化条件であるレベル16になるように経験値をセットしてみましょう。
出力ファイル(/index.php)
<?php
require_once(__DIR__.'/Classes/Pokemon/Fushigidane.php');
// HTML出力用関数
function echoKeyToVal($array)
{
foreach($array as $key => $val){
echo '<p>'.$key.':'.$val.'</p>';
}
}
// フシギダネをゲット
$pokemon = new Fushigidane;
// 詳細取得
echoKeyToVal($pokemon->getDetails());
// ステータス取得
echoKeyToVal($pokemon->getStats());
// 経験値獲得
$pokemon = $pokemon->setExp('4000');
// 詳細取得
echoKeyToVal($pokemon->getDetails());
// ステータス取得
echoKeyToVal($pokemon->getStats());
?>
# 出力結果
フシギダネをゲットした
正式名称:フシギダネ
ニックネーム:フシギダネ
現在のレベル:5
覚えている技:たいあたり,なきごえ
現在の経験値:125
次のレベルまでに必要な経験値:91
HP:21
こうげき:11
ぼうぎょ:10
とくこう:12
とくぼう:11
すばやさ:9
フシギダネは経験値を4000ポイント手に入れた!
フシギダネのレベルは6になった!
フシギダネのレベルは7になった!
やどりぎのタネを覚えた!
フシギダネのレベルは8になった!
フシギダネのレベルは9になった!
フシギダネのレベルは10になった!
フシギダネのレベルは11になった!
フシギダネのレベルは12になった!
フシギダネのレベルは13になった!
つるのムチを覚えた!
フシギダネのレベルは14になった!
フシギダネのレベルは15になった!
フシギダネのレベルは16になった!
フシギソウに進化した
正式名称:フシギソウ
ニックネーム:フシギソウ
現在のレベル:16
覚えている技:たいあたり,なきごえ,やどりぎのタネ,つるのムチ
現在の経験値:4125
次のレベルまでに必要な経験値:788
HP:50
こうげき:29
ぼうぎょ:26
とくこう:35
とくぼう:31
すばやさ:24
レベルアップの処理後に、無事フシギソウに進化することができましたね。これでレベルアップ処理は完了です。
※ポケモンではワープ進化(フシギダネ→フシギバナ)には対応していませんので、原作再現のためこの仕様で進めていきます
技習得条件の追加
レベルアップ進化を導入したので、技の習得条件について見直しておきましょう。第8回配布コードでは、技の重複チェックがされていませんでしたが、進化すれば既に覚えている技を覚えようとしてしまい重複する可能性があるので、その判定を追加します。
技のチェック処理は別の場面でも使用する可能性があるため、新しくcheckMoveというメソッドを作成して処理を移します。
ポケモン(/Classes/Pokemon.php)
/**
* 現在のレベルで覚えられる技があるか確認する処理
*
* @var integer
*/
protected function checkMove()
{
// レベルアップして覚えられる技があれば習得する
$level_move_keys = array_keys(array_column($this->level_move, 0), $this->level);
foreach($level_move_keys as $key){
$move_name = $this->level_move[$key][1];
// 覚えようとしている技が重複していないか確認
if(!in_array($move_name, $this->move, true)){
$this->setMove($move_name);
echo '<p>'.$move_name.'を覚えた!</p>';
}
}
}
追加した重複チェック部分を確認してみましょう。
// 覚えようとしている技が重複していないか確認
if(!in_array($move_name, $this->move, true))
in_arrayを使用して、既に覚えている技かどうか存在をチェックしています。こうしていれば、進化後に既に覚えている技を覚えようとしてもスキップされるため、技が重複することがありません。
では、まずレベルアップ処理の技チェック部分を新しく作成したメソッドに置き換えましょう。
ポケモン(/Classes/Pokemon.php)
/**
* レベルアップ処理
*
* @var integer
*/
protected function actionLevelUp()
{
// レベルアップ
$this->level++;
echo '<p>'.$this->getNickName().'のレベルは'.$this->level.'になった!</p>';
// 現在のレベルで習得できる技があるか確認
$this->checkMove();
}
進化した時点でも技のチェックをする必要があるので、進化後にも技のチェックを追加しましょう。
ポケモン(/Classes/Pokemon.php)
/**
* インスタンス作成時に実行される処理
*
* @param object|null
* @return void
*/
public function __construct($before=null)
{
// 進化前のポケモンと一致しているかチェック
if(is_a($before, $this->child_class ?? null)){
// 進化した際の処理
$this->takeOverAbility($before);
echo '<p>'.$this->name.'に進化した</p>';
$this->checkMove();
}else{
// 捕まえた際の処理
$this->setLevel();
$this->setDefaultExp();
$this->setDefaultMove();
$this->setIv();
echo '<p>'.$this->name.'をゲットした</p>';
}
}
では確認のため、フシギダネに経験値を11000をセットしてレベル22にしてみましょう。
出力ファイル(/index.php)
<?php
require_once(__DIR__.'/Classes/Pokemon/Fushigidane.php');
// HTML出力用関数
function echoKeyToVal($array)
{
foreach($array as $key => $val){
echo '<p>'.$key.':'.$val.'</p>';
}
}
// フシギダネをゲット
$pokemon = new Fushigidane;
// 詳細表示
echoKeyToVal($pokemon->getDetails());
// ステータス表示
echoKeyToVal($pokemon->getStats());
// 経験値をセット
$pokemon = $pokemon->setExp('11000');
// 詳細表示
echoKeyToVal($pokemon->getDetails());
// ステータス表示
echoKeyToVal($pokemon->getStats());
# 出力結果
フシギダネをゲットした
正式名称:フシギダネ
ニックネーム:フシギダネ
現在のレベル:5
覚えている技:たいあたり,なきごえ
現在の経験値:125
次のレベルまでに必要な経験値:91
HP:21
こうげき:10
ぼうぎょ:10
とくこう:11
とくぼう:12
すばやさ:9
フシギダネは経験値を11000ポイント手に入れた!
フシギダネのレベルは6になった!
フシギダネのレベルは7になった!
やどりぎのタネを覚えた!
フシギダネのレベルは8になった!
フシギダネのレベルは9になった!
フシギダネのレベルは10になった!
フシギダネのレベルは11になった!
フシギダネのレベルは12になった!
フシギダネのレベルは13になった!
つるのムチを覚えた!
フシギダネのレベルは14になった!
フシギダネのレベルは15になった!
フシギダネのレベルは16になった!
フシギダネのレベルは17になった!
フシギダネのレベルは18になった!
フシギダネのレベルは19になった!
フシギダネのレベルは20になった!
どくのこなを覚えた!
フシギダネのレベルは21になった!
フシギダネのレベルは22になった!
フシギソウに進化した
正式名称:フシギソウ
ニックネーム:フシギソウ
現在のレベル:22
覚えている技:なきごえ,やどりぎのタネ,つるのムチ,どくのこな
現在の経験値:11125
次のレベルまでに必要な経験値:1042
HP:65
こうげき:33
ぼうぎょ:36
とくこう:41
とくぼう:43
すばやさ:32
フシギソウはレベル22になれば「どくのこな」を覚えますが、フシギダネの時点で既に覚えているためスキップされていますね。他のもわざマシン機能などを実装した際に、技の習得チェックメソッドは活用できるので、汎用性の高いものは小分けにしておくようにしましょう。
まとめ
いかがだったでしょうか。
今回のPHPポケモンは「レベルアップ進化」の条件追加を行いました。一時的にピカチュウが進化できない状態になっていますが、アイテムの概念がない以上しばらくは我慢してもらいましょう。
進化条件などを増やしていけば、一層ゲーム性が高まります。どういった進化条件があるのか、それはどうやって実装すればいいのかなど、PHPで再現する方法をぜひ考えながら実装してみてください。
プログラミング上達のポイントは、楽しく取り組むことです。ゲームに興味があったり、ポケモンが好きな人でプログラミング学習中の方は、ぜひ参考にしてくださいね。