「10-10 アニメーションタイマーとしての利用」で述べた”2 セットした時間を繰り返し、その回数を教えてくれるタイマー”の例です。ここでは、Animation.effect.getComputedTiming()が返すcurrentIterationを利用します。
ページを開くと、カミナリ小僧がジャンプを始めます。最初は少しだけジャンプしますが、次第に高くジャンプするようになります。
この例では、ジャンプや落下表現に物理的な計算方法を用いて、<canvas>要素に描画しています。アニメーションタイマーの作成には、duration値に加え、繰り返し回数のiterationsも指定したタイミングパラメータを使用しています。
// 5秒を4回刻むアニメーションタイマー
const timings = {iterations: 4, duration: 5000};
// ターゲットはnull、keyframesはnull
const effect = new KeyframeEffect(null, null, timings);
const animationTimer = new Animation(effect, document.timeline);
また、getComputedTiming()が返すcurrentIterationは、requestAnimationFrame()から呼び出されるアニメーションループで、繰り返し回数に応じたジャンプ力の算出に用いています。
// 今の繰り返し回数を取得(0~3)
currentIteration = animationTimer.effect.getComputedTiming().currentIteration;
…
// 今の繰り返し回数をジャンプ力に変える。
// 繰り返し回数が増えるほど、ジャンプ力が増す
jumpPower = (currentIteration+1)*(-10);
// <canvas>要素のコンテキストを準備
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.font = '20px century';
// 5秒を4回刻むアニメーションタイマー
const timings = {
iterations: 4,
duration: 5000
};
// ターゲットはnull、keyframesはnull
const effect = new KeyframeEffect(null, null, timings);
const animationTimer = new Animation(effect, document.timeline);
// かみなり小僧の最初の位置
const xpos = 140;
let ypos = canvas.height - 84;
const kaminari = new Image();
const cloud = new Image();
// かみなり小僧の画像をロードし、
kaminari.addEventListener('load', () => {
// キャンバスに描画
context.drawImage(kaminari, xpos, ypos);
// 次いで、雲の画像をロード
cloud.src = "images/cloud.png";
}, false);
kaminari.src = "images/kaminari.png";
// 雲の画像がロードできたら
cloud.addEventListener('load', () => {
// キャンバスに描画
context.drawImage(cloud, 120, 10);
// アニメーションタイマーが準備できたら、
animationTimer.ready.then(() => {
// 再生開始
animationTimer.play();
// JavaScriptアニメーションをスタート
render();
});
}, false);
// かみなり小僧のジャンプアニメーションに使用する変数
let ay = 0;
let isGoingUp = true;
const friction = 0.9;
const GRAVITY = 2;
let jumpPower = 0;
const ground = canvas.height;
const H = 84; //kaminari.height;
let currentIteration = 0;
const update = () => {
// ジャンプのパワーを足す
if (isGoingUp) {
ay = jumpPower;
}
// 落下要因
ay += GRAVITY;
// 落下する
ypos += ay;
// 着地
if (ypos > ground - H) {
// 地面で跳ね返り
ay *= -1;
ay *= friction;
ypos = ground - H;
// 跳ね返り終わり
if (Math.abs(ay) < GRAVITY) {
ay = 0;
// 今の繰り返し回数を取得(0~3)
currentIteration = animationTimer.effect.getComputedTiming().currentIteration;
if (currentIteration === null) {
currentIteration = 0;
}
// 今の繰り返し回数をジャンプ力に変える。
// 繰り返し回数が増えるほど、ジャンプ力が増す
jumpPower = (currentIteration + 1) * (-10);
isGoingUp = true
}
// ジャンプしたら後は落下
}
else {
isGoingUp = false;
}
}
// コンテキストで描画
const draw = () => {
// キャンバスをクリア
context.clearRect(0, 0, canvas.width, canvas.height);
// コンテキストを一時的に保存
context.save();
// かみなり小僧を適切な位置に描画
context.drawImage(kaminari, xpos, ypos);
// 雲を決まった位置に描画
context.drawImage(cloud, 120, 10);
// キャンバスの左上に、今の繰り返し回数とジャンプ力を描画
context.fillText(currentIteration, 27, 30);
context.fillText(jumpPower, 10, 50);
// コンテキストを回復
context.restore();
}
const render = () => {
update();
draw();
window.requestAnimationFrame(render);
}