HTML5 Canvas滚动滞后

时间:2017-10-28 18:08:50

标签: html5 canvas smooth-scrolling

我正在制作HTML5 canvas平台游戏。在玩家的位置更新后,每一帧都会更新玩家的视图(相机)。这会导致相机略微不平稳(如果您看相机轮廓的最左侧)。我不能让相机位置像那样波涛汹涌。

问题:我如何修理相机,以便用播放器更新它的位置,但它是否顺畅? (无缝移动,不波涛汹涌,不滞后)

//setting everything up.
var canvas = document.getElementById("canvas"),
	ctx = canvas.getContext("2d"),
	wrapper = document.getElementById("wrapper"),
	requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.mozRequestAnimationFrame,
	then = Date.now(),
	now,
	framesPerSecond = 30,
	counter = 1000/framesPerSecond,
	delta = 0,
	//for smooth movement.
	friction = 0.9,
	//to track key presses.
	keyDown = {};

var main = function(){
	now = Date.now();
	delta += now - then;
	then = now;

	if(delta >= counter){
		delta = 0;
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		tick();
		render();
	}

	requestAnimationFrame(main);
}

var player = {
	x:0,
	y:115,
	w:20,
	h:20,
	velX:0,
	speed:3,
	color:"maroon",
	camX:0,
	camY:0,
	camOffsetX:250,
	camOffsetY:125,

	tick:function(){
		this.velX *= friction
		this.x += 2*this.velX;

		//left arrow key.
		if(37 in keyDown){
			if(this.velX > -this.speed){
				this.velX--;
			}
		}

		//right arrow key.
		if(39 in keyDown){
			if(this.velX < this.speed){
				this.velX++;
			}
		}

		//update new camera position after the player's position got updated.
		this.updateCamera();
	},

	render:function(){
		ctx.fillStyle = this.color;
		ctx.fillRect(this.x, this.y, this.w, this.h);
	},

	updateCamera:function(){
		//sets the center of the camera view to the center of the player
		this.camX = this.x + this.w/2 - this.camOffsetX;
		this.camY = this.y + this.h/2 - this.camOffsetY;
		//scrolls canvas with the camera
		wrapper.scrollLeft = this.camX;
	}
};

var tick = function(){
	player.tick();
}

var render = function(){
	player.render();
  
  //arrow pointing to the problem
  ctx.fillText("<---", player.camX + 10, player.y);

	//camera bounderies
	ctx.strokeRect(player.x + player.w/2 - player.camOffsetX, player.y + player.h/2 - player.camOffsetY, 2*player.camOffsetX, 2*player.camOffsetY);
		
	//sets markers so you can tell your're scrolling.
	ctx.fillText("250 pixels", 250, 10);
	ctx.fillText("500 pixels", 500, 10);
	ctx.fillText("750 pixels", 750, 10);
	ctx.fillText("1000 pixels", 1000, 10);
	ctx.fillText("1250 pixels", 1250, 10);
	ctx.fillText("1500 pixels", 1500, 10);
	ctx.fillText("1750 pixels", 1750, 10);
}

//adds or removes keys from keyDown on keydown or keyup
document.addEventListener("keydown", function(e){
	keyDown[e.keyCode] = true;
});

document.addEventListener("keyup", function(e){
	delete keyDown[e.keyCode];
});

requestAnimationFrame(main);
#wrapper {
  width:250px;
  height:250px;
  overflow:hidden;
  border:1px solid navy;
}
<!-- div is so the canvas can scroll. -->
<div id="wrapper" style="width:500px; height:250px; border:1px solid navy; overflow:hidden;">
	<canvas id="canvas" width="2000" height="250"></canvas>
</div>

1 个答案:

答案 0 :(得分:0)

问题在于您使用画布的方式。您不应创建大于可在屏幕上显示的画布。如果你这样做,你只会过度使用渲染代码。

闪烁是由于您尝试将画布像素调整为像素的分数。如果将摄像机位置设置为x = 100.5像素,则显示器无法将显示像素物理移动1/2,因此最好插入画布像素以适合显示像素。结果是闪烁。

但是你不应该移动画布,而应该移动画布变换。这可确保边界矩形始终与显示像素对齐,即使滚动像素的分数也是如此。

我对您的代码进行了一些更改。在//adds or removes keys from keyDown on keydown or keyup function keyEvent(e) { keyDown[e.keyCode] = e.type === "keydown" } document.addEventListener("keydown", keyEvent); document.addEventListener("keyup", keyEvent); requestAnimationFrame(main); const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); const wrapper = document.getElementById("wrapper"); var then; const framesPerSecond = 30; var counter = 1000 / framesPerSecond; var delta = 0; var friction = 0.9; const keyDown = {}; function main(time) { if (then === undefined) { then = time } delta += time - then; then = time; if (delta >= counter) { delta = 0; ctx.setTransform(1, 0, 0, 1, 0, 0); // set default transform ctx.clearRect(0, 0, canvas.width, canvas.height); player.update(); // set the view to the camera ctx.setTransform(1, 0, 0, 1, -player.camX, -player.camY); render(); } requestAnimationFrame(main); } var player = { x: 0, y: 115, w: 20, h: 20, velX: 0, speed: 3, color: "maroon", camX: 0, camY: 0, camOffsetX: 250, camOffsetY: 125, update() { this.velX *= friction this.x += 2 * this.velX; if (keyDown["37"]) { if (this.velX > -this.speed) { this.velX-- } } if (keyDown["39"]) { if (this.velX < this.speed) { this.velX++ } } this.updateCamera(); }, render() { ctx.fillStyle = this.color; ctx.fillRect(this.x, this.y, this.w, this.h); }, updateCamera() { this.camX = this.x + this.w / 2 - this.camOffsetX; this.camY = this.y + this.h / 2 - this.camOffsetY; } }; var render = function() { player.render(); //arrow pointing to the problem ctx.fillText("<---", player.camX + 10, player.y); ctx.fillText("Player X pos : " + player.camX.toFixed(3), player.x, 100); //camera bounderies ctx.strokeRect(player.x + player.w / 2 - player.camOffsetX, player.y + player.h / 2 - player.camOffsetY, 2 * player.camOffsetX, 2 * player.camOffsetY); //sets markers so you can tell your're scrolling. ctx.fillText("250 pixels", 250, 10); ctx.fillText("500 pixels", 500, 10); ctx.fillText("750 pixels", 750, 10); ctx.fillText("1000 pixels", 1000, 10); ctx.fillText("1250 pixels", 1250, 10); ctx.fillText("1500 pixels", 1500, 10); ctx.fillText("1750 pixels", 1750, 10); }函数内部,我更改了画布变换以跟随相机,而不是在DOM中移动画布。

#wrapper {
  width: 500px;
  height: 250px;
  overflow: hidden;
  border: 1px solid cyan;
}
<!-- div is so the canvas can scroll. -->
<div id="wrapper">
  <canvas id="canvas" width="500" height="250"></canvas>
</div>
{{1}}