【问题标题】:How do you prevent glitching when trying to render something in a canvas?尝试在画布中渲染某些内容时如何防止出现故障?
【发布时间】:2021-03-30 15:41:57
【问题描述】:

所以,我正在尝试使用箭头键让角色在屏幕上移动,虽然它有效,但它会留下条纹。我不希望我的后端出现条纹。我知道它为什么会出现这些条纹,但不知道如何摆脱它们。条纹的原因是玩家正在从画布中清除,然后以很大的延迟进行渲染。我该如何阻止它?

编辑:我希望它只清除播放器,周围什么都没有。

片段:

const c = document.getElementById('c')
const ctx = c.getContext('2d')

c.height = window.innerHeight
c.width = window.innerWidth

let blockInfo = {
    h: 15, // Height in pixels. I'm gonna use this like blocks, like this: blockAmount * blockInfo.h
    w: 15
}

let renderedPlayer = false // The player wasn't rendered yet so this is false

let player = {
    speed: 0.125,
    x: 2,
    y: 2,
    height: 1,
    width: 1
}

function clearPlayer() { // I think this is where the glitch comes in.
    ctx.clearRect(player.x * blockInfo.w, player.y * blockInfo.h, player.width * blockInfo.w, player.height * blockInfo.h)
}

function renderPlayer() {
    ctx.fillRect(player.x * blockInfo.w, player.y * blockInfo.h, player.width * blockInfo.w, player.height * blockInfo.h)
}

function press(e) { // When a character on the keyboard gets pressed:
    let w = e.which
    
    if (renderedPlayer == true) {
        clearPlayer() // It clears the player before the player moves, so it doesn't have more streaks.
        
        if (w == 39) {
            player.x += player.speed
        } else if (w == 37) {
            player.x -= player.speed
        } else if (w == 38) {
            player.y -= player.speed
        } else if (w == 40) {
            player.y += player.speed
        }
    }
}

setInterval(function() { // Rendering player each MS.
    renderedPlayer = false
    renderPlayer()
    renderedPlayer = true
}, 0)
body {
    margin: 0;
    overflow: hidden;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>repl.it</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body onkeydown="press(event)">
    <canvas id="c"></canvas>

    <script src="script.js"></script>
  </body>
</html>

【问题讨论】:

  • 在每一帧开始时清除整个画布。当您开始拥有许多移动物体时,很难清除它们。 ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height) 非常非常快。也使用requestAnimartionFrame developer.mozilla.org/en-US/docs/Web/API/window/… 而不是走内存泄漏setInterval
  • 这会有所帮助,但您可以将其作为答案而不是评论。不过,还是谢谢你的教导。

标签: javascript html css html5-canvas


【解决方案1】:

我会在你绘制之前清除整个画布,如下所示:

const c = document.getElementById('c')
const ctx = c.getContext('2d')
c.height = c.width = 180

let blockInfo = {h: 15,  w: 15}
let player = {speed: 0.1, x: 2, y: 2, height: 1, width: 1}

function render() {
  ctx.clearRect(0, 0, c.width, c.height)
  
  //renderOtherStuff
  ctx.fillStyle = "#FF0000";
  ctx.arc(75, 75, 60, 0, Math.PI * 2, true);  
  ctx.fill();

  //renderPlayer
  ctx.fillStyle = "#000000";
  ctx.fillRect(player.x * blockInfo.w, player.y * blockInfo.h, player.width * blockInfo.w, player.height * blockInfo.h)
}

function press(e) { // When a character on the keyboard gets pressed:
  let w = e.which
  if (w == 39) {
    player.x += player.speed
  } else if (w == 37) {
    player.x -= player.speed
  } else if (w == 38) {
    player.y -= player.speed
  } else if (w == 40) {
    player.y += player.speed
  }
}

setInterval(render, 25)
<body onkeydown="press(event)">
  <canvas id="c"></canvas>
</body>

只清除播放器会带来其他问题,因为您引入了可能重叠的其他对象,当您清除播放器时,您还清除了可能包含其他东西的背景。

...另外,这看起来像是一个简单游戏的开始,如果你是认真的,请研究一个合适的游戏引擎,那里有一堆开源的:
https://github.com/collections/javascript-game-engines

【讨论】:

  • 对不起,但我确实提到我不希望它清除任何东西,但播放器。为什么我只希望它清除播放器是因为如果我在画布中添加不同的东西,它也会被清除。如果您有解决方案,您可以编辑此答案。
  • @UnknownBobby 当您绘制多个东西时,同样的解决方案也适用,您应该清除整个画布并重新绘制所有内容
  • @UnknownBobby 我编辑了我的答案,以展示它在画布上的不同外观......但是当你有时间时,请查看一个合适的游戏引擎,这将在以后为你省去很多麻烦
  • 是的,但我不喜欢复制。这让我觉得..我不知道。
  • 不喜欢抄袭是什么意思?你认为你可以自己创造一个更好的游戏引擎吗?并且使用您不会复制的游戏引擎,您将使用一套好的工具来构建您的游戏。 _ _ _ 想想如果像木匠一样,您可以使用手锯来制作东西或使用专业的电锯台,每次都能快速准确地切割
猜你喜欢
  • 2015-02-17
  • 1970-01-01
  • 2022-01-21
  • 2018-09-24
  • 2018-08-10
  • 2021-03-30
  • 1970-01-01
  • 2013-11-27
  • 1970-01-01
相关资源
最近更新 更多