javascript - 滚动大画布时有没有办法解决滞后问题?
问题描述
我正在尝试使用 vanilla JS/HTML/CSS 实现视差滚动效果;我已经实现的已经工作了,但是最下面的背景画布似乎有一个滞后(我已经制作了三个画布,一个用于容纳玩家/其他障碍物,一个用于容纳背景,一个用于容纳前景) . 滞后似乎只发生在背景(而不是前景)。
// Drawing the background
draw() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Preventing browser(s) from smoothing out/blurring lines
this.ctx.mozImageSmoothingEnabled = false;
this.ctx.webkitImageSmoothingEnabled = false;
this.ctx.msImageSmoothingEnabled = false;
this.ctx.imageSmoothingEnabled = false;
this.ctx.drawImage(this.image, this.posX, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
this.ctx.drawImage(this.image, this.posX - this.image.width, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
if (this.image.width > this.canvas.width) {
this.ctx.drawImage(this.image, this.x - this.image.width * 2, 0);
}
if (this.posX >= this.image.width) {
this.posX = 0;
}
this.scrollImage();
}
// Scrolls an image
scrollImage() {
this.posX += this.speed;
}
我已经尝试使用整数speed
来避免计算十进制像素大小,并且在查看了其他一些有关此问题的帖子后,似乎很难找到解决方法。(实际上,我不太确定这是否正是我的问题,但这是我能想到的滞后的唯一原因)。奇怪的是,前景正在无缝滚动。
这是重现问题所需的一切(我不会发布整个代码文件,因为它太长了,但我相信人们可以收集文件的剩余样板形式):
// index.html
<body>
<canvas id="background-canvas"></canvas>
<canvas id="foreground-canvas" height="302" width="802"></canvas>
<div class="overlay-wrapper"></div>
<canvas id="game-canvas" tabindex="1"></canvas>
<p>Press tab to play</p>
</body>
// index.js
const Game = require('./game');
document.addEventListener('DOMContentLoaded', function () {
// Getting main game canvas
const gameCanvas = document.getElementById('game-canvas');
const gameCanvasCtx = gameCanvas.getContext('2d');
// Parallax scrolling effect
// Getting background canvas
const backgroundCanvas = document.getElementById('background-canvas');
const backgroundCanvasCtx = backgroundCanvas.getContext('2d');
// Getting foreground canvas
const foregroundCanvas = document.getElementById('foreground-canvas');
const foregroundCanvasCtx = foregroundCanvas.getContext('2d');
const game = new Game(
gameCanvasCtx,
gameCanvas,
backgroundCanvasCtx,
backgroundCanvas,
foregroundCanvasCtx,
foregroundCanvas
);
game.start();
});
// 游戏.js
class Game {
// Constructor for game
constructor(gameCtx, gameCanvas, backgroundCtx, backgroundCanvas, foregroundCtx, foregroundCanvas) {
// Setting context and canvas
this.gameCtx = gameCtx;
this.gameCanvas = gameCanvas;
this.backgroundCtx = backgroundCtx;
this.backgroundCanvas = backgroundCanvas;
this.foregroundCtx = foregroundCtx;
this.foregroundCanvas = foregroundCanvas;
// Setting game state
this.gameOver = false;
this.paused = false;
// Binding class methods
this.draw = this.draw.bind(this);
// Creating background and foreground
this.createBackground(this.backgroundCtx, this.backgroundCanvas, this.foregroundCtx, this.foregroundCanvas);
}
// Creating the background and foreground
createBackground(backgroundCtx, backgroundCanvas, foregroundCtx, foregroundCanvas) {
// Background
const backgroundImage = new Image();
backgroundImage.src = '../dist/assets/images/background.png';
backgroundImage.alt = 'Background';
this.background = new Background(backgroundCtx, backgroundCanvas, backgroundImage, 1);
// Foreground
const foregroundImage = new Image();
foregroundImage.src = '../dist/assets/images/foreground.png';
this.foreground = new Background(foregroundCtx, foregroundCanvas, foregroundImage, 10);
}
// Drawing the game
draw() {
if (!this.gameOver) {
requestAnimationFrame(this.draw);
// Drawing background
this.background.draw();
this.foreground.draw();
}
}
// temp start function for game
start() {
this.draw();
}
}
// 背景.js
class Background {
// Constructor for background
constructor(ctx, canvas, image, speed) {
this.ctx = ctx;
this.canvas = canvas;
this.image = image;
this.speed = speed;
this.posX = 0;
}
// Drawing the background
draw() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Preventing browser(s) from smoothing out/blurring lines
this.ctx.mozImageSmoothingEnabled = false;
this.ctx.webkitImageSmoothingEnabled = false;
this.ctx.msImageSmoothingEnabled = false;
this.ctx.imageSmoothingEnabled = false;
this.ctx.drawImage(this.image, this.posX, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
this.ctx.drawImage(this.image, this.posX - this.image.width, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
if (this.image.width > this.canvas.width) {
this.ctx.drawImage(this.image, this.x - this.image.width * 2, 0);
}
if (this.posX >= this.image.width) {
this.posX = 0;
}
this.scrollImage();
}
// Scrolls an image
scrollImage() {
this.posX += this.speed;
}
}
在我的 css 文件中,这就是我为画布设置样式的方式:
body {
width: 100vw;
height: 100vh;
overflow: hidden;
}
/* For rendering sprites without blurring */
canvas {
image-rendering: pixelated;
}
/* Canvas styling */
#game-canvas {
position: absolute;
top: 0;
left: 0;
tabindex: 1;
width: 100%;
height: 100%;
z-index: 3;
}
#background-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
#foreground-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.overlay-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.25);
z-index: 2;
}
解决方案
推荐阅读
- scala - 在 Spark 集群上运行 Drools - 在 org.kie.internal.builder.KnowledgeBuilderFactory.newKnowledgeBuilder 获取空指针
- mysql - 每周六特定时间的 MySQL 事件调度程序
- c# - ES 512 jwt 令牌验证
- treeview - 是否可以重新设置 wxTreeItem 或 wxTreeListItem?
- awk - gawk 中 gensub() 的解释
- swift - 编写 switch 语句以根据数字返回图像而不重复太多代码的最佳方法是什么?
- php - 查询结果到数组字符串
- python-3.x - 为什么每次迭代我的 tqdm 进度条都显示在新行上?
- hugo - 将带有隐私包的 cookie 消息添加到 blogdown 网站
- mysql - 如何在mysql中查找同一列不同行中的两个值之间的差异