パーティーの並び替え
ポケモンをバトルに選出する際に欠かせないのが「パーティーの並び替え」です。パーティーの先頭(ひんし状態でない)がポケモンでは自動的に選択されるため、戦闘前に並び替えをしておく必要があります。
ゲーム上では簡単に見える処理ですが、これがPHPで行うとなれば少し厄介な問題が出てきます。なので、PHPポケモン独自の仕様で組み上げていきます。
sortableの活用
並び替えの方法については、直感的に行えるようにjQuery UIのプラグイン、sortableを使用します。
sortable(jQuery UI)
これは、並び替えしたい要素を囲っている要素を指定することで、ドラッグすることで自由に並び替えすることができるようになります。要素を判別するために、パーティーのモーダルにdata属性を付与しましょう。
パーティーモーダル(/Resources/Partials/Common/Modals/Party/party.php)
<div class="modal-body py-0" data-list="party">
<?php foreach(player()->getParty() as $order => $party): ?>
<div class="row py-2 bg-hover-light" data-toggle="modal" data-dubble_modal="true" data-target="#pokemon<?=$order?>-details-modal" data-order="<?=$order?>">
<div class="col-3 text-center">
<img src="/Assets/img/pokemon/dots/mini/<?=get_class($party)?>.gif" alt="<?=$party->getName()?>">
</div>
<div class="col-9">
<div class="row">
<div class="col-12">
<?=$party->getNickname()?>
</div>
</div>
<div class="row">
<div class="col-10">
<div class="progress" style="height:4px;">
<div class="progress-bar bg-<?=$party->getRemainingHp('color')?>"
role="progressbar"
style="width:<?=$party->getRemainingHp('per')?>%;"
aria-valuenow="<?=$party->getRemainingHp()?>"
aria-valuemin="0"
aria-valuemax="<?=$party->getStats('HP')?>">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-8">
<?=$party->getRemainingHp()?> / <?=$party->getStats('HP')?>
</div>
<div class="col-4">
Lv.<?=$party->getLevel()?>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php # フッター(ホーム画面のみ) ?>
<?php if(getPageName() === 'home'): ?>
<div class="modal-footer">
<form id="party-order-sort-form" method="post">
<input type="hidden" name="action" value="sort_party">
<input type="hidden" name="orders" value=''>
<?php input_token(); ?>
<button type="submit" class="btn btn-sm btn-secondary" disabled>並び替え</button>
</form>
</div>
<?php endif; ?>
ポケモンの行を囲っている要素に対してdata-list=”party”を付与して、行に対してはdata-orderにそれぞれのポケモン番号を持たせました。data-listについては、クラスやIDを使って判別しても構いません。
並び替えただけでは、セッション内の並び順までは変更できません。なので、変更をした際には並び替え確定用のsubmitを有効化させ、送信処理がされて初めて並び替えを確定させます。
※並び替えと同時に更新するのが理想ですが、そうなると更新後に再度モーダルを開いた状態を作らなければなりません。ajaxなどを使用する方法もありますが、今回は最終的に確定させるという仕様で組み上げていきます
次に、sortableの起動から送信までの処理を行うjsについてです。
パーティーモーダル用JS(/Public/Assets/js/Home/party.js)
/*----------------------------------------------------------
// 初期化する関数
----------------------------------------------------------*/
/**
* パーティーの並び替え
* @function sortable
* @return void
**/
var sortPartyInit = function(){
$('[data-list="party"]').sortable({
// 並び替え完了後に並び替えボタンを有効家
update: function(){
var submit = $('form#party-order-sort-form button[type="submit"]');
submit.prop('disabled', false)
.removeClass('btn-secondary')
.addClass('btn-primary');
}
});
}
/**
* パーティーの並び替え情報を送信
* @function submit
* @return void
**/
var submitPartyOrderSortInit = function(){
$('form#party-order-sort-form').submit(function(){
// 並び順を配列で取得
var orders = [];
$('[data-list="party"] > .row[data-order]').each(function(){
orders.push(
$(this).data('order')
);
});
// 並び順配列のJSONをセット
$(this).find('[name="orders"]')
.val(
JSON.stringify(orders)
);
});
}
/*----------------------------------------------------------
// 初期化
----------------------------------------------------------*/
jQuery(function($){
sortPartyInit();
submitPartyOrderSortInit();
});
まず、data-list=”party”に対してsortableを起動、updateのコールバック関数として、変更後には並び替えボタンを有効化させました。
並び替えの送信ボタンが押された際には、ポケモンの行にセットしたポケモン番号を上から順番に配列へ格納していき、json形式でpostしています。
これで、フロント側の処理は完成です。
並び替え処理
次に、配列内の要素の並び替えについてです。新しくSortPartyServiceを作成し、ホームコントローラー内の分岐に追加しましょう。
パーティーの並び替え(/App/Services/Home/SortPartyService.php)
<?php
$root_path = __DIR__.'/../../..';
// 親クラス
require_once($root_path.'/App/Services/Service.php');
/**
* パーティーの並び替え
*/
class SortPartyService extends Service
{
/**
* @return void
*/
public function __construct()
{
//
}
/**
* @return void
*/
public function execute()
{
// 並び替え処理
$this->sortOrders();
}
/**
* パーティーの並び替え
* @return void
*/
private function sortOrders(): void
{
// 送られてきた並び順を一意にする
$orders = array_unique(
json_decode(request('orders'))
);
// 並び替えの実行
if(player()->sortParty($orders)){
setMessage('ポケモンの並び替えをしました');
}else{
setMessage('並び替えに失敗しました');
}
}
}
もし、並び順が直接入力された場合、ポケモンのデータが消えてしまったり、増えてしまう可能性があります。それを防ぐためにも、まずは並び順の重複回避としてarray_uniqueを使って送信された値をチェックしています。
並び替え処理自体は、partyプロパティそのものを置き換えることになるので、プレイヤークラス内で行います。
パーティー操作用トレイト(/App/Traits/Class/Player/ClassPlayerPartyTrait.php)
/**
* パーティーの並び替え
* @param orders:array
* @return boolean
*/
public function sortParty($orders): bool
{
// 並び順と現在のポケモン番号を比較
if(
array_diff(array_keys($this->party), $orders) || # 差分チェック
count($this->party) !== count($orders) # 数チェック
){
return false;
}
// 並び替え後のパーティーを生成
$this->party = array_map(function($order){
return $this->party[$order];
}, $orders);
// 結果を返却
return true;
}
もし引数で受け取った並び順の配列が、パーティーより少なければ、含まれていない番号のポケモンは消失してしまいます。それを避けるためにも、まずarray_diffでパーティーの添字と並び替え番号の差分を取得します。ここでもし、添字の番号が並び替え番号に含まれていないものがあれば、配列として抽出されるので、並び替えが中止されます。
次に、ポケモンの増加を避けるための処理として、並び数の要素数を比較しています。
パーティーに3匹(0,1,2)に対して、並び順(0,1,2,3)が投げられると、一回のarray_diffでは検出できません。なので、要素数を比較することで回避しています。もし事前にarray_uniqueが行われていなかったとしても、この2重フィルターで回避することができます。
肝心な並び替えの処理自体は、並び順に対してarray_mapを使用して、新しく作成された配列をpartyへセットすることで、並び替えをしています。
それでは、実際の動きを見てみましょう。
sortableによる並び替え順が反映されていることがわかりますね。
これで、パーティーの並び替え処理は完成です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「パーティーの並び替え処理」についてご紹介しました。
sortableはいろいろな場面で活躍するので、ぜひwebアプリケーションを作る際には参考にしてみてくださいね。