简体   繁体   English

如何在HTML5画布上创建正在播放的动画?

[英]How can I create a running animation on an HTML5 canvas?

I am building a simple 2D game as an attempt to learn canvas. 我正在构建一个简单的2D游戏,以尝试学习画布。 The character can run around a virtual environment, and a variable called yOffset controls his offset from the top of the screen. 角色可以在虚拟环境中运行,并且一个名为yOffset的变量控制其与屏幕顶部的偏移量。 I also have a global variable called running which sets itself to true or false based on whether or not the character is running (not shown here). 我还有一个名为running的全局变量,它根据字符是否正在运行而将自身设置为true或false(此处未显示)。 My goal is to make the character bob up and down whilst he is running, and all the below code does is spawn lots of setInterval() s. 我的目标是使角色在运行时上下摆动,以下所有代码都产生了许多setInterval() Is this the right way to make my character run, or should I do it another way? 这是使角色运行的正确方法,还是应该以其他方式进行? If so, how? 如果是这样,怎么办?

$(document).keydown(function(e) {
        if(e.which == 97) {
            running = true;
            run();
        } else if(e.which == 100) {
            running = true;
            run();
        } else if(e.which == 119) {
            running = true;
            run();
        } else if(e.which == 115) {
            running = true;
            run();
        }
      });

(yes, if the character stops running, the running variable does go to false [not shown here] - I've already made sure the running variable works well) (是的,如果角色停止运行,则运行变量确实变为false [此处未显示]-我已经确保了运行变量运行良好)

runTimer = 0;
function run() {
    if(runTimer == 0 && running) {
        runTimer = 1;
        yOffset = 80;
        setTimeout(function() {
            yOffset = 120;
        }, 150);
        setTimeout(function() { if (running) { runTimer = 0;run(); } }, 300);
    }
}

If you need more information, the version that I am currently working on is available here . 如果您需要更多信息,请在此处获得我当前正在使用的版本。

I think you can simplify your code, and in fact you must in the quite probable case where you'd like to add some other characters. 我认为你可以简化你的代码,而事实上,你必须在很可能的情况下,你想添加一些其它字符。

To allow re-use of the animation, it's better to separate what is an animation (== the different steps that your character will go through), and an animation state (== in which step your character is now ). 为了重新使用动画,最好将动画(==角色将经历的不同步骤)和动画状态(==角色现在位于哪一步)分开。

I wrote here some elements of an animation system. 我在这里写了动画系统的一些元素。
So i define what is an animation step, a whole Animation (which is so far only an array of animation step), and an Animator (which holds the state, one might see it as a 'reader' of an animation). 因此,我定义了什么是动画步骤,整个动画(到目前为止,这只是动画步骤的一个数组)和一个动画器(保存状态,有人可能会将其视为动画的“读取器”)。

Once you defined the animation and animators, and started the animators, you just have to call tick(time) to have the animation move on, and offset() to read the offset, which is way simpler than fighting with a bunch of setIntervals. 一旦定义了动画和动画师,并启动了动画师,您只需要调用tick(time)以使动画继续前进,并调用offset()来读取偏移量,这比与一堆setIntervals战斗要简单得多。

http://jsfiddle.net/xWwFf/ http://jsfiddle.net/xWwFf/

// --------------------
function AnimationStep(duration, offset) {
    this.duration = duration;
    this.offset = offset;
    // you might add : image index, rotation, ....
}

// --------------------
function Animation(animationSteps) {
    this.steps = animationSteps;  // Array of AnimationStep
}

// define a read-only length property
Object.defineProperty(Animation.prototype, 'length', {
    get: function () {
        return this.steps.length
    }
});

// --------------------
function Animator() {
    this.currentAnimation = null;
    this.step = -1;
    this.running = false;
    this.remainingTime = 0; // remaining time in current step;
}

Animator.prototype.startAnim = function (newAnim, firstStep) {
    this.currentAnimation = newAnim;
    this.step = firstStep || 0;
    this.remainingTime = newAnim.steps[this.step].duration;
    this.running = true;
}

Animator.prototype.tick = function (dt) {
    // do nothing if no animation ongoing.
    if (!this.running) return;
    this.remainingTime -= dt;
    // 'eat' as many frames as required to have a >0 remaining time
    while (this.remainingTime <= 0) {
        this.step++;
        if (this.step == this.currentAnimation.length) this.step = 0;
        this.remainingTime += this.currentAnimation.steps[this.step].duration;
    }
};

Animator.prototype.offset = function () {
    return this.currentAnimation.steps[this.step].offset;
}

// ______________________________
// example

var bounceAnim = [];
bounceAnim.push(new AnimationStep(200, 10));
bounceAnim.push(new AnimationStep(180, 20));
bounceAnim.push(new AnimationStep(150, 30));
bounceAnim.push(new AnimationStep(300, 40));
bounceAnim.push(new AnimationStep(320, 45));
bounceAnim.push(new AnimationStep(200, 40));
bounceAnim.push(new AnimationStep(120, 30));
bounceAnim.push(new AnimationStep(100, 20));

var anim1 = new Animation(bounceAnim);

var animator1 = new Animator();
var animator2 = new Animator();

animator1.startAnim(anim1);
animator2.startAnim(anim1, 3);

// in action :
var ctx = document.getElementById('cv').getContext('2d');

function drawScene() {
    ctx.fillStyle = 'hsl(200,60%, 65%)';
    ctx.fillRect(0, 0, 600, 200);
    ctx.fillStyle = 'hsl(90,60%,75%)';
    ctx.fillRect(0, 200, 600, 200);
    ctx.fillStyle = 'hsl(10,60%,75%)';
    ctx.fillRect(200, 200 + animator1.offset(), 22, 22);
    ctx.fillStyle = 'hsl(40,60%,75%)';
    ctx.fillRect(400, 200 + animator2.offset(), 22, 22);
    animator1.tick(20);
    animator2.tick(20);
}

setInterval(drawScene, 20);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM