我正在尝试制作一个小游戏来玩画布。我决定选择 Flappy Bird ,因为网上有很多示例。我的目标是使游戏对所有设备都“响应”。如果您在手机屏幕或任何屏幕上打开它,都应该能够正常播放。
为此,我在画布上绘制了一个背景图像,该背景图像将使高度适应屏幕的高度,并在x轴上重复它。
我遇到的问题是,当我为这只鸟设置动画时,它会在它后面留下痕迹。
就像这样:
一个简单的解决方法是按照本文中的说明清除画布:
Canvas image leaves weird trail when moving left
但是这是不可能的,因为我绘制背景的方式(我会绘制一次,如果大小会重新绘制)。
问题
如何避免静态背景下出现此图像痕迹?是否有可能具有不需要重新粉刷的虚假静态背景?
我显然想在画布上完成此操作,而无需在html中添加图片。
这是具有主要功能的代码,因此您可以看一下:
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
cvs.style.height = "100vh";
cvs.style.width = "100vw";
var bird = new Image();
var bg = new Image();
bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;
const draw = () => {
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
const resizeCanvas = () => {
const {
width,
height
} = cvs.getBoundingClientRect();
cvs.height = height;
cvs.width = width;
let x = 0,
y = 0;
while (x < cvs.width && y < cvs.height) {
ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
};
bg.onload = () => {
resizeCanvas();
};
window.addEventListener("resize", resizeCanvas, false);
draw();
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<style>
html {
overflow: hidden;
}
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
希望这确实有意义!
谢谢!
答案 0 :(得分:2)
在将要保持屏幕外的画布上绘制背景,然后在绘制运动部件之前在可见的每一帧上绘制此画布。
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
// our backround canvas that we won't append in the doc ("off-screen")
const background = cvs.cloneNode();
const bg_ctx = background.getContext('2d');
cvs.style.height = "100vh";
cvs.style.width = "100vw";
var bird = new Image();
var bg = new Image();
bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;
const draw = () => {
// first draw the background canvas
ctx.drawImage(background, 0,0);
// then your persona
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
const resizeCanvas = () => {
const {
width,
height
} = cvs.getBoundingClientRect();
// resize both canvases
cvs.height = background.height = height;
cvs.width = background.width = width;
let x = 0,
y = 0;
while (x < cvs.width && y < cvs.height) {
// draw on the off-screen canvas
bg_ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
};
bg.onload = () => {
resizeCanvas();
draw();
};
window.addEventListener("resize", resizeCanvas, false);
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<style>
html {
overflow: hidden;
}
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
答案 1 :(得分:0)
我认为您可以在绘制循环中调用resizeCanvas
来重绘背景。
编辑:显然这不起作用。另一个选择就是像这样在绘制循环中绘制它:
const draw = () => {
ctx.clearRect(0, 0, cvs.width, cvs.height)
let x = 0, y = 0;
while (x < cvs.width && y < cvs.height) {
ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
编辑:那也不起作用。另一种选择是制作两幅画布,并将它们重叠在一起,其中一幅画背景,另一幅画鸟。