Looking for a way to display particles as random .png images

Hello, I started a project with an ecosystem type code, now i’m trying to display some particles (Particle1 class) as random .png images, everytime a new particle 1 appear i want that it display as a different .png image. Right now what i have is all the particle 1 that appear show all the random images one after the other

Does anyone have an idea to help?

Here’s my code, sorry it’s a little messy, excuse my english too

ecosystem tab:


     ArrayList<Particle1> particles1 = new ArrayList<Particle1>();
     int numberOfParticles1 = 0;
     int rate = 60;
     int deathTime = 60;




    // total number of images
    int numImages = 16;
    int randomNumber;

    
    // an array of images
    PImage[] cells = new PImage[numImages];



    void setup() {
    size(1024, 600);
 
     particles1.add(new Particle1(random(width), random(height) ));
 
    
    
      // initialize images array (loading each one)
      for(int i = 0 ; i < numImages; i++){
        
        cells[i] = loadImage("particule"+(i)+".png");
        }
     }
     void draw() {
     background(255);
     randomNumber = (int)random(numImages);

                                                                      //for each particle1
     for (int i = 0; i < particles1.size(); i++) {

    Particle1 p = particles1.get(i);     //ajouter particule1 
    p.update();
    p.display();  
    } 
     }

particle 1 class tab :



     class Particle1 extends LivingThing {
     int diameter = 12;


     void display() {
     image(cells[randomNumber],x,y,diameter,diameter);
  
     }

    void update() {
    //movement

    x += random(-1, 1);
    y += random(-1, 1);
    

    


    // borders canvas
    if (x - diameter < 0) {
      x++;
    } else if (x + diameter > width) {
      x--;
    }
    if (y - diameter < 0) {
      y++;
    } else if (y + diameter > height) {
      y--;
    }

    //reproduction
    if(numberOfParticles1 < 100) {
    offspring += 0.01;
    if (offspring > 1) {
      offspring = 0;
     particles1.add(new Particle1(x + random(-0.8, 0.8), y + random(-0.8, 0.8)));
   
    }  
    }
    }

     Particle1(float x, float y) {
    super(x, y);
    numberOfParticles1++;
    
    }
  
  
  
    }

Hi @chxtaigne,

Welcome to the processing forum. Would you please read the following to format your code…

FAQ - Processing Foundation 1

This makes it easier for us to help you.

Cheers
— mnse

A well known design pattern that might help is dependency injection. It sounds scary, but it’s actually quite easy. You’re already doing it when you create your first Particle instance.

new Particle1(random(width), random(height)

Inside the Particle’s constrcutor you pass x and y to the superclass LivingThing which, I guess, initialize the x and y fields that you declared there.

Another example of dependency injection is by doing it directly:

ArrayList<Student> students = new ArrayList<>();

void setup() {
  students.add(new Student("Paul", "FGDO793DJ", 1996));
  students.add(new Student("Rose", "ORP8884RT", 2000));
  students.add(new Student("John", "BKJ1254PL", 1998));
  for (int i = 0; i < students.size(); i++) {
    Student student = students.get(i);
    student.printInfo();
  }
  exit();
}

class Student {

  String name;
  String id;
  int birthyear;

  Student(String name, String id, int birthyear) {
    this.name = name;
    this.id = id;
    this.birthyear = birthyear;
  }
  
  void printInfo() {
    println(name + ": " + id);
    println("born in " + birthyear);
  }
}

As you can see, dependency injection is passing an instance its data at creation time. A great thing about this is that after creating the instance, it’s good to go. You don’t have to worry about errors or bugs sneaking in due to uninitialized data.

Now compare this design pattern to your situation. Is it possible to solve your issue using dependency injection?

1 Like

Thanks for answer

I’m not sure how to do that in my case, should i make a class with cells or with numImages ?

With object orientated programming languages such as Processing, try to think in term of objects. This can be hard to wrap your head around at first, but once you do it becomes much easier to logically organize your code.

Each object that you create should be an entity of its own and —within itself— contain everything it needs to function properly. In my earlier code example it wouldn’t make sense to place String name outside the Student class, because the name of the student simply belongs to the student.

So ask yourself: What belongs to a particle within your ecosystem app? From your code I can deduct that each Particle instance has its own x and y location on the screen and its own diameter, but what else? Does it have movement speed?
And what does the .png image represent, is it its body? If so, I’d make this part of the Particle class in the same way that String name is part of my Student class.

Does that make sense?

1 Like

If I understand well, things related to particule 1 should be inside the Particle1 class? I tried different changes, one result was each particles display as all the images randomly one after the others, but all particles haves a different random orders of showing the .png images
do you think you could explain it again or give more clue? I’m having hard time comparing your example (student → name, id, birthdate), with mine (particle → position x, y, diameter, .png image)

Yes exactly, that way you keep things that belong together in one place. It’s convenient.

Of course! But before I do, I have to ask: is there a particular reason you keep referring to your Particle class as Particle1? Is there a Particle2 class that’s fundamentally different from the first one?

1 Like

Yes there is a particle2 class as well as predator1, 2 (particle1 gonna be eat by predator1, particle2 by predator2…) but to keep things clear here i didn’t share all the tabs and i erase the parts related to particle2, predator 1, 2 in the ecosystem tab since what i’m looking for is that the particles1 looks like differents images but still have the same behaviour

Alright, I think I understand where your confusion is coming from. Am I right to assume that you’re not entirely clear yet on the difference between a class and an object?

Imagine that a class is like a cooking recipe for an apple pie. I can follow the recipe multiple times and bake 10 pies, which are all similar to each other. They taste similar, smell similar, and look similar. Perhaps I baked the first one a bit too long and added too much sugar to the 5th pie, but overall they’re the same type of object: an apple pie.
What’s crucial to understand is that the recipe (the class) is not the same as the pie (an object of that class). Those objects are what we call instances. In this case each pie would be an instance of the ApplePie class.

If Particle1 and Particle2 have the same behavior and the same types of data (where the only difference is that they use different values for those data types), there is no need to write separate classes. They can both be created from the same Particle class. You can use that to create as many particles as you’d like with different values.

ArrayList<Particle> particles = new ArrayList<>();

void setup() {
  size(800, 400);  
  // create 50 particle instances
  for (int i = 0; i < 50; i++) {
    float x = random(width);
    float y = random(height);
    PVector movement = new PVector(random(-1, 1), random(-1, 1));
    Particle particle = new Particle(x, y, movement);
    particles.add(particle);
  }
}

void draw() {
  background(250);
  stroke(#FF0000);
  strokeWeight(3);
  // each frame loop over all particles and call the method
  // update() on each instance
  for (int i = 0; i < particles.size(); i++) {
    Particle particle = particles.get(i);
    particle.update();
  } 
}

class Particle {

  float x, y;
  PVector movement;
  
  Particle(float x, float y, PVector movement) {
    this.x = x;
    this.y = y;
    this.movement = movement;
  }
  
  // draws the particle and then updates its x & y value
  void update() {    
    point(x, y);
    x += movement.x;
    y += movement.y;    
  }
}

For each instance that you create, Processing creates a separate float x, float y, and a PVector movement that belongs to that instance. When you change the x value of the last particle, you only change the value for that specific instance. All the other 49 will remain unchanged by that change.

Does this explanation help?

1 Like

Ok I understand that, then is there a way to make every instances from the particle class look different, each one assign to a different image?

Great!

Yes, in the same way you pass the x and y to the Particle’s constructor, you could pass a PImage. This would mean that the randomization process for picking the image takes place outside the class.

1 Like

Ok i tried with your sketch doing this :

ArrayList<Particle> particles = new ArrayList();

  int numImages = 16;
  int randomNumber;
  int diameter = 16;

  PImage[] cells = new PImage[numImages];


void setup() {
 
  size(800, 400);  
  // create 50 particle instances
  for (int i = 0; i < 50; i++) {
    float x = random(width);
    float y = random(height);
    PVector movement = new PVector(random(-1, 1), random(-1, 1));
    Particle particle = new Particle(x, y, movement);
    particles.add(particle);
   }
  // initialize images array (loading each one)
  for(int i = 0 ; i < numImages; i++){
  // TODO correct path to images
  cells[i] = loadImage("particule"+(i)+".png");}
  randomNumber = (int)random(numImages);
  }


void draw() {
  background(250);
  stroke(#FF0000);
  
  strokeWeight(3);
  // each frame loop over all particles and call the method
  // update() on each instance
  for (int i = 0; i < particles.size(); i++) {
    Particle particle = particles.get(i);
    particle.update();
  }
}

class Particle {
  
  float x, y;
  PVector movement;

  Particle(float x, float y, PVector movement) {
    this.x = x;
    this.y = y;
    this.movement = movement;
      randomNumber = (int)random(numImages);
  }

  // draws the particle and then updates its x & y value
  void update() {
    image(cells[randomNumber],x,y,diameter,diameter);
    point(x, y);
    x += movement.x;
    y += movement.y;    
  }
}

what i have is all instance of particle have the same image, the image change randomly every time i reload the sketch. Can you tell me what’s wrong? thanks for help

Each time draw() executes (which is roughly 30 times per second) you loop over all the particles. Each particle calls its own update() method and mostly uses their own data for displaying itself.

I say mostly, because cells[] and randomNumber aren’t part of the instance. So this line is causing unexpected behavior for you:

image(cells[randomNumber],x,y,diameter,diameter);

The way I see it, the image that you’re displaying should belong to the instance. It shouldn’t change all the time, right? So in the same way that you pass the starting x and y values to the constructor, do the same for the image:

class Particle {
  
  float x, y;
  PImage img; // 1. declare that each particle should have its own image
  PVector movement;

  Particle(float x, float y, PImage img, PVector movement) {
    this.x = x;
    this.y = y;
    this.img = img; // 2. initialize the image through injection
    this.movement = movement;

   // does not belong to the instance, because it's not declared in the class
    randomNumber = (int)random(numImages); 
  }
  
  // ... rest of the code
}

Then in update() you can show the instance’s own PImage instead of an image from cells[].

ok thank you, now i did this and it works, does the code seems right to you? i’m gonna try to apply to my ecosystem sketch now

ArrayList<Particle> particles = new ArrayList();

  int numImages = 16;
  int randomNumber;
  int diameter = 16;

  PImage[] cells = new PImage[numImages];


void setup() {
 
  size(800, 400);  
  for(int i = 0 ; i < numImages; i++){
   cells[i] = loadImage("particule"+(i)+".png");}
  
  // create 50 particle instances
  for (int i = 0; i < 50; i++) {
    float x = random(width);
    float y = random(height);

    randomNumber = (int)random(numImages);
    
    PImage img = cells[randomNumber];
    //PImage img = new PImage (random("particule0.png","particule1.png","particule2.png"));
    PVector movement = new PVector(random(-1, 1), random(-1, 1));
    Particle particle = new Particle(x, y, img, movement);
    particles.add(particle);
   }
  }


void draw() {
  background(250);
  stroke(#FF0000);
  
  strokeWeight(3);
  // each frame loop over all particles and call the method
  // update() on each instance
  for (int i = 0; i < particles.size(); i++) {
    Particle particle = particles.get(i);
    particle.update();
  }
}

class Particle {
  
  float x, y;
  PImage img;
  PVector movement;

  Particle(float x, float y,PImage img, PVector movement) {
    this.x = x;
    this.y = y;
    this.img = img;  
    this.movement = movement;
  }

  // draws the particle and then updates its x & y value
  void update() {
    image(img,x,y,diameter,diameter);
    point(x, y);
    x += movement.x;
    y += movement.y;    
  }
}

The code seems like a good basis to extend from. Good luck with your ecosystem!