首页 > 解决方案 > 滚动大画布时有没有办法解决滞后问题?

问题描述

我正在尝试使用 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;
}

标签: javascriptcanvas

解决方案


推荐阅读