简体   繁体   English

在HTML5游戏中实现计时器

[英]Implement a Timer in HTML5 Game

I'm trying to build a small game on an HTML5 canvas, and I'm running into a bit of trouble when trying to set a 1 minute countdown timer in game. 我正在尝试在HTML5画布上构建一个小型游戏,尝试在游戏中设置1分钟倒数计时器时遇到了麻烦。

The following code contains the timeKeeper function and the animate loop. 以下代码包含timeKeeper函数和animate循环。

timeKeeper 计时员

function timeKeeper(width, font, posX, posY, text) {
    this.width = width;
    this.x = posX;
    this.y = posY;
    this.font = font;
    this.text = text;
    this.numSeconds = 0;
    this.time = 0;

    this.draw = () => {
        c.font = this.width + " " + this.font;
        c.fillStyle = "white";
        c.fillText(this.text, this.x, this.y);
    }

    this.update = () => {
        setInterval(() => {
            this.text -= 1;
        },1000)
        this.draw();
    }

}

animate 活跃

// Animation Loop
function animate() {
    requestAnimationFrame(animate)
    c.clearRect(0, 0, canvas.width, canvas.height)
    timeBoard.update()
    //Move enemies
    enemies.forEach((enemy) => {
        //update score and time
        scoreBoard.draw();

        //draw labels
        scoreLabel.draw();
        timeLabel.draw();

        //update enemies
        enemy.update();
        enemy.checkBoundary();
        if (enemy.isTrue == true) {
            enemies.splice(enemies.indexOf(enemy), 1);
            // console.log(enemies);
        }

        if (enemies.length == 0) {
            setTimeout(initEnemies(), 200)
        }

        //collision detection by checking color
        if (enemy.color == "#2185C5") {
            if (getDistance(enemy.x, enemy.y, ship[0].x, ship[0].y) < enemy.radius + ship[0].radius) {
                enemy.color = "#FF00FF"
                scoreBoard.update();
            }
        }
    });
    //create one particle
    ship[0].update();
}

What I think happens here is that the timeBoard.update() function gets called every frame, causing the countdown to be really fast. 我认为这里发生的是timeBoard.update()函数每帧都会调用一次,从而导致倒数真的非常快。

Can anyone help me figure this out? 谁能帮我解决这个问题?

Thanks in advance. 提前致谢。

You need to have the counter run outside the animate frame loop method. 您需要使计数器在动画帧循环方法之外运行。 You could add some kind of timer within the function to compensate for the frame (60fps means animate() will run approximately every 16.667ms) time but, requestAnimationFrame() doesn't always run at 60fps. 您可以在函数内添加某种计时器来补偿帧(60fps意味着animate()大约每隔16.667ms运行一次),但是requestAnimationFrame()并不总是以60fps运行。 If the browser can't render at that pace, it will slow down the frame loop. 如果浏览器无法以这种速度渲染,则会降低帧循环的速度。 Therefore, it isn't a good idea to make a timer that is at all related to requestAnimationFrame(); 因此,制作一个与requestAnimationFrame();有关的计时器不是一个好主意requestAnimationFrame(); .

Instead, made a counter outside the function. 而是在函数外部创建一个计数器。 Ideally, use setInterval() right before you start the animate loop. 理想情况下,请在开始动画循环之前立即使用setInterval() The interval might look something like this.... 时间间隔可能看起来像这样...

var counter = 0;
var timer = window.requestAnimationFrame(function(){
  timeBoard.update();
  if(counter+1 == 60){
    //a minute has passed, clear the interval:
    clearInterval(timer);
  }else{
    counter++;
  }
},1000);

If you include the code that starts the animate loop in your question details, I can help show exactly how you would implement it. 如果您在问题详细信息中包含启动动画循环的代码,那么我可以帮助您确切地说明如何实现它。 Also, you don't mention if you need the counter to be reusable. 另外,您没有提及是否需要计数器可重复使用。 These are all things to consider. 这些都是要考虑的事情。 If you need it to be reusable, you might consider using an object oriented solution. 如果需要可重用,则可以考虑使用面向对象的解决方案。

The setInterval function stacks, meaning that it will keep on creating setInterval instances. setInterval函数堆栈,这意味着它将继续创建setInterval实例。 By calling timeBoard.update() repeatedly, you are creating many instances of setInterval, making your timer run faster than it should. 通过重复调用timeBoard.update(),您将创建许多setInterval实例,从而使计时器运行得更快。 You could change your update method to something like init , and then call that once outside of the animation loop. 您可以将update方法更改为init ,然后在动画循环之外调用该方法。

Called timeBoard.draw() within the animation loop in order to get the timer drawn. 在动画循环中调用timeBoard.draw()以便绘制计时器。 Then called the setInterval() function outside the animation loop. 然后在动画循环之外调用setInterval()函数。

Thank you all~ :) 谢谢大家〜:)

function animate() {
    requestAnimationFrame(animate)
    c.clearRect(0, 0, canvas.width, canvas.height)
    timeBoard.draw()
    //Move enemies
    enemies.forEach((enemy) => {
        //update score and time
        scoreBoard.draw();

        //draw labels
        scoreLabel.draw();
        timeLabel.draw();

        //update enemies
        enemy.update();
        enemy.checkBoundary();
        if (enemy.isTrue == true) {
            enemies.splice(enemies.indexOf(enemy), 1);
            // console.log(enemies);
        }

        if (enemies.length == 0) {
            setTimeout(initEnemies(), 200)
        }

        //collision detection by checking color
        if (enemy.color == "#2185C5") {
            if (getDistance(enemy.x, enemy.y, ship[0].x, ship[0].y) < enemy.radius + ship[0].radius) {
                enemy.color = "#FF00FF"
                scoreBoard.update();
            }
        }
    });
    //create one particle
    ship[0].update();
}

//Run Timer
setInterval(() => {
    timeBoard.update()
}, 1000)

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

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