drstuggels
drstuggels

Reputation: 132

Why does the red blocks skip a block in p5.js?

Ok so the red blocks dangers[] should fall down smoothly down the canvas, but they skip and act weirdly. Does it have anything to do with the for loop that show(); them?

Here's the code:

var dangers = [];

function setup() {
	createCanvas(1060, 480);
	createDanger();
}
var x = 0;

function createDanger() {
	var randomWidth = (floor(random(980)) * 80) % 980;
	dangers[x] = new Danger(randomWidth, -80);
	dangers.forEach(function(obj) {
		setInterval(function() {
			obj.fall();
		}, 1000);
	});
	x++;
	console.log(dangers);
}

function draw() {
	background(0);


	for (danger of dangers) {
		danger.show();
	}


}

setInterval(createDanger, 3000)



//Danger


function Danger (x, y) {
	this.x = x;
	this.y = y;
	var size = 80;
	this.fall = function () {
		this.y += size;
	}
	this.update = function () {
	}
	this.show = function () {
		fill(255,0,0);
		noStroke();
		rect(this.x, this.y, size, size);
		
		
		
	}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script>
<meta charset="utf-8" />

And if you have any other suggestions to my code, feel free to help. Thanks.

Upvotes: 0

Views: 103

Answers (1)

Wyck
Wyck

Reputation: 11730

Here's an example of smoother performance.

var dangers = [];

function setup() {
	background(0);
	createCanvas(1060, 480);
	createDanger();
}

function createDanger() {
	var randomWidth = (floor(random(980)) * 80) % 980;
	dangers.push(new Danger(randomWidth, -80));
}

var lastRenderTime;

function update() {
  var now = Date.now();
  if (lastRenderTime) {
    var elapsed = (now - lastRenderTime) / 1000;
    dangers.forEach(function(obj) {
			obj.fall(elapsed);
		});  
  }
  
  dangers = dangers.filter(d => d.y < 400);
  
  lastRenderTime = now;
}

function draw() {
  update();
  
  background(0);
	for (danger of dangers) {
		danger.show();
	}
}

setInterval(function () {
   createDanger();
}, 500)


//Danger


function Danger (x, y) {
	this.x = x;
	this.y = y;
  this.speed = 40 + random(50); // pixels per second
	var size = 80;
	this.fall = function (time) {
		this.y += this.speed * time;
	}
	this.update = function () {
	}
	this.show = function () {
		fill(255,0,0);
		noStroke();
		rect(this.x, this.y, size, size);
		
		
		
	}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script>
<meta charset="utf-8" />

This is close to the original, except that I did a couple of things differently:

  1. I got rid of the idea of setting an update function for each object when you create a new one. That just doesn't make sense.
  2. I updated the position of each object on every frame. I did this by adding an update function that is called from the draw function. That guarantees that the animation is up to date before each frame is rendered.
  3. I used an absolute real-time clock to adjust the amount of time that passes per frame. I keep track of this with a lastRenderTime variable and subtract now minus lastRenderTime to compute the elapsed time. The elapsed time is passed through to the update function as a parameter.
  4. I used a more physics-based approach to updating the position of the object. I defined the speed of each object in pixels per second. The position is updated, not by a constant amount each frame, but instead by a variable amount, according to the actual amount of time that has elapsed since the last frame of animation. This ensures that the object moves consistently in real-time regardless of the performance of the machine rendering it. So this.y += size becomes this.y += this.speed * time.
  5. I changed the array access to use push which is a more language-agnostic description of the operation you are trying to perform rather than relying on JavaScript's quirky "extend the length of the array when you write off the end of it" behaviour.
  6. I added a filter function to remove expired objects after they hit the bottom of the window to ensure the array doesn't grow without bound and consume resources over time.
  7. I increased the frequency with which the objects are created from once every 3000 milliseconds to once every 500 milliseconds. Perhaps only because I'm a little impatient. :)
  8. I also decided to choose a random speed for each object, just for a little visual variety and to make it clear that each object has its own speed.

Upvotes: 1

Related Questions