2017-10-28 3 views
0

Ich mache ein HTML5 Leinwand Platformer Spiel. Die Ansicht des Spielers (die Kamera) wird jedes Bild aktualisiert, nachdem die Position des Spielers aktualisiert wurde. Dies führt dazu, dass die Kamera etwas ruckelt (wenn Sie auf die äußerste linke Seite des Kameraumrisses schauen). Ich kann nicht die Kamera-Position so abgehackt haben.HTML5 Canvas scroll lag

Frage: Wie kann ich die Kamera reparieren, damit ihre Position mit dem Spieler aktualisiert wird, aber so ist es glatt? (Seamless bewegend, nicht abgehackt, nicht laggy)

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

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

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

 
\t requestAnimationFrame(main); 
 
} 
 

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

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

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

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

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

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

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

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

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

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

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

 
document.addEventListener("keyup", function(e){ 
 
\t 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;"> 
 
\t <canvas id="canvas" width="2000" height="250"></canvas> 
 
</div>

Antwort

0

Das Problem ist in der Art und Weise Sie die Leinwand verwenden. Sie sollten keine Leinwand erstellen, die größer ist als auf dem Bildschirm angezeigt werden kann. Sie überarbeiten nur Ihren Rendering-Code, wenn Sie dies tun.

Das Flackern liegt daran, dass Sie versuchen, die Leinwandpixel auf Bruchteile eines Pixels anzupassen. Wenn Sie die Kameraposition auf x = 100,5 Pixel setzen, kann die Anzeige die Pixel des Displays nicht physisch um 1/2 verschieben, so dass die Leinwandpixel am besten interpoliert werden, um sie an die Anzeigepixel anzupassen. Das Ergebnis ist ein Flackern.

Aber Sie sollten die Leinwand nicht verschieben, sondern Sie sollten die Leinwand transformieren. Dies stellt sicher, dass das Begrenzungsrechteck immer mit den Anzeigepixeln ausgerichtet ist, auch wenn Sie Bruchteile eines Pixels scrollen.

Ich habe einige Änderungen an Ihrem Code vorgenommen. Innerhalb der main Funktion habe ich die Canvas-Transformation geändert, um der Kamera zu folgen, anstatt die Leinwand im DOM zu verschieben.

//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); 
 
}
#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>

+0

Awesome! Kurz gesagt, der Code funktioniert. Ich frage mich, ob Sie ein wenig mehr erklären können, warum es mit 'player.camX' und' -player.camY' funktioniert. Können Sie Ihre Antwort bearbeiten, um das zu erklären? –

+0

@ Jordan, denn wenn Sie die Leinwand bewegen, wie Sie es taten, bewegten Sie sie Bruchteile eines Pixels, dies stimmt nicht mit der Ausrichtung der Anzeigepixel überein. Wenn Sie die Transformation verschieben, verschieben Sie den Ursprung, um ihn mit dem oberen linken Leinwandpixel auszurichten. Dadurch wird sichergestellt, dass die Ansicht immer mit den Anzeigepixeln ausgerichtet ist. – Blindman67