p5.js change object colour after X frames - p5.js

I would like to change the fill colour of an object over time. Is there a way to change the fill colour of an object after X frames?
I am learning about constructors, and I am thinking that in the code's updateParticle function, after this.age counts to 'X', the fill colour of the ellipse could change.
'''
function Particle(x, y, xSpeed, ySpeed, size, colour) {
this.x = x;
this.y = y;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.size = size;
this.colour = colour;
this.age = 0;
this.drawParticle = function() {
fill(this.colour);
noStroke();
ellipse(this.x, this.y, this.size);
}
this.updateParticle = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
this.age++;
}
}
function Emitter(x, y, xSpeed, ySpeed, size, colour) {
this.x = x;
this.y = y;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.size = size;
this.colour = colour;
this.particles = [];
this.startParticles = [];
this.lifetime = 0;
this.addParticle = function() {
var p = new Particle(random(this.x - 10, this.x + 10),
random(this.y - 10, this.y + 10),
random(this.xSpeed - 0.4, this.xSpeed + 0.4),
random(this.ySpeed - 5, this.ySpeed - 1),
random(this.size - 4, this.size + 40),
this.colour);
return p;
}
this.startEmitter = function(startParticles, lifetime) {
this.startParticles = startParticles;
this.lifetime = lifetime;
for (var i = 0; i < startParticles; i++) {
this.particles.push(this.addParticle());
}
}
this.updateParticles = function() {
var deadParticles = 0
for (var i = this.particles.length - 1; i >= 0; i--) {
this.particles[i].drawParticle();
this.particles[i].updateParticle();
if (this.particles[i].age > random(0, this.lifetime)) {
this.particles.splice(i, 1);
deadParticles++;
}
}
if (deadParticles > 0) {
for (var i = 0; i < deadParticles; i++) {
this.particles.push(this.addParticle());
}
}
}
}
var emit;
function setup() {
createCanvas(800, 600);
emit = new Emitter(width / 2, height - 100, 0, -1, 10, color(200, 0, 200, 50));
emit.startEmitter(600, 4000);
}
function draw() {
background(200);
emit.updateParticles();
}
'''

Well you could just:
if(frameCount % 30 == 0){ // % 30 is the remainder of num / 30, so 4 % 3 = 1, since 3 / 3 = 0 And 4 / 3 = 3.33
fill("lime") // these are just preset colors in p5.js AND css lime == rgb(0,255,0)
} else {
fill('darkred')
}
or you could also do it with for example a switch statement: using background for no reason
switch(MY_frameCount){
case 1:
background('blue')
break
case 2:
background("darkgreen")
break
case 376:
background(crimson)
// break
}
MY_frameCount ++
or:
if(Math.random() < 0.1){
fill(Math.random() * 255, Math.random() * 255, Math.random() * 255)
} // this should on average fill with random color every 10 frames

Related

different scenes with different animation won't play in p5

