sabot Posted June 14, 2017 Share Posted June 14, 2017 Hi all, I want to put together a little snake game to teach myself PixiJs. What I'm trying to achieve is a smooth gliding effect when moving this block around. (press left/right to start moving). Unfortunately, I simply cannot get rid of the occasional 'stuttering' when rendering - so I'm starting to think I might be going about it the wrong way. Could somebody tell me what I'm doing wrong here? see: fiddle const graphics = new PIXI.Graphics(); const app = new PIXI.Application(); const movementSpeed = 150; const stage = app.stage; const blocks = []; stage.addChild(graphics); class Block { constructor(position=[0, 0], direction=[0, 0]) { this.width = 20; this.position = position; this.prevPosition = position; this.direction = direction; } render (alpha = 0) { let offsetX = (this.position[0] * alpha) + (this.prevPosition[0] * (1 - alpha)); let offsetY = (this.position[1] * alpha) + (this.prevPosition[1] * (1 - alpha)); graphics.drawRect(offsetX, offsetY, this.width, this.width); } update (delta = 0) { this.prevPosition = this.position; this.position = this.calculateNewPosition(delta); } calculateNewPosition (delta) { let movementOffset = movementSpeed * (delta / 1000); return [ this.position[0] + (movementOffset * this.direction[0]), this.position[1] + (movementOffset * this.direction[1]) ]; } }; function render (delta) { graphics.clear(); graphics.beginFill(0xFF0000); blocks.forEach((block) => block.render(delta)); graphics.endFill(); }; function update (delta) { blocks.forEach((block) => block.update(delta)); }; function changeDirection (direction) { blocks.forEach((block) => { block.direction = direction }); } const fps = 30; // Frames per second const frameDuration = 1000 / fps; // Maximum time per frame. const maxFrameDelta = 1000; // Upper limit on how long the frame takes to render. let previousTimestamp = 0; // Last timestamp. let accumulator = 0; // Remainder of time that we could not simulate in our fixed-step physics. (used to smooth out temporal aliasing) function gameLoop(timestamp = 0) { requestAnimationFrame(gameLoop); //Calculate the time that has elapsed since the last frame let frameDelta = timestamp - previousTimestamp; //Optionally correct any unexpected huge gaps in the elapsed time if (frameDelta > maxFrameDelta) elapsed = maxFrameDelta; //Add the elapsed time to the accumulator accumulator += frameDelta; //Update the physics simulation in discrete chunks, and keep whatever remainder is left in the accumulator. while (accumulator >= frameDuration) { //Update the physics simulation update(frameDuration); accumulator -= frameDuration; } // After performing the physics steps, we might have some remaining time in the accumulator. // This causes 'stuttering' (temporal aliasing), so we interpolate where the block should be rendered. // That is: we don't draw the block exactly where the physics simulation has placed it, but where it should be to get the smoothest animation. // (Thank you Glenn Fiedler!) let renderOffset = accumulator / frameDuration; render(renderOffset); previousTimestamp = timestamp; } function initStage() { document.body.appendChild(app.view); blocks.push(new Block()); // Keyboard input. document.addEventListener('keydown', function(event) { if(event.keyCode == 37) { changeDirection([-1, 0]); } else if(event.keyCode == 39) { changeDirection([1, 0]); } }); gameLoop(); }; document.addEventListener("DOMContentLoaded", initStage); Quote Link to comment Share on other sites More sharing options...
Fritzy Posted June 16, 2017 Share Posted June 16, 2017 This seems way more complicated than it needs to be. A simple delta (although max delta is nice) should be enough. I would also recommend just drawing the block once, and then moving the position of the graphics object around. Quote Link to comment Share on other sites More sharing options...
sabot Posted June 16, 2017 Author Share Posted June 16, 2017 6 hours ago, Fritzy said: This seems way more complicated than it needs to be. A simple delta (although max delta is nice) should be enough. I would also recommend just drawing the block once, and then moving the position of the graphics object around. Thanks for the tip, I did notice that actually drawing to the graphics object seems to be done only during initialization in most examples. I was afraid that this might lead to me making a graphics object for every single segment of the snake, which seems to be something to avoid. Can you tell me if this example stutters on your machine? I'm on a ubuntu laptop, so I was thinking maybe it's related. (it's not too bad actually, but it does irritate me) As for the complexity of the timestep - I was following along with the famous 'fix your timestep' blogpost by Glenn Fiedler, but it's indeed a little complicated for something this simple Quote Link to comment Share on other sites More sharing options...
tywang2006 Posted June 16, 2017 Share Posted June 16, 2017 it is over complicated, you can use ticker in the update callback, it will pass delta time for you. it will be extremely simple to implement into any transform or animation. Quote Link to comment Share on other sites More sharing options...
Merlot Posted December 26, 2022 Share Posted December 26, 2022 Having a timestep is useful for aligning clients with server on a multiplayer game. I wish somebody would actually answer his question. I'm facing the same issues right now. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.