首页 > 解决方案 > 无法在 javascript 中强制刷新画布

问题描述

我试图让游戏定期刷新画布,主循环包括一个重播屏幕的函数和一个让计算机计算移动的函数(如果轮到它的话)。玩家可以选择 1-9 步,然后,如果计算机在玩家最后一次移动后还没有运行,它将使用一个非常深的树来计算它的移动。计算机移动需要几秒钟才能移动。尽管在计算机移动之前已经更新了画布,但直到计算机离开后它才会刷新,这意味着玩家和计算机移动是同时显示的,而不是顺序显示的。我能做些什么来确保画布每 100 毫秒更新一次,而不是在计算机计算出它的移动之后才更新?

function playGame() {
    function doKeyDown(evt) {
        console.log(evt.keyCode)
        if (evt.keyCode > 48 && evt.keyCode < 58) { 
            game.makeMove(evt.keyCode-48); // 1-9 are user actions
        }
    }

    function mainLoop(ctx, game, board) {
        board.showBoard(ctx); // display board
        game.makeMove(0); // zero is computer move
    }

    Canvas.canvas = document.getElementById("myCanvas");
    let game = new Game();
    let board = new Board(game);
    window.addEventListener( "keydown", doKeyDown, true);
    Canvas.ctx = Canvas.canvas.getContext('2d');
    setInterval(() => {mainLoop(Canvas.ctx, game, board)}, 100);
};  

document.addEventListener('DOMContentLoaded', playGame);

标签: javascriptcanvas2d-games

解决方案


有几件事绝对可以帮助您确保您的画布在您期望的时候刷新。

  1. 将计算密集型任务转移到 Web Worker 中。

  2. 利用window.requestAnimationFrame()而不是setInterval()用于渲染。

网络工作者

Web Workers 非常适合将计算密集型任务转移到;Web Workers 的 MDN 文档指出,“工作线程可以在不干扰用户界面的情况下执行任务。” 这将允许在不阻塞渲染线程的情况下计算计算机的移动。

有关 Web Workers 的更多信息,请参阅:Web Workers (MDN Web Docs)

window.requestAnimationFrame()

window.requestAnimationFrame()方法是目前实现动画的最佳方法。本质上,它会导致浏览器在下一次重绘之前执行提供的回调。setTimeout()这是对之前的and方法的改进,setInterval()因为它只在浏览器重绘之前调用回调,换句话说,它减少了使用setTimeout()and可能导致的不必要的计算setInterval()

有关更多信息,window.requestAnimationFrame()请参阅:window.requestAnimationFrame() (MDN Web Docs)

有关为什么要选择的简短文章window.requestAnimationFrame()setTimeout()setInterval()参阅 Matt West 的这篇文章:Efficient Animations with requestAnimationFrame

工作示例:

我使用codesandbox.io 整理了一个小的工作示例;正如我所描述的,它使用 Web Workers 和 requestAnimationFrame()。请注意,它使用计时器代替计算密集型任务,它使用 5 秒计时器来模拟计算机移动,并使用 1 秒计时器来模拟玩家移动。

代码沙箱:Web Worker 和 requestAnimationFrame() 示例


推荐阅读