for school we need to make a sequence of animations in p5.
I wrote the code below, but it doesn't show any of my animations.
please help me...
let currentScene = 0;
let prevTime = 0;
let interval1 = 5000;
let interval2 = 8500;
let interval3 = 10000;
let interval4 = 11500;
let interval5 = 13000;
let interval6 = 15500;
let interval7 = 18000;
let interval8 = 20500;
let interval9 = 25000;
function setup() {
createCanvas(400, 400);
prevTime = millis();
}
function draw() {
if (millis() > prevTime + interval1) {
currentScene = 1;
}
if (millis() > prevTime + interval2) {
currentScene = 2;
}
if (millis() > prevTime + interval3) {
currentScene = 3;
}
if (millis() > prevTime + interval4) {
currentScene = 4;
}
if (millis() > prevTime + interval5) {
currentScene = 5;
}
if (millis() > prevTime + interval6) {
currentScene = 6;
}
if (millis() > prevTime + interval7) {
currentScene = 7;
}
if (millis() > prevTime + interval8) {
currentScene = 8;
}
if (millis() > prevTime + interval9) {
currentScene = 0;
prevTime = millis();
}
switch (currentScene) {
case 0:
Scene1();
break;
case 1:
Scene2();
break;
case 2:
Scene3();
break;
case 3:
Scene4();
break;
case 4:
Scene5();
break;
case 5:
Scene6();
break;
case 6:
Scene7();
break;
case 7:
Scene8();
break;
case 8:
Scene9();
break;
}
}
const Scene1 = () => {
const amount = 35;
let color = ["white", "black"];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(random(color));
strokeWeight(2);
frameRate(5);
fill("black");
textStyle(BOLD);
textSize(140);
textAlign(CENTER);
text("WAKE", 200, 130);
textSize(300);
text("UP", 200, 380);
const grid = width / amount;
for (let a = 0; a < amount; a++) {
for (let b = 0; b < amount; b++) {
kruis(a * grid, b * grid, grid);
}
}
}
const kruis = (x, y, h) => {
push();
translate(x, y, h);
fill("white");
textSize(random(10, 15));
text("Z", 5, 10);
pop();
};
};
const Scene2 = () => {
let t = 0;
const increment = 0.8;
maxEllipse = 100;
angle = 0;
scaleValue = 400;
snelheid = 10;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(0, 20);
const r = 255 * noise(t + 10);
const g = 255 * noise(t + 15);
const b = 255 * noise(t + 20);
for (let i = 0; i < maxEllipse; i++) {
push();
const y = sin(angle + i) * scaleValue;
const space = width / maxEllipse;
const x = (i + 0.5) * space;
stroke(r, g, b);
line(x, y, 400, 0);
pop();
}
angle += snelheid;
t += increment;
}
};
const Scene3 = () => {
let t = 0;
const increment = 0.8;
maxEllipse = 100;
angle = 0;
scaleValue = 400;
snelheid = 10;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(0, 20);
const r = 255 * noise(t + 10);
const g = 255 * noise(t + 15);
const b = 255 * noise(t + 20);
for (let i = 0; i < maxEllipse; i++) {
push();
const y = sin(angle + i) * scaleValue;
const space = width / maxEllipse;
const x = (i + 0.5) * space;
stroke(r, g, b);
line(x, y, 400, 400);
pop();
}
angle += snelheid;
t += increment;
}
};
Not all animations are in it yet (it should be 9 in total), but the scenes I've already placed in it don't do anything.
I've also tried to remove the draw and setup function in the scenes, in the first scene this works, but afterwards it only shows a static image.
This is a good start, make other scenes like this.
let currentScene = 0;
let prevTime = 0;
let interval1 = 5000;
let interval2 = 8500;
let interval3 = 10000;
let interval4 = 11500;
let interval5 = 13000;
let interval6 = 15500;
let interval7 = 18000;
let interval8 = 20500;
let interval9 = 25000;
function setup() {
createCanvas(400, 400);
prevTime = millis();
}
function draw() {
if (millis() > prevTime + interval1) {
currentScene = 1;
}
if (millis() > prevTime + interval2) {
currentScene = 2;
}
if (millis() > prevTime + interval3) {
currentScene = 3;
}
if (millis() > prevTime + interval4) {
currentScene = 4;
}
if (millis() > prevTime + interval5) {
currentScene = 5;
}
if (millis() > prevTime + interval6) {
currentScene = 6;
}
if (millis() > prevTime + interval7) {
currentScene = 7;
}
if (millis() > prevTime + interval8) {
currentScene = 8;
}
if (millis() > prevTime + interval9) {
currentScene = 0;
prevTime = millis();
}
switch (currentScene) {
case 0:
Scene1();
break;
case 1:
Scene2();
break;
case 2:
Scene3();
break;
case 3:
Scene4();
break;
case 4:
Scene5();
break;
case 5:
Scene6();
break;
case 6:
Scene7();
break;
case 7:
Scene8();
break;
case 8:
Scene9();
break;
}
}
function Scene1()
{
const amount = 35;
var color = ["white", "black"];
var kruis = (x, y, h) =>
{
push();
translate(x, y, h);
fill("white");
textSize(random(10, 15));
text("Z", 5, 10);
pop();
}
background(random(color));
strokeWeight(2);
frameRate(5);
fill("black");
textStyle(BOLD);
textSize(140);
textAlign(CENTER);
text("WAKE", 200, 130);
textSize(300);
text("UP", 200, 380);
const grid = width / amount;
for (let a = 0; a < amount; a++) {
for (let b = 0; b < amount; b++) {
kruis(a * grid, b * grid, grid);
}
}
}
function Scene2()
{
let t = 0;
const increment = 0.8;
maxEllipse = 100;
angle = 0;
scaleValue = 400;
snelheid = 10;
background(0, 20);
const r = 255 * noise(t + 10);
const g = 255 * noise(t + 15);
const b = 255 * noise(t + 20);
for (let i = 0; i < maxEllipse; i++)
{
push();
const y = sin(angle + i) * scaleValue;
const space = width / maxEllipse;
const x = (i + 0.5) * space;
stroke(r, g, b);
line(x, y, 400, 0);
pop();
}
angle += snelheid;
t += increment;
}
function Scene3()
{
let t = 0;
const increment = 0.8;
maxEllipse = 100;
angle = 0;
scaleValue = 400;
snelheid = 10;
background(0, 20);
const r = 255 * noise(t + 10);
const g = 255 * noise(t + 15);
const b = 255 * noise(t + 20);
for (let i = 0; i < maxEllipse; i++) {
push();
const y = sin(angle + i) * scaleValue;
const space = width / maxEllipse;
const x = (i + 0.5) * space;
stroke(r, g, b);
line(x, y, 400, 400);
pop();
}
angle += snelheid;
t += increment;
}

