Reputation: 3568
So I'm still writing a bouncing box demo using the HTML Canvas and Javascript. So far, the logic is working as expected (good news!) - however, when there's a large amount of movement on the canvas, things start becoming... pixelated. Here's a fiddle to demonstrate what I mean https://jsfiddle.net/hL8epzk3/2/
The number of boxes is currently at 50 (where the problem is evident). Lower the number to 20 and all looks fine!
(Line 67 in the fiddle, var boxes = 20)
In case this is relevant, tested in Google Chrome
My Code
<!-- GAME WINDOW -->
<canvas id="canvas" width="800" height="600"></canvas>
<div id="menu">
<button onclick="addBox();">Add Box</button>
</div>
Javascript
var Box = function(dimensions, color, x, y){
this.width = dimensions;
this.height = dimensions;
this.x = x;
this.y = y;
this.velocityX = 10;
this.velocityY = 10;
this.color = color;
this.context = document.getElementById('canvas').getContext('2d');
this.possibleColors = ['#1abc9c', '#2ecc71', '#3498db', '#9b59b6', '#34495e', '#e67e22', '#c0392b', '#7f8c8d'];
var that = this;
this.update = function(){
this.x += this.velocityX;
this.y += this.velocityY;
this.collisionCheck();
};
this.render = function(){
this.context.fillStyle = this.color;
this.context.fillRect(this.x, this.y, this.width, this.height);
};
this.collisionCheck = function(){
if(this.y > 600 - this.height || this.y < 0){
this.velocityY *= -1;
this.generateColor();
}
if(this.x > 800 - this.width || this.x < 0){
this.velocityX *= -1;
this.generateColor();
}
};
this.generateColor = function(){
this.color = this.possibleColors[Math.floor((Math.random() * 10) - 1)];
};
function addBox(){
console.log('box added');
}
window.renderLayer.addObject(this);
};
var RenderLayer = function(){
this.objects = [];
this.addObject = function(obj){
this.objects[this.objects.length] = obj;
console.log(this.objects[this.objects.length - 1]);
};
this.updateObjects = function(){
for(var x = 0; x < this.objects.length; x++)
this.objects[x].update();
};
this.renderObjects = function(){
for(var x = 0; x < this.objects.length; x++)
this.objects[x].render();
};
};
function init(){
window.renderLayer = new RenderLayer();
window.box = [];
var boxes = 20;
for(var x = 0; x < boxes; x++){
window.box[x] = new Box(50, 'red', Math.floor((Math.random() * 750) + 1), Math.floor((Math.random() * 550) + 1));
}
requestAnimationFrame(update);
}
function update() {
document.getElementById('canvas').width = document.getElementById('canvas').width;
window.renderLayer.updateObjects();
requestAnimationFrame(update);
requestAnimationFrame(render);
}
function render() {
window.renderLayer.renderObjects();
}
function addBox(){
window.box[window.box.length] = new Box(50, 'red', Math.floor((Math.random() * 750) + 1), Math.floor((Math.random() * 550) + 1));
}
Does this happen for performance reasons? Is there any way to prevent it? It seems to happen when the boxes overlap, but it's hard to tell when there's that many boxes.
Upvotes: 0
Views: 120
Reputation: 54026
There is no pixelation happening, you can see this if you add a pause button, or snap a copy of the canvas by copying it to another and viewing it. Or draw circles instead of boxes. The reason it looks pixelated is because of a strange effect due to you changing the colour of the boxes when they hit the walls. Not changing the colour reduces the optical illusion. Also your bouncing is off, the boxes are partly clipped each time they hit the walls, this also adds to the illusion.
Lastly you are in danger of causing the page to lock up and eventually throw a call stack overflow by the way you are calling requestAnimationFrame
twice on the one frame. All is good while the load is low, but as the load increases and the frame time goes over the 1/60th of a frame time, first you will start to get update and render happening on separate frames, and then requests will start to accumulate on the call stack, leading to even stranger behaviour and eventually throwing a call stack overflow.
Only call requestAnimationFrame
once per frame to avoid this problem.
Upvotes: 1