1

this is for a project in my p5.js class. I have a class that creates a 3D shape and i call it in my draw function in a for loop. In this for loop i create the shape and it has a rotation. If i press the the "a" button, it creates a new shape. My problem is, that i want to stop the rotation of the previous shape when i create a new shape, but i can't find a solution.

this is my code:

let BLACK;
let GRAY;
let LIGHTGRAY;
let WHITE;
let RED;
let forms = [];
let coorX, coorY, coorZ, colour;
let COL = [];
let ran;

function setup() {
  createCanvas(586, 810, WEBGL);
  BLACK = color(0);
  GRAY = color(70);
  LIGHTGRAY = color(180);
  WHITE = color(255);
  RED = color(217, 4, 33);
  COL = [BLACK, WHITE, GRAY, RED, RED\]
    ran = random(0.01, 0.1)
}

function draw() {
  background(80);
  pointLight(250, 250, 250, 250);
  for (let i = 0; i < forms.length; i++) {
    newSpeed = 0.05 + i * ran
      forms[i].create(newSpeed, 0.01);
    if (forms.length > 1) {
      rotateX(0);
    }
  }
  if (forms.length > 10) {
    //Array limited on 10 objects
    forms.splice(0, 1)
  }
}

function keyTyped() {
  if (key === 'a') {
    coorX = int(random(-100, 100))
      coorY = int(random(-100, 100))
      coorZ = int(random(-200, 200))
      forms.push(new Shape(coorX, coorY, coorZ));
  }
  if (key === 'd') {
    forms.pop()
  }
}

class Shape {
  constructor(posX, posY, posZ, colour) {
    this.x = 50; //width
    this.y = 50; //height
    this.z = 50; // depth
    this.x1 = 0;
    this.y1 = 500;
    this.z1 = 80;
    this.posX = posX;
    this.posY = posY;
    this.posZ = posZ;
    this.rand = int(random(0, 5));
    this.colour = colour;
  }
  create (speed, rotation) {
    //create a new shape
    stroke(0);
    strokeWeight(0);
    push();
    translate(this.posX, this.posY, this.posZ)
      //rotate the shape
      this.speed = speed;
    this.rotation = rotation;
    rotateX((frameCount * this.rotation) * speed)
      rotateY((frameCount * this.rotation) * speed)
      if (this.rand == 1) {
      fill(RED)
        box(50, 50, 50)
    }
    if (this.rand == 2) {
      fill(LIGHTGRAY);
      sphere(50, 10)
    }
    if (this.rand == 3) {
      fill(WHITE);
      cylinder(5, 280, 15)
    }
    if (this.rand == 4) {
      fill(GRAY);
      torus(90, 24, 3)
    }
    pop();
  }
}

I tried separating the rotation and the creation function, but then it rotated the whole canvas and not the shapes individually.

Kroepniek
  • 301
  • 1
  • 7
NoEl
  • 11
  • 1

2 Answers2

0

In fact, in p5.js approach is completely different, and You need to analyze this example: https://p5js.org/examples/simulate-multiple-particle-systems.html

But, to solve Your problem in 'object style':
1 - You need to memorize state of the object, in this case the frameCount of the last frame when the key a was pressed,
2 - draw all shapes with memorized lastActiveFrame and one just with recent frameCount.

let BLACK;
let GRAY;
let LIGHTGRAY;
let WHITE;
let RED;
let forms = [];
let coorX, coorY, coorZ, colour;
let COL = [];
let ran;

function setup() {
  createCanvas(586, 810, WEBGL);
  BLACK = color(0);
  GRAY = color(70);
  LIGHTGRAY = color(180);
  WHITE = color(255);
  RED = color(217,4,33);
  COL = [BLACK, WHITE, GRAY, RED, RED]
  ran = random(0.01,0.1)
  
  coorX = int(random(-100,100))
  coorY = int(random(-100,100))
  coorZ = int(random(-200,200))
  forms.push(new Shape(coorX, coorY, coorZ));
}

function draw() {
  background(80);
  pointLight(250, 250, 250, 250);
  
  for(let i = 0; i < forms.length-1; i++) {
    newSpeed = 0.05 + i * ran
    forms[i].show(newSpeed, 0.01);
  }
  
  forms[forms.length-1].rotate(2.5, 0.01);
  
  if (forms.length > 10){
    //Array limited on 10 objects
    forms.splice(0,1)
  }
}

function keyTyped() {
  if (key === 'a'){
    coorX = int(random(-100,100))
    coorY = int(random(-100,100))
    coorZ = int(random(-200,200))
    forms.push(new Shape(coorX, coorY, coorZ));
  }
  if (key === 'd'){
    forms.pop()
  }
}

class Shape {
  
  constructor(posX, posY, posZ, colour){
    this.posX = posX;
    this.posY = posY;
    this.posZ = posZ;
    this.rand = int(random(0,5));
    this.colour = colour;
    this.lastActiveFrame = frameCount;
  }
  
  rotate(speed, rotation){
    //create a new shape
    stroke(0);
    strokeWeight(0);  
    push();
    translate(this.posX, this.posY, this.posZ)
    //rotate the shape
    this.lastActiveFrame = frameCount;
    rotateX(frameCount * rotation * speed)
    rotateY(frameCount * rotation * speed)
    if (this.rand == 1){
      fill(RED)
      box(50,50,50)
    }if(this.rand == 2) {
      fill(LIGHTGRAY);
      sphere(50,10)
    }if(this.rand == 3){
      fill(WHITE);
      cylinder(5,280,15)
    }if(this.rand == 4){
      fill(GRAY);
      torus(90,24,3)
    }  
    pop();
  }
      
  show(speed, rotation){
    //create a new shape
    stroke(0);
    strokeWeight(0);  
    push();
    translate(this.posX, this.posY, this.posZ)
    //rotate the shape
    rotateX(this.lastActiveFrame * rotation * speed)
    rotateY(this.lastActiveFrame * rotation * speed)
    if (this.rand == 1){
      fill(RED)
      box(50,50,50)
    }if(this.rand == 2) {
      fill(LIGHTGRAY);
      sphere(50,10)
    }if(this.rand == 3){
      fill(WHITE);
      cylinder(5,280,15)
    }if(this.rand == 4){
      fill(GRAY);
      torus(90,24,3)
    }  
    pop();
  }
}
Mruk
  • 171
  • 1
  • 11
  • Thank you very much, it works now. Now i just have to understand the code haha but I will look right into it! – NoEl Feb 02 '23 at 13:22
  • Active Shape have continously updated rotation: this.lastActiveFrame = frameCount; Other Shapes not. That's all of fix. – Mruk Feb 03 '23 at 15:24
0

In the console, p5.js says that the 4th argument of pointLight() must be a Vector. That argument is used to tell in which direction the light will point, as for the arguments 1 - 3, they tell where is the pointLight.

Vector reference

pointLight reference

nanto
  • 1
  • 4