PHPをピカチュウ(ポケモン)から学ぶ大人気コーナー、第6回目は「ステータス機能の導入編」です。
前回(第5回)で終了段階でのサンプルコードを公開しているので、もし本記事から始める人はぜひそちらを参考にしてください。
※お詫び
調べたところによると、ポケモンの経験値はexpと表現するのが一般的なようです。前回までメソッドやプロパティ等で使用していたex_pointやExPointという表記は全てexp、Expに変更しています。
今後は以下ページを参考にしながら進めていきたいと思います。サーセン。
ポケモン関連の英語
ステータスの計算
各ゲームによってステータス(実数値)の計算式は様々です。ポケモンにおいてはその計算式がポケモンwikiに掲載されていたので、そちらを参考に実装していきましょう。
ポケモンWiki ステータス
計算式
第二世代までの計算式と第三世代移行の計算式が異なっていますが、今回は第三世代移行の計算式を使用します。ただし「せいかく補正」は除きます。
最大HP
(種族値×2+個体値+努力値÷4)×レベル÷100+レベル+10
こうげき・ぼうぎょ・とくこう・とくぼう・すばやさ
(種族値×2+個体値+努力値÷4)×レベル÷100+5
※各小数点以下は切り捨て
ステータスに関係する要素として「種族値」「個体値」「努力値」「レベル」という4要素が関係してきます。それでは、1つずつ見ていきましょう。
種族値(Base Stats)
種族値とはその名の通り、各ポケモンの種族ごとに設定された数値である。
だそうです。簡単に言えば、ポケモンごとに割り振られている隠しステータスの1つです。
ピカチュウの場合は
HP:35
こうげき:55
ぼうぎょ:40
とくこう:50
とくぼう:50
すばやさ:90
という値が割り振られています。※執筆現在最新バージョンの種族値を使用しています
この値は先に説明したとおり、ポケモンごとに割り振られているため、ピカチュウのクラスに対して設定しておきます。
ピカチュウのクラス(/Class/Pikachu.php)
/**
* 種族値
* @var array
*/
protected $base_stats = [
'HP' => 35,
'こうげき' => 55,
'ぼうぎょ' => 40,
'とくこう' => 50,
'とくぼう' => 50,
'すばやさ' => 90,
];
※毎度ながらわかりやすさ重視でキーに日本語を使用しています。ご了承ください。
種族によって値が決まっているため、原則変更することはできません。
個体値(Individual Value)
個体値とはポケモン1匹1匹ごとに存在する、隠しステータスのことを指します。
だそうです。簡単に言えば「ピカチュウによっても強いやつと弱いやつがいるよ!」ってことです。
個体値は、最小が0で最大が31になります。それが6項目全てに対して別々に割当られているため、オール31(6Vと言われる)が最も強い個体ということになります。
個体値は全ポケモンが共通して持っている値なので、ポケモンのクラスに対してプロパティを準備します。
ポケモンのクラス(/Class/Pokemon.php)
/**
* 個体値
* @var array(value min:0 max:31)
*/
protected $iv = [
'HP' => null,
'こうげき' => null,
'ぼうぎょ' => null,
'とくこう' => null,
'とくぼう' => null,
'すばやさ' => null,
];
後ほど計算で使用するため、ステータスのキーは合わせておきましょう。初期値としてnullを設定していますが、0などを格納してもらっても構いません。
次に、個体値を割り当てる処理をSet格納トレイトに追加します。
Set格納トレイト(/Trait/SetTrait.php)
/**
* 個体値をセットする
* @return void
*/
protected function setIv()
{
/**
* 個体値のランダム生成(コールバック用)
* @return integer
*/
function randIv(){
// 0〜31の間でランダムの数値を割り振る
return mt_rand(0, 31);
}
$this->iv = array_map('randIv', $this->iv);
}
先程準備をした個体値のプロパティ($this->iv)の配列の各項目に対して、0から31の値をランダムに割り当てるという処理を行うため、今回はarray_mapを使用しています。
array_map(PHP.net)
同じ処理を行いたいコールバック関数を第1引数で指定して、第2引数に処理を行う配列を指定します。第2引数に渡した配列の値に対してコールバック関数の返り値がセットされたものが、array_mapの返り値となります。第3引数以降を設定した場合は、第2引数のキーは引き継がれません。
個体値割り振りの処理は、まずコールバック関数としてrandIv(自作関数)を指定しています。
/**
* 個体値のランダム生成(コールバック用)
* @return integer
*/
function randIv(){
// 0〜31の間でランダムの数値を割り振る
return mt_rand(0, 31);
}
randIvの中身は至って単純です。mt_randという関数を使って最小値(0)から最大値(31)の中からランダムに数字を1つ返却しています。
mt_rand(PHP.net)
randIvの返り値は、array_mapの第2引数で指定された$this->ivの値に対して順番に格納されます。結果、HPからすばやさまでの6項目に各ランダムの個体値を割り振られてるということになります。
余談…
array_mapのようにコールバック関数を使うものは、文字やコードによる説明だけでは動がわかりにくいため、ぜひ一度使ってみてください。受け取った引数などをその都度var_dumpやvar_exportを使って出力してみると、より理解しやすくなるでしょう。
mt_randという関数でランダムに数字を割り当てていると表現しましたが、実際は「擬似乱数」です。こちらも気になった方は、ぜひ詳しく調べてみてください。
個体値を割り振るメソッドが完成したので、インスタンスを作成した時点で割り当てられるようにピカチュウクラスのコンストラクタ(__construct)へ追加しましょう。
ピカチュウのクラス(/Class/Pikachu.php)
/**
* インスタンス作成時に実行される処理
*/
public function __construct()
{
$this->setLevel();
$this->setDefaultExp();
$this->setDefaultMove();
$this->setIv();
echo '<p>ピカチュウをゲットした</p>';
}
これで、インスタンスを作成した時点で個体値が割り振られるようになりました。
個体値は1度決定すれば変更することができません。なので、基本的にはsetIvのメソッドはこのタイミングでしか使用しないものです。さらに、個体値は隠しステータスのため、publicのgetメソッドは現状不要です。どういった値が割り振られているか確認したい人は、こっそりと準備しておきましょう。
努力値(Effort Value)
努力値(どりょくち)とは、ポケモンの強さにかかわる数値のひとつ。 ステータス画面では確認できない隠しパラメータの一つである。 なお、努力値という言葉は俗称であり、ゲーム内では基礎ポイントと呼ばれている。
だそうです。簡単に言えば、戦ったり育てることで溜まっていくステータスのことです。
努力値は原則としてバトルをすることで溜まっていく値になります。レベルがアップすれば増えるというものではありません。そのため、今回は計算用に初期値の0を割り振ったプロパティを準備するだけになります。
努力値も全ポケモンに共通した項目のため、ポケモンのクラスに対してプロパティを追加します。
ポケモンのクラス(/Class/Pokemon.php)
/**
* 努力値
* @var array
*/
protected $ev = [
'HP' => 0,
'こうげき' => 0,
'ぼうぎょ' => 0,
'とくこう' => 0,
'とくぼう' => 0,
'すばやさ' => 0,
];
これで努力値の設定は完了です。
計算機の実装
それではステータスの取得用メソッドを作成していきます。取得用と言っても、格納された値を返却するわけではありません。なぜなら、レベルや努力値(今回は固定値)など変動する値が計算式に使用されているため、その度に変更をして格納するよりは、取得する際に計算結果を返すほうが都合が良いのです。
では、ステータスの計算式を参考にしながらGet格納トレイトへ追加しましょう。
Get格納用トレイト(/Trait/GetTrait.php)
/**
* ステータスの取得
*
* @var void
*/
public function getStats()
{
foreach($this->base_stats as $key => $val){
/**
* ステータスの計算式(小数点以下は切り捨て)
* HP:(種族値×2+個体値+努力値÷4)×レベル÷100+レベル+10
* HP以外:(種族値×2+個体値+努力値÷4)×レベル÷100+5
*/
if($key === 'HP'){
$correction = $this->level + 10;
}else{
$correction = 5;
}
$stats[$key] = (int)(($val * 2 + $this->iv[$key] + $this->ev[$key] / 4) * $this->level / 100 + $correction);
}
return $stats;
}
ステータス(実数値)は公開情報のため、publicのメソッドを準備します。
計算処理が複雑なだけで、処理自体は簡潔です。1つずつ見ていきましょう。
foreach($this->base_stats as $key => $val){
種族値(base_stats)を基準に、foreachを使って1項目ずつ計算していきます。種族値・個体値・努力値には全て同じキーが割り振られているため、どれを基準にしてもらっても構いません。
次に、HPとその他での分岐を作成します。
if($key === 'HP'){
$correction = $this->level + 10;
}else{
$correction = 5;
}
HPの算出方法は他の5項目と異なります。最終的に加算する値が、HPの場合は「レベル+10」ですが、その他は「5」となっています。式全体を分岐で準備しても構いませんが、加算は計算順序にも影響しないので、この補正箇所の結果だけを変数($correction)に格納しています。
補正値が決まれば、実数値の計算式に各値を当てはめていきます。
$stats[$key] = (int)(($val * 2 + $this->iv[$key] + $this->ev[$key] / 4) * $this->level / 100 + $correction);
※式の最初に宣言している(int)は小数点を切り捨てるために使用しています。計算結果に対して切り捨てをしているので、上記の計算結果をカッコで囲ってからintを宣言しています。
最終的にステータスを配列として返却するので、その格納用に空配列を準備します。
計算式は、先程のHP補正の変数を利用して以下の通りです。
(種族値×2+個体値+努力値÷4)×レベル÷100+ $correction
個体値、努力値にはforeachで取得したkeyを使って取得しています。計算結果は項目($key)を割り当てて配列に格納していきます。
最後は、作成したステータスの配列($stats)をreturnを使って返却すれば、実数値を取得することができます。
出力用ファイル(/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を追加しました
# 出力結果
ピカチュウをゲットした
現在のレベル:8
---
正式名称:ピカチュウ
ニックネーム:ピカチュウ
現在のレベル:8
覚えている技:でんきショック,なきごえ
現在の経験値:512
次のレベルまでに必要な経験値:217
---
HP:24
こうげき:15
ぼうぎょ:11
とくこう:14
とくぼう:14
すばやさ:21
実数値を取得することができました。数値が合っているかどうかは、ポケモンのステータス計算機を使って確認してみてください。
ポケモンステータス計算機
※計算には個体値が必要な場合は、var_dumpやvar_exportを使って確認してみてください
まとめ
いかがだったでしょうか。
今回はステータス(実数値)の計算機能の導入方法をご紹介しました。
計算方法や配列に対して実施する処理に関しては、他にも便利な関数あるかも知れません。もし今回ご紹介した方法以外にも同じ結果が得られるものがあれば、ぜひ今回紹介したコードを参考にしながら試してみてくださいね。