延迟 globalTick() JS 中每个精灵的 tick()

Delay tick() of each sprite within a globalTick() JS

必须有一个非常简单的解决方案,因为我已经尝试过使用 setInterval(),但似乎无法获得我想要的结果...

我有这个 globalTick()

function globalTick(){
    ctx.clearRect(0,0,800,800)

    if(target){
        target.tick();
    }

    // Move arrows
    for(var i = 0; i < spriteList.length; i++){
        spriteList[i].tick()
    }


    window.requestAnimationFrame(globalTick);
}

document.onkeyup = function(e){
    // Change gamestate
    if(e.which == 13){
        $("#state"+gameState).hide()
        gameState ++

        if(gameState == 6){
            // Affect game variables
            player = new Player(0);
            target = new Target(targetX, targetY)

            for(var i = 0; i < player.calculateNotes(); i++){
                timerID = setInterval(spawnArrows(), 3000)
            }
            clearInterval(timerID)
    }

    // ...

spawnArrows = function(){
    // Rabdomize arrows (15 for now)
    var dirCode = Math.floor((Math.random() * 8));
    spriteList.push(new Arrow(dirCode))
    //soundsSequence.push(soundsList[dirCode])
}

然后我在精灵上使用了这个 tick() 方法,在本例中是一个箭头对象

    class Arrow{
        constructor(dirCode){
            this.dirCode = dirCode;
            this.speedX = 1
            this.speedY = 1

             switch(this.dirCode){
                // ...
            }

    tick(){
            ctx.fillStyle = "black"
            ctx.fillRect(this.x, this.y, spriteSize, spriteSize)

            switch(this.dirCode){
                case 0:
                    this.x += this.speedX
                    break
                case 1:
                    this.x += this.speedX
                    this.y -= this.speedY
                    break
                // ...

我给你们省去了变量声明。

我想要的是将每个新箭头延迟推入数组的时间设置为另一个对象中存在的时间,在示例中假设为 3 秒。是否有可能在 requestAnimationFrame 每秒调用 60 次左右的 globalTick() 中放慢速度?理想情况下在纯 JS 中,除非 JQuery 是唯一的方法...

非常感谢,希望这足够清楚!

这是一个使用 setTimeout 队列的解决方案。

部分应用的 spawnArrow 函数被推入队列。 spawnQueue.shift()(); 从队列中删除第一个函数并调用它。

JSFiddle demo

let notes = ["A", "B", "C", "D", "E"];
let spriteList = [];
let spawnQueue = [];
let delayTime = 500;

function globalTick() {
    spriteList.forEach(sprite => sprite.tick());
    requestAnimationFrame(globalTick);
}
globalTick();

$('button').click(onButtonClick);

function onButtonClick() {
    let kickOffQueue = spawnQueue.length <= 0;

    notes.forEach(note =>
        spawnQueue.push(() => spawnArrow(note))
    );

    if (kickOffQueue) {
        // here you can set the delay time of the first execution
        consumeSpawnQueue(500);
    }
}

function consumeSpawnQueue(nextDelayTime) {
    if (spawnQueue.length > 0) {
        setTimeout(() => {
            spawnQueue.shift()();
            consumeSpawnQueue(delayTime);
        }, nextDelayTime);
    }
}

function spawnArrow(note) {
    var dirCode = Math.floor((Math.random() * 8));
    spriteList.push(new Arrow(dirCode, note));
}

class Arrow {
    constructor(dirCode, note) {
        this.dirCode = dirCode;
        this.x = 0;
        this.domEl = $(`<div>${note}${dirCode}</div>`).appendTo('body');
    }

    tick() {
        this.x += 1;
        this.domEl.css({
            marginLeft: this.x
        });
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>spawnArrows</button>

注意:setTimeout 的时间不是很准确 - 它只保证最小延迟。如果您需要时间准确性,则必须像这样计算经过的时间:

const startTime = new Date();
const elapsedTime = () => (new Date() - startTime) / 1000;

在您的 globalTick 游戏循环中:

if ((elapsedTime() - lastSpawnArrowTime) > delayTime) {
    spawnQueue.shift()();
}

在 spawnArrow 函数中,您将设置:

lastSpawnArrowTime = elapsedTime()