特にJank Bustersの話を見た後、私は最近、アニメーションが多いWebサイトでHTML5 -requestAnimationFrame
- APIをたくさん使用するようになりました。これはかなりうまくいくようで、多くの場合実際にパフォーマンスを向上させます。
まだ1つの質問がまだ私に残っています:[〜#〜] [〜#〜]完全に計算されていないアニメーションを使用したい場合(たとえば、スプライトシートを考えてください)固定フレームレートを目指します。もちろん、setInterval
を再び使用することもできますが、これに対処する他の方法があるかもしれません。
固定フレームレートでrequestAnimationFrame
を使用する方法は2つ考えられます。
var fps = 25; //frames per second
function animate(){
//actual drawing goes here
setTimeout(function(){
requestAnimationFrame(animate);
}, 1000 / fps)
}
animate();
または
var fps = 25; //frames per second
var lastExecution = new Date().getTime();
function animate(){
var now = new Date().getTime();
if ((now - lastExecution) > (1000 / fps)){
//do actual drawing
lastExecution = new Date().getTime();
}
requestAnimationFrame(animate);
}
animate();
個人的には、2番目のオプション(最初のオプションは不正行為のように感じる)を選択しますが、特定の状況では、それはbuggyのようです。
このアプローチは本当に価値がありますか(特に12.5のような低いフレームレートで)?改善すべき点はありますか?これに取り組む別の方法はありますか?
アニメーションは、計算が完全に時間の関数であっても計算する必要があります。また、いつでも[アニメーション]画像をdraw()
でき、適切なフレームを取得していることを確認できます。あなたはこのようなものを望みますが、必ずしもそうではありませんthis:
// whatever your "attributes" looks like, the point is you've given enough
// information to the constructor to find ordered frames in the image and know
// the framerate
function SpriteAnimation(image, attributes) {
// you probably want a SpriteFrame "class" to populate here, based on whatever
// existing code you use to extract frames from the Sprite
this.frames = [ SpriteFrame, SpriteFrame, ... ];
// ... getFramesFromImageAndAttributes(image, attributes)
// if the animation is running, this is the time it started
this.startTime = 0;
// whatever your framerate is ...
this.fps = 25; // getFPSFromAttributes(frame_attributes)
// whether the animation loops infinitely
this.loop = true; // getLoopFlagFromAttributes(frame_attributes)
// for canceling the animationframe request, if necessary
this.animationFrameRequestId = null;
// draw whichever frame should be visible *right now*
this.draw = function() {
// unconditionally show the first frame if the animation isn't running
if (this.startTime == 0) {
this.frames[0].draw();
return;
}
// there may be a better and more accurate way to compute this ...
var frame_duration = 1000 / this.fps;
var now = (new Date()).getTime();
var elapsed_time = now - this.startTime;
var visible_frame = Math.floor(elapsed_time / frame_duration);
if (visible_frame_number > frames.length) {
if (!this.loop) {
// we're past the end of the animation and we're not looping.
// stop the animation.
this.startTime = 0;
visible_frame = 0;
}
}
this.frames[visible_frame % frames.length].draw();
if (this.startTime != 0) {
var _t = this;
requestAnimationFrame(_t.draw);
}
}
this.animate = function() {
this.startTime = (new Date()).getTime();
var _t = this;
requestAnimationFrame(_t.draw);
}
this.stop = function() {
this.startTime = 0;
if (this.animationFrameRequestId) {
cancelAnimationFrame(this.animationFrameRequestId);
}
}
}
var a = new SpriteAnimation("/path/to/image.jpeg", {
fps: 25,
frame_width: 100,
frame_height: 100,
image_width: 1000,
image_height: 10000
});
a.animate();
...または何でも。
シームレスなアニメーションの場合、スプライトベースでも2番目のオプションであるDate.now()
を使用します。忘れないで
戻り値
requestIDは、コールバックリストのエントリを一意に識別する長整数値です。これはゼロ以外の値ですが、その値について他の仮定を行うことはできません。この値をwindow.cancelAnimationFrame()に渡して、更新コールバック要求をキャンセルできます。
(from [〜#〜] mdn [〜#〜] )