moving a sketch from draw to setup

Im playing around with the prime spiral code from Dan Shiffman:
https://www.youtube.com/watch?v=a35KWEjRvc0&t=716s&ab_channel=TheCodingTrain
I need to use this code as a background to another sketch, but due to the moving nature of the spiral its impossible that the spiral will not draw ontop of the other sketch, even with p5.layers.
I am therefore searching for a way to refactor this code into something that draw all the figures at once so use it as a background.
My idea is to create some kind of for loop in setup, but i am afraid its to big of nut to crack for me.
let x, y;
let step = 1;
let stepSize = 20;
let numSteps = 1;
let state = 0;
let turnCounter = 1;
let totalSteps;
let offset = 0;
function isPrime(value) {
if (value == 1) return false;
for (let i = 2; i <= sqrt(value); i++) {
if (value % i == 0) {
return false;
}
}
return true;
}
function setup() {
createCanvas(500, 500);
const cols = width / stepSize;
const rows = height / stepSize;
totalSteps = cols * rows;
x = width / 2;
y = height / 2;
background(0);
}
function draw() {
primeSpiral(20, 1)
primeSpiral(30, 200)
incrementStep();
noStroke();
}
function incrementStep()
{
switch (state) {
case 0:
x += stepSize;
break;
case 1:
y -= stepSize;
break;
case 2:
x -= stepSize;
break;
case 3:
y += stepSize;
break;
}
if (step % numSteps == 0) {
state = (state + 1) % 4;
turnCounter++;
if (turnCounter % 2 == 0) {
numSteps++;
}
}
step++;
if (step > totalSteps) {
noLoop();
}
}
function primeSpiral(offset, color){
if (!isPrime(step+offset)) {
//might put something here
} else {
let r = stepSize * 0.5;
fill(color, 99, 164);
push();
translate(x, y);
rotate(-PI / 4);
triangle(-r, +r, 0, -r, +r, +r);
pop();
}
}
You can move the code from draw() to the loop in setup(), here is example:
...
function setup() {
createCanvas(500, 500);
const cols = width / stepSize;
const rows = height / stepSize;
totalSteps = cols * rows;
x = width / 2;
y = height / 2;
background(0);
for (let i = 0; i<100; i++) { // 100 is the number of processed frames, you can change it as you need
primeSpiral(20, 1)
primeSpiral(30, 200)
incrementStep();
noStroke();
}
}
function draw() { // now draw is empty and you can place new code here
}
...

Is it possible to change particle color?

