2013-11-27 60 views
0

我正在构建一个简单的2D游戏,试图学习画布。角色可以在虚拟环境中运行,并且名为yOffset的变量控制他从屏幕顶部的偏移量。我也有一个叫做running的全局变量,根据角色是否正在运行将它自己设置为true或false(此处未显示)。我的目标是在跑步期间让角色上下摆动,下面的代码确实会产生大量的setInterval() s。这是让我的角色跑步的正确方法吗,还是我应该以另一种方式去做?如果是这样,怎么样?如何在HTML5画布上创建运行动画?

$(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(); 
     } 
     }); 

(是的,如果字符停止运行时,运行变量不进入假[此处未示出] - 我已经确信运行变量效果很好)

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); 
    } 
} 

如果您需要更多信息,我目前正在使用的版本可用here

回答

1

我认为你可以简化你的代码,事实上你必须在很可能的情况下,你想添加一些其他字符。

要允许重新使用动画,最好分开什么是动画(==你的角色将经历的不同步骤)和动画状态(==现在你的角色现在是)。

我在这里写了一些动画系统的元素。
所以我定义了什么是动画步骤,整个动画(迄今为止只有动画步骤的一个数组),以及一个动画师(持有状态,人们可能将其视为动画的'读者')。一旦你定义了动画和动画师,并启动了动画师,你只需要调用tick(时间)让动画继续,offset()读取偏移量,这比用一堆setIntervals。

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);