2013-11-27 104 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);