is it possible to change the particle color to any color in mind?
Because i only get one color and i want to change it to make it more suitable for spring is there a way to configure the colors based on your taste following is my functions code:
function Particle() {
this.pos = createVector(random(width), random(height));
this.vel = createVector(0, 0);
this.acc = createVector(0, 0);
this.maxspeed = 4;
this.h = 100;
this.prevPos = this.pos.copy();
this.update = function() {
this.vel.add(this.acc);
this.vel.limit(this.maxspeed);
this.pos.add(this.vel);
this.acc.mult(0);
}
this.follow = function(vectors) {
var x = floor(this.pos.x / scl);
var y = floor(this.pos.y / scl);
var index = x + y * cols;
var force = vectors[index];
this.applyForce(force);
}
this.applyForce = function(force) {
this.acc.add(force);
}
this.show = function() {
strokeWeight(6);
stroke(255, this.h, 10);
this.h = this.h + 1;
if (this.h > 255) {
this.h = 100;
}
strokeWeight(8);
line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
this.updatePrev();
}
this.updatePrev = function() {
this.prevPos.x = this.pos.x;
this.prevPos.y = this.pos.y;
}
this.edges = function() {
if (this.pos.x > width) {
this.pos.x = 0;
this.updatePrev();
}
if (this.pos.x < 0) {
this.pos.x = width;
this.updatePrev();
}
if (this.pos.y > height) {
this.pos.y = 0;
this.updatePrev();
}
if (this.pos.y < 0) {
this.pos.y = height;
this.updatePrev();
}
}
}
The call to stroke(255, this.h, 10) in the show function is what is determining the color of the line drawn by the Particle class in this case. It looks like it is cycling from red to yellow. The stroke function is well documented. You can certainly use it to make the line drawn in this example any color you want. You can learn more about color in p5js on p5js.org.

P5.js Creating a fading curve on a grid

I've made a square grid on top of the canvas and also a cruve (that is meant to have a fading trail). I made them seperately and tried combining them so the curve would appear on top of the grid. However, it doesn't show the curve.
I've commented out the grid so it's easier to see the curve.
How do I get this to work?
var cols = 10;
var rows = 10;
var t = 0;
var particleArray = [];
function setup() {
createCanvas(600, 600);
background(0);
fill(100);
rect(0, 0, 550, 550, 25);
}
// blue grid
function draw() {
/*for (var c = 0; c < cols; c++) {
for (var r = 0; r < rows; r++) {
var XO = 25 + c * 50;
var YO = 25 + r * 50;
stroke(0);
fill(100,149,237);
rect(XO, YO, 50, 50);
noLoop();
// :(
}
}
*/
//curve
y = width / 2 + 270 * sin(3 * t + PI / 2) - 25;
x = height / 2 + 270 * sin(1 * t) - 25;
particleArray.push(new Particle(x, y, t));
for (i=0; i<particleArray.length; i++) {
particleArray[i].show(t);
}
if (particleArray.length > 700) {
particleArray.shift();
}
t += .01;
}
function Particle(x, y, t) {
this.x = x;
this.y = y;
this.t = t;
this.show = function(currentT) {
var _ratio = t / currentT;
_alpha = map(_ratio, 0, 1, 0, 255); //points will fade out as time elaps
fill(255, 255, 255, _alpha);
ellipse(x, y, 5, 5);
}
}
I don't know if this was intentional but you called noLoop() function where you're drawing the grid. If you comment that out it works.

Setting background image in canvas animation

