アイテム(どうぐ)
PHPポケモンもバトル機能が一通り揃ってきたので、新機能として「アイテム」の実装に取り掛かります。
アイテムにも色々ありますが、技やポケモンのクラス同様に、初代で登場したアイテムから順番に取り揃えていきましょう。
キズぐすりの実装
ポケモンのどうぐ、一番手は「キズぐすり」です。RPGでは欠かせない回復アイテムの1つで、ポケモンの体力を少量回復させる効果をもっています。
スプレー式の キズぐすり。 ポケモン 1匹の HPを 20だけ 回復する。
アイテムにも、それぞれに効果や使用タイミングがあるため、ポケモンや技同様にクラスによる管理をしていきましょう。
まずはアイテムの親クラス(Item)を作成します。
アイテムクラス(/Classes/Item.php)
<?php
// どうぐ
abstract class Item
{
/**
* @return void
*/
public function __construct()
{
//
}
/**
* 名称の取得
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* カテゴリの取得
* @return string
*/
public function getCategory()
{
return $this->category;
}
/**
* 説明文の取得
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* 最大保有数の取得
* @return integer|null
*/
public function getMax()
{
return $this->max;
}
/**
* 買値の取得
* @return integer
*/
public function getBidPrice()
{
return $this->bid_price;
}
/**
* 売値の取得
* @return integer
*/
public function getSellPrice()
{
return $this->sell_price;
}
}
アイテムに持たせるパラメーターを取得するためのメソッドを、親クラスに持たせています。
次に、キズぐすりのクラスを作成しましょう。
キズぐすり(/Classes/Item/Potion.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Item.php');
// キズぐすり
class ItemPotion extends Item
{
/**
* 正式名称
* @var string
*/
protected $name = 'キズぐすり';
/**
* 説明文
* @var string
*/
protected $description = 'スプレー式のキズぐすり。ポケモン1匹のHPを20だけ回復する。';
/**
* カテゴリ
* @var string::general|health|ball|important|machine
*/
protected $category = 'health';
/**
* 最大所有数
* @var integer
*/
protected $max = 99;
/**
* 買値
* @var integer
*/
protected $bid_price = 200;
/**
* 売値
* @var integer
*/
protected $sell_price = 100;
/**
* 対象
* @var string::pokmeon|player
*/
protected $target = 'pokemon';
/**
* 使用できるタイミング
* @var array
*/
protected $timing = ['battle', 'home'];
/**
* 効果
* @return array
*/
public function effects($pokemon)
{
$before = $pokemon->getRemainingHp();
if($before < $pokemon->getStats('HP')){
// HP20回復
$after = $pokemon->calRemainingHp('add', 20);
$message = $pokemon->getPrefixName().'のHPが'.($after - $before).'回復した';
}else{
// 効果なし
$message = '使っても効果がないよ';
}
// メッセージを返却
return [
'message' => $message
];
}
}
まずカテゴリプロパティ(category)についてです。
初代では、アイテムのカテゴリ分けがされておらず、見にくい状態になっていましたが、第2世代からは「ボール」「わざマシン」「大切なもの」などを分けて格納できるようになりました。PHPポケモンでも見やすさ重視で、初代アイテムで実装する項目をカテゴリ分けしていきます。
対象(target)、使用できるタイミング(timing)については、必要になる可能性が想定されたので設定しました。
効果メソッド(effects)は、技と同様に配列でメッセージを返却する仕様にしていますが、こちらもバトルやホーム画面へアイテムを使用する機能を組み込みながら調整予定です。
フレンドリィショップ
アイテムを実装しても、手に入れる手段がなければ意味がありません。なので、ダミーで準備していたフレンドリィショップに商品を陳列させていきましょう。
商品準備
フレンドリィショップへ陳列させる商品は、そのままHTMLの要素として容易せず、configを活用します。
ショップconfig(/Config/shop.php)
<?php
return [
'ItemPotion'
];
現在はキズぐすりしか用意をできていないため、配列としてキズぐすりのクラスだけを返却しています。
次に、コントローラーでフレンドリィショップ用の配列を作成し、ホーム画面から簡単に呼び出せるようにしましょう。
ホームコントローラー用トレイト(/Traits/Controller/HomeControllerTrait.php)
<?php
/**
* ホームコントローラー用トレイト
*/
trait HomeControllerTrait
{
/**
* 戦闘に参加するポケモン番号を取得
*
* @return integer
*/
protected function getFightPokemonOrder()
{
$orders = array_filter($this->party, function($partner){
return $partner->getRemainingHp() > 0;
});
if(empty($orders)){
return null;
}else{
return array_key_first($orders);
}
}
/**
* ショップ情報の取得
* @return array
*/
public function getShop()
{
return array_map(function($item){
return new $item;
},config('shop'));
}
}
array_mapを使って、取得したショップ配列の要素をオブジェクトに変換して返しています。どこからでもインスタンス化できるように、Itemディレクトリをオートローダーの対象にしておきましょう。
フレンドリィショップではポケモンセンターと違い、購入や売却などいくつか操作が必要になるため、モーダルとして用意します。
フレンドリィショップモーダル(/Resources/Partials/Home/Modals/shop.php)
<!-- Modal -->
<div class="modal fade" id="shop-modal" tabindex="-1" role="dialog" aria-labelledby="shop-modal-title" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="shop-modal-title">フレンドリィショップ</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<?php # ナビ ?>
<nav class="nav nav-pills nav-justified btn-group mb-3" id="shop-modal-tab">
<a class="btn btn-outline-success nav-item nav-link active" id="shop-modal-buy-tab" data-toggle="tab" href="#shop-modal-buy" role="tab" aria-controls="shop-modal-buy" aria-selected="true" data-type="buy">購入</a>
<a class="btn btn-outline-info nav-item nav-link" id="shop-modal-sell-tab" data-toggle="tab" href="#shop-modal-sell" role="tab" aria-controls="shop-modal-sell" aria-selected="true" data-type="sell">売却</a>
</nav>
<?php # 購入 ?>
<div class="tab-content mb-3" id="shop-modal-tab-content">
<div class="tab-pane fade show active" id="shop-modal-buy" role="tabpanel" aria-labelledby="shop-modal-buy-tab">
<form method="post" data-form="shop">
<input type="hidden" name="action" value="shop">
<input type="hidden" name="do" value="buy">
<div class="mb-3 p-3 bg-light">
<div class="input-group">
<select class="custom-select col-8" name="order" data-form="buy">
<option value="" selected>----</option>
<?php foreach($controller->getShop() as $order => $item): ?>
<option value="<?=$order?>" data-price="<?=$item->getBidPrice()?>" data-item="<?=$item->getName()?>">
<?=$item->getName()?>(<?=$item->getBidPrice()?>円)
</option>
<?php endforeach; ?>
</select>
<select class="custom-select col-4" name="count" data-form="buy">
<option value="">----</option>
<?php for($i=1;$i<100;$i++): ?>
<option value="<?=$i?>"><?=$i?> 個</option>
<?php endfor; ?>
</select>
</div>
</div>
<div class="alert alert-success" id="shop-buy-calculator" role="alert">
<div class="form-group row">
<label class="col-3 col-form-label">おこづかい</label>
<div class="col-9 text-right">
<p class="form-control-plaintext">
<span class='mr-2'><?=$player->getMoney()?></span>円
</p>
</div>
</div>
<hr>
<div class="form-group row">
<label class="col-3 col-form-label">内訳</label>
<div class="col-3 text-right">
<p class="form-control-plaintext">
<span id="shop-buy-item-name"></span>
</p>
</div>
<div class="col-3 text-right">
<p class="form-control-plaintext">
<span id="shop-buy-item-price"></span>
</p>
</div>
<div class="col-3 text-right">
<p class="form-control-plaintext">
<span id="shop-buy-item-count"></span>
</p>
</div>
</div>
<hr>
<div class="form-group row mb-0">
<label class="col-3 col-form-label">合計</label>
<div class="col-9 text-right">
<p class="form-control-plaintext font-weight-bolder">
<span id="shop-buy-total-price" class="mr-2"></span>
</p>
</div>
</div>
<p data-alert="buy" class="text-danger text-right mb-0 mt-2" style="display:none;">
おこづかいが足りません
</p>
</div><!-- aleart -->
<button type="submit" class="btn btn-success btn-block" id="shop-buy-submit" disabled>購入</button>
</form>
</div><!-- buy -->
<?php # 売却 ?>
<div class="tab-pane fade show" id="shop-modal-sell" role="tabpanel" aria-labelledby="shop-modal-sell-tab">
<form method="post" data-form="shop">
<input type="hidden" name="action" value="shop">
<input type="hidden" name="do" value="sell">
<div class="mb-3 p-3 bg-light">
売却
</div>
<div class="alert alert-info" id="shop-sell-calculator" role="alert">
<div class="form-group row">
<label class="col-3 col-form-label">おこづかい</label>
<div class="col-9 text-right">
<p class="form-control-plaintext">
<span class='mr-2'><?=$player->getMoney()?></span>円
</p>
</div>
</div>
<hr>
<div class="form-group row">
<label class="col-3 col-form-label">内訳</label>
<div class="col-3 text-right">
<p class="form-control-plaintext">
<span id="shop-sell-item-name"></span>
</p>
</div>
<div class="col-3 text-right">
<p class="form-control-plaintext">
<span id="shop-sell-item-price"></span>
</p>
</div>
<div class="col-3 text-right">
<p class="form-control-plaintext">
<span id="shop-sell-item-count"></span>
</p>
</div>
</div>
<hr>
<div class="form-group row mb-0">
<label class="col-3 col-form-label">合計</label>
<div class="col-9 text-right">
<p class="form-control-plaintext font-weight-bolder">
<span id="shop-sell-total-price" class="mr-2"></span>
</p>
</div>
</div>
</div><!-- aleart -->
<button type="submit" class="btn btn-info btn-block" id="shop-sell-submit" disabled>売却</button>
</form>
</div><!-- sell -->
</div>
<input type="hidden" id="player-remaining-money" value="<?=$player->getMoney()?>">
</div><!-- Modal body -->
</div><!-- Modal content -->
</div><!-- Modal dialog -->
</div><!-- Modal -->
ショップの見た目はPHPポケモンオリジナルのものとなっています。アイテムをテーブルとして準備する場合、それぞれにフォームを用意するか、jQueryを使って選択した値をセットしてsubmitしなければなりません。今回はそれらの手間をひとまとめにできるよう、セレクトボックスを採用しました。
ポケモンでは、私達が使っているようなネットショップとは異なり、複数のアイテムを一気に購入することはできません。なので、PHPポケモンでもアイテムは1種類ずつ購入する仕様を採用しました。
計算機の作成
ポケモンではアイテムと数を選択すると、確認画面としてその合計金額が表示されます。確認画面を入れる場合、もう1枚モーダルを表示する必要があるので、その手間を省くためにPHPポケモンでは購入画面に計算機の機能を持たせました。
選択したアイテムと個数の値をjQueryで受け取り、計算結果を画面上に出力させます。
フレンドリィショップ用JS(/Pulibc/Assets/js/Home/shop.js)
/*----------------------------------------------------------
// 初期化する関数
----------------------------------------------------------*/
// おこづかい
var money = $('#player-remaining-money').val();
/**
* フレンドリィショップ
* @function change
* @return void
**/
var shopInit = function(){
$('form[data-form="shop"] select').on('change', function(){
// フォームの判別
var form = $(this).data('form');
// 必要値の取得
var order_option = $('[data-form="' + form + '"][name="order"] option:selected')
var price = order_option.data('price');
var item = order_option.data('item');
var count = $('[data-form="' + form + '"][name="count"]').val();
// アイテムが選択されていなければ、計算機をリセット
if(!item || !count){
calculatorReset(form);
return;
}
// 合計金額の算出
var total = price * count;
// 計算機に値をセット
$('#shop-' + form + '-item-name').text(item);
$('#shop-' + form + '-item-price').text(price + ' 円');
$('#shop-' + form + '-item-count').text(count + ' 個');
$('#shop-' + form + '-total-price').text(total + ' 円');
if(money < total){
$('#shop-' + form + '-submit').prop('disabled', true);
$('[data-alert="' + form + '"]').show();
}else{
$('#shop-' + form + '-submit').prop('disabled', false);
$('[data-alert="' + form + '"]').hide();
}
});
}
/**
* モーダル起動時の初期化
* @function change
* @return void
**/
var showModalInit = function(){
$('#shop-modal').on('show.bs.modal', function(){
$.each(['buy', 'sell'], function(index, value){
formReset(value);
calculatorReset(value);
})
});
}
/**
* タブクリック時の初期化
* @function change
* @return void
**/
var shopTabInit = function(){
$('#shop-modal-tab .nav-link').on('click', function(){
var form = $(this).data('type');
formReset(form);
calculatorReset(form);
});
}
/*----------------------------------------------------------
// 処理内で呼び出す関数
----------------------------------------------------------*/
/**
* 計算機の初期化
* @param form:string
* @return void
**/
var calculatorReset = function(form){
$('#shop-' + form + '-item-name').text('-');
$('#shop-' + form + '-item-price').text('-');
$('#shop-' + form + '-item-count').text('-');
$('#shop-' + form + '-total-price').text('-');
$('[data-alert="' + form + '"]').hide();
$('#shop-' + form + '-submit').prop('disabled', true);
}
/**
* フォームの初期化
* @param form:string
* @return void
**/
var formReset = function(form){
$('[data-form="'+ form +'"]').val('');
}
/*----------------------------------------------------------
// 初期化
----------------------------------------------------------*/
jQuery(function($){
shopInit();
shopTabInit();
showModalInit();
});
セレクトボックスの変更を取得し、金額と個数で合計金額を算出、おこづかいが足りているかを判別しています。
フォームではDOMの直接書き換えを考慮して、アイテムクラスや金額を直接飛ばさず、アイテム番号と必要数のみで判別しています。
それでは、ショップ計算機の動きを確認してみましょう。
計算機が正常に機能していることが確認できました。これで、フレンドリィショップの開店準備は完了です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「アイテムの実装」と「フレンドリィショップの開店準備」についてご紹介しました。
プログラミング学習に取り組んでいる方や、興味を持たれている方は、ぜひ参考にしてみてくださいね。