ボールアニメーション
前回までに作成した捕獲判定処理を使って、ボールのアニメーションを作成します。
捕獲演出は以下の通りです。
- 味方側から相手に向かってボールを投げる
- 相手ポケモンの前でボールを開く
- 捕獲判定で算出した揺れ回数分ボールを揺らす
捕まえた際は、ボールの揺れをストップさせて完了メッセージ、失敗時には再度ボールを開くという分岐を作ります。
それでは、必要な処理と素材について見ていきましょう。
ボールを開く
ボールを開くにもいろんな演出があります。今回は初代のボール使用時の演出に似せたgif画像を使用します。
3種類の大中小の丸を作成、大・中は破線にして3フレーム並べたgifアニメーションです。
相手ポケモンにボールがヒットした際にこのgif画像を表示、失敗時にも同じようにポケモンの上で再生することで、初代のような演出を再現していきます。
こちらは必要な際に自由に呼び出せるよう、ボールと同じくtemplateタグとして用意します。
effect用テンプレート(Resources/Partials/Layouts/Templates/template-effects.php)
<template id="template-effect-ball">
<img src="" alt="ボール" class="capture-ball">
</template>
<template id="template-effect-ball-open">
<img src="/Assets/img/animation/ball/ball-open.gif" alt="ボール オープン" class="capture-ball open">
</template>
ボールには、レスポンスで返すパスを当てはめて使います。テンプレートとして用意するメリットとして、必要なタイミングでパーツを呼び出すことができ、コード自体の視認性も良くなるという点が挙げられます。
放物線を描く
モンスターボールを投げる軌道は放物線を描く必要があります。ボール自体はabsolute、バトルフィールドをrelativeでそれぞれポジション設定をしておき、ボールのtopとleftの値をキーフレームアニメーションで動かしていきます。
バトル画面用メッセージjs(/Public/Assets/js/Battle/message.js)
// ==============================================
// 捕獲処理 =====================================
/**
* @param integer
* @return Promise
**/
var doAnimateCapture = function (param){
return new Promise ((resolve, reject) => {
// ボール画像を取得
var ball = $($('#template-effect-ball').html());
ball.attr('src', param.src);
$('#battle-field').prepend(ball);
// キーフレームの用意
var l = 25;
var t = 15;
var keyframes = {
name: 'throw-ball'
};
for (var i = 0; i <= 100; i++) {
var left = l + (i / 2); // x座標
var top = t + 100 ** ((100 - i + 1) / 100) / 2; // y座標(累乗で山なりにする)
var rotate = 3.6 * i * 1.5 - 180; // 回転率
var per = i + '%';
keyframes[per] = {
transform: 'translateY(-50%) translateX(-50%) rotate(' + rotate + 'deg)',
left: left + '%',
top: top + '%'
};
// 最後の基準Y値は、揺れ処理用に合わせて-100%にする
if(i === 100){
keyframes[per].transform = 'translateY(-100%) translateX(-50%) rotate(' + rotate + 'deg)';
}
}
$.keyframe.define(keyframes);
// ボールスローアニメーション
ball.show();
ball.playKeyframe({
name: 'throw-ball',
duration: '750ms',
timingFunction: 'ease',
delay: '0s',
iterationCount: 1, // 繰り返し回数
direction: 'normal',
fillMode: 'forwards',
complete: async function(){
// ボールエフェクト
ball.hide();
$('#battle-field').append(
$($('#template-effect-ball-open').html())
);
await timer(500);
// 相手ポケモンを非表示
ball.show();
$('img.capture-ball.open').hide();
$('#enemy-pokemon-image').hide();
// 揺れ演出
await shakeBall(ball, param.shake);
if(param.shake >= 4){
// 捕獲成功
resolve();
}else{
// 捕獲失敗
// ボールエフェクト
ball.remove();
$('#battle-field').append(
$('#template-effect-ball-open').html()
);
// 相手ポケモンを表示
$('#enemy-pokemon-image').show();
await timer(500);
// 非表示
$('img.capture-ball.open').hide();
await timer(500);
resolve();
}
}
});
});
}
開始点がleft25%、top65%の位置になります。放物線を描くためには、Y軸であるtop値がどんどん原則していくようにしなければならないため、回数に対して100―回数の100分の1の値を累乗、それを最終的な移動値(50)に変換するために割る2、を加算することで求めています。
※累乗でスピードの変化を算出できることはわかりましたが、無理やり式を作成して完成させた放物線式のため、もしもっときれいな計算式が組める人はぜひ挑戦してみてください。
また、ボールは投げられると回転しておくほうが自然のため、座標軸を中心においてrotateで1回転半させています。
ボールの揺れ
レスポンスでボールの揺れ回数を返却しているため、この値を使ってボールの揺れアニメーションを作成します。
/**
* 揺れアニメーション
* @param ball:element
* @param count:integer
* @return Promise
**/
var shakeBall = function(ball, count){
return new Promise ((resolve, reject) => {
$.keyframe.define({
name: 'shake-ball',
'0%': {
transform: 'translateY(-100%) translateX(-50%) rotate(0deg)'
},
'30%': {
transform: 'translateY(-100%) translateX(-50%) rotate(45deg)'
},
'60%': {
transform: 'translateY(-100%) translateX(-50%) rotate(-45deg)'
},
'90%': {
transform: 'translateY(-100%) translateX(-50%) rotate(0deg)'
},
});
ball.playKeyframe({
name: 'shake-ball',
duration: '500ms',
timingFunction: 'ease',
delay: '500ms',
iterationCount: count, // 繰り返し回数
direction: 'normal',
fillMode: 'forwards',
complete: function(){
setTimeout(function() {
resolve();
}, 500);
}
});
});
}
揺れを自然にするため、ボールの軸点は画像下中央として、45度ずつ左右へ揺らしています。もし回数が4回以上であれば捕獲完了だということが判定できるので、そのままアニメーションを終了、3回以下であればボールを再度開いてポケモンを再表示させています。
それでは、捕獲アニメーション一連の流れを見てみましょう。
失敗、成功どちらも正常に表示されました。細かなアニメーション演出には修正が必要ですが、大本はこれで完成です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンではボール使用時の演出をご紹介しました。
プログラミングやゲームづくりに興味がある方は、ぜひ参考にしてみてくださいね。