I need to set background image for this canvas animation without affecting the animation style.
This CodePen is shown below.
var c = document.getElementById('canv');
var $ = c.getContext('2d');
var w = c.width = window.innerWidth;
var h = c.height = window.innerHeight;
var grav = 0.00095;
var s = [20, 15, 10, 5];
var gravX = w / 2;
var gravY = h / 2;
var nodes;
var num = 55;
var minDist = 155;
var spr = 0.0000009;
part();
run();
//random size function
function S() {
var curr = s.length;
var cur_ = Math.floor(Math.random() * curr);
return s[cur_];
}
function part() {
nodes = [];
for (var i = 0; i < num; i++) {
var node = {
hue: Math.random()*360,
rad: S(),
x: Math.random() * w,
y: Math.random() * h,
vx: Math.random() * 8 - 4,
vy: Math.random() * 8 - 4,
upd: function() {
this.x += this.vx;
this.y += this.vy;
if (this.x > w) this.x = 0;
else if (this.x < 0) this.x = w;
if (this.y > h) this.y = 0;
else if (this.y < 0) this.y = h;
},
draw: function() {
//outer ring
var g = $.createRadialGradient(this.x, this.y, this.rad * 2, this.x, this.y, this.rad);
g.addColorStop(0,'hsla(242, 55%, 15%,.7)');
g.addColorStop(.5, 'hsla(242, 50%, 10%,.5)');
g.addColorStop(1,'hsla(242, 30%, 5%,.5)');
$.fillStyle = g;
$.beginPath();
$.arc(this.x, this.y, this.rad * 2, 0, Math.PI * 2, true);
$.fill();
$.closePath();
//inner particle
var g2 = $.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.rad);
g2.addColorStop(0, 'hsla('+this.hue+', 85%, 40%, 1)');
g2.addColorStop(.5, 'hsla('+this.hue+',95%, 50%,1)');
g2.addColorStop(1,'hsla(0,0%,0%,0)');
$.fillStyle = g2;
$.beginPath();
$.arc(this.x, this.y, this.rad, 0, Math.PI * 2, true);
$.fill();
$.closePath();
}
};
nodes.push(node);
}
}
function run() {
$.globalCompositeOperation = 'source-over';
$.fillStyle = 'hsla(242, 40%, 5%,.85)';
$.fillRect(0, 0, w, h);
$.globalCompositeOperation = 'lighter';
for (i = 0; i < num; i++) {
nodes[i].upd();
nodes[i].draw();
}
for (i = 0; i < num - 1; i++) {
var n1 = nodes[i];
for (var j = i + 1; j < num; j++) {
var n2 = nodes[j];
Spr(n1, n2);
}
Grav(n1);
}
window.requestAnimationFrame(run);
}
function Spr(na, nb) {
var dx = nb.x - na.x;
var dy = nb.y - na.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
$.lineWidth = 1;
$.beginPath();
$.strokeStyle = "hsla(217, 95%, 55%, .15)";
$.moveTo(na.x, na.y);
$.lineTo(nb.x, nb.y);
$.stroke();
$.closePath();
var ax = dx * spr;
var ay = dy * spr;
na.vx += ax;
na.vy += ay;
nb.vx -= ax;
nb.vy -= ay;
}
}
function Grav(n) {
n.vx += (gravX - n.x) * grav;
n.vy += (gravY - n.y) * grav;
};
window.addEventListener('resize', function() {
c.width = w = window.innerWidth;
c.height = h = window.innerHeight;
});
body{
width:100%;
margin:0;
overflow:hidden;
}
<canvas id='canv' ></canvas>
CSS
Just replace the beginning of the run() code to:
function run() {
...
//$.fillStyle = 'hsla(242, 40%, 5%,.85)';
$.clearRect(0, 0, w, h);
...
Then move the color settings to CSS together with an image reference:
#canv {
background: hsla(242, 40%, 5%, .85) url(path/to/image.jpg);
}
Add background-size to the CSS rule if needed. Note that since you're using different blending modes such as lighter which depends on existing content, you may not get desired result as it will blend with an empty canvas and not a solid - the approach below should solve that in this case.
CodePen
JavaScript
As before, replace the first lines in run() but after you made sure the image you want to use has loaded, simply draw it in:
function run() {
...
//$.fillStyle = 'hsla(242, 40%, 5%,.85)';
$.drawImage(img, 0, 0, w, h); // img must be loaded (use onload)
...
If your image contains transparency you also need to clear the canvas first:
function run() {
...
//$.fillStyle = 'hsla(242, 40%, 5%,.85)';
$.clearRect(0, 0, w, h);
$.drawImage(img, 0, 0, w, h); // img must be loaded (use onload)
...
CodePen

Resources