Add an ArrayList to another ArrayList


#1

Hi, i have 2 almost identical classes of objects (the color change) they have the same action : a random position without overlapping. Its work, but now i wonder how do i manage to place every objects with a random position without overlapping with the other classe.

so here is my world (where everything is lanch):

public class World2 {
	PApplet parent;
	
	public int worldW = 2000;
	public int worldH = 2000;
	
	Player player;
	
	Prairie prairie;
	
	ArrayList<Grass> grass;
	
	ArrayList<Champi> champi;
	
	public World2(PApplet p){
		parent = p;
		
		//////player//////
		float px = worldW/2;
		float py = worldH/2;
		
		PVector playerVector = new PVector(px,py); 
		player = new Player(parent,playerVector);
		//////////////////
		
		/////prairie///////
		prairie = new Prairie(parent);
		///////////////////
		
		
		/////grass/////////
		int nombGrass = 1;
		grass = new ArrayList<Grass>();
		for(int i = 0; i < nombGrass; i++){
			PVector l = new PVector(p.random(worldW-1750 , worldW-250), p.random(worldH-1750 , worldH-250));
			grass.add(new Grass(p, l));
		}
		///////////////////
		
		//////champi///////
		int nombChampi = 1;
		champi = new ArrayList<Champi>();
		for(int i = 0; i < nombChampi; i++){
			PVector l = new PVector(p.random(worldW-1750 , worldW-250), p.random(worldH-1750 , worldH-250));
			champi.add(new Champi(p,l));
		}
		///////////////////
		
	}
	
	public void run(){
		
		parent.background(0); ///fond noir = le néant
		
		////// attention il faut pop les créature sur base du monde et non de l'écran !!!! 
		////// mtn il faut mettre dans le push les objets, ou il vont suivrent la camera
		
		parent.pushMatrix();
		
		
		//////fct pas correctement, a refaire avec une "camera"
		parent.translate(-player.position.x+worldW-parent.width-200, -player.position.y+worldH-parent.height-650);
		
		
		//////le fond blanc//////
		parent.fill(255); ///le monde en lui meme
		parent.rect(0, 0, worldW, worldH);
		/////////////////////////
		
		//////prairie////////////
		prairie.run(parent);
		/////////////////////////
		
		/////grass///////////////
		Iterator<Grass> G = grass.iterator();
		while(G.hasNext()){
			Grass g = G.next();
			g.display(parent);
			g.grow();
		}
		/////////////////////////
		
		//////champi/////////////
		Iterator<Champi> C = champi.iterator();
		while(C.hasNext()){
			Champi c = C.next();
			c.display(parent);
			c.grow();
		}
		/////////////////////////
		
		
		parent.popMatrix();
		
		player.PlayerMvt(parent);
		player.run(parent);
		
		parent.fill(255,0,0);
		parent.text("player x " + player.position.x + " " + "player y " + player.position.y, 10, 10);
		
		
	}
}

my first class:

public class Grass {
	PApplet parent;
	ArrayList<PVector> grass;
	public PVector position;
	
	int r ;
	
	@SuppressWarnings("deprecation")
	public Grass(PApplet p,PVector l){
		position = l.get();
		parent = p;
		r = 32;
		grass = new ArrayList<PVector>();
	}
	
	@SuppressWarnings("deprecation")
	public void add(PVector l){
		grass.add(l.get());
	}
	
	public void display(PApplet p){
		for(PVector g : grass){
			p.ellipseMode(PConstants.CENTER);
			p.fill(0);
			p.ellipse(g.x, g.y, r, r);
			//p.text("x " + g.x + " y " + g.y, g.x+16 , g.y);
		}
	}
	
	
	public void grow(){
		int totalgrass = 25;
		
		while(grass.size() < totalgrass){
			PVector grasses = new PVector();
			grasses.x = parent.random(250, 1750);
			grasses.y = parent.random(250, 1750);
			boolean overlapping = false;
			for(int i = 0; i < grass.size(); i++){
				PVector other = grass.get(i);
				float d = PApplet.dist(grasses.x, grasses.y, other.x, other.y);
				if(d < 32){
					overlapping = true;
					break;
				}
			}
			if(!overlapping ){
				grass.add(grasses);
			}	
		}
	}
	
	
	public ArrayList<PVector> getGrass(){
		return grass;
	}
	
	public PVector position(){
		return position;
	}
	
	public float getR(){
		return r;
	}

}

and the second:

public class Champi {
	PApplet parent;
	ArrayList<PVector> champi;
	public PVector position;
	
	int r;
	
	
	
	@SuppressWarnings("deprecation")
	public Champi(PApplet p, PVector l){
		position = l.get();
		parent = p;
		r = 32;
		champi = new ArrayList<PVector>();
	}
	
	@SuppressWarnings("deprecation")
	public void add(PVector l){
		champi.add(l.get());
	}
	
	public void display(PApplet p){
		for(PVector c : champi){
			p.ellipseMode(PConstants.CENTER);
			p.fill(255,0,0);
			p.ellipse(c.x, c.y, r, r);
		}
	}
	
	public void grow(){
		int totalchamp = 25;
		while(champi.size() < totalchamp){
			PVector champis = new PVector();
			champis.x = parent.random(250, 1750);
			champis.y = parent.random(250, 1750);
			boolean overlapping = false;
			for(int i = 0; i < champi.size(); i++){
				PVector other = champi.get(i);
				float d = PApplet.dist(champis.x, champis.y, other.x, other.y);
				if(d < 32){
					overlapping = true;
					break;
				}
			}
			if(!overlapping){
				champi.add(champis);
			}
		}
	}
	
	public ArrayList<PVector> getChampi(){
		return champi;
	}
	
	public PVector position(){
		return position;
	}
	
	public float getR(){
		return r;
	}
}

i tried to add the ArrayList of one classe to the other but it doenst work, i have this message:

The method add(PVector) in the type ArrayList is not applicable for the arguments (Class)

when i tried this:

public void grow(){
		int totalchamp = 25;
                ///////////////what i tried////////////////////
		champi.addAll((Collection<? extends PVector>) new Grass(parent, position));
                ////////////////////////////////////////////////////
		while(champi.size() < totalchamp){
			PVector champis = new PVector();
			champis.x = parent.random(250, 1750);
			champis.y = parent.random(250, 1750);
			boolean overlapping = false;
			for(int i = 0; i < champi.size(); i++){
				PVector other = champi.get(i);
				float d = PApplet.dist(champis.x, champis.y, other.x, other.y);
				if(d < 32){
					overlapping = true;
					break;
				}
			}
			if(!overlapping){
				champi.add(champis);
			}
		}
	}

i have this exception :
java.lang.ClassCastException: entity.Grass cannot be cast to java.util.Collection

what do i do wrong ?

Thanks for yours times.


#2

The class Grass is not a one of the Java collections but one of its attributes is grass so you might try

champi.addAll( (new Grass(parent, position)).grass);

#3

thanks for the advice, i dont have the error now :slight_smile:.

but it still overlapp, i gonna search


#4

i just check the champi.size() and it do not add the list of grass (the number of object in the champi.size() is still the same)


#5

It does add the grass item but it is empty because you started with a new instance of Grass, and the constructor creates an empty collection of PVector objects called grass.


#6

ho ok, so how do i add the grass items into the champi list without create an new instance of Grass ?


#7

so if i understand right, when i do :

champi.addAll((new Grass(parent, position)).grass);

i create an new empty list of grass and i added it to the list of champi

am i right ?


#8

Yes that is correct …


#9

ok sorry for my dumb question, im a beginner in programing :slight_smile:
so is there a way to add the grass list in the champi list without create a new empty list ?


#10

so i found a “solution” and its work:

	public void grow(Grass g){
		int totalchamp = 50;
		//champi.addAll((new Grass(parent, position)).grass);
		while(champi.size() < totalchamp){
			PVector champis = new PVector();
			champis.x = parent.random(250, 1750);
			champis.y = parent.random(250, 1750);
			boolean overlapping = false;
			for(int i = 0; i < champi.size(); i++){
				PVector other = champi.get(i);
				float d = PApplet.dist(champis.x, champis.y, other.x, other.y);
				if(d < 32){
					overlapping = true;
					break;
				}
			}
			ArrayList<PVector> grass = g.getGrass();
			for(int a = 0; a < grass.size(); a++){
				PVector other = grass.get(a);
				float d = PApplet.dist(champis.x, champis.y, other.x, other.y);
				if(d < 32){
					overlapping = true;
					break;
				}
			}
			if(!overlapping){
				champi.add(champis);
			}
		}
	}

i call the grass list and then i check if its overlapp.
But i wonder, is it a good way ?


#11

I expect so but it is difficult to advise you because I don’t understand what the program is supposed to do.

You have a World class that consists of
1 Praire object (whatever that is)
0 or more Grass objects
0 or more Champi objects (is that the French for Field?)

but then both Grass and Champi have their own collection of positions (PVector) which I assume represents their position in the World.

You also talk about ‘avoiding overlap’ but do not define what constitutes overlap.

Need more info :confounded:


#12

well i want to create a “forest” with grass, mushroom ect…

the prairie is just a green rectangle.
champi is for champignon(mushroom and yes its french)
yes the PVector(position) are for the position in the world

when i said avoiding overlap, i mean, “not on each other”.

ho and prairie is for meadow :slight_smile:


#13

OK I understand what you are trying to achieve and the problem is caused by the design of your classes. In particular the Grass and Champi classes. I will create a simple Processing example to show what I mean.


#14

Before I show you the example code some things to mention.

Note 1:

This is often a common occurrence and in this case both the Grass and Champi class represents an obstacle for the player. To avoid a lot of duplicate coding we should create a class called Obstacle which holds all the general information about an obstacle i.e. position, size, colour etc;
Different types of obstacle e.g. Champi and Grass will inherit from Obstacle and provide any information specific to their type.

Note2:
The classes Grass and Champi should represent a single instance of this type of obstacle so neither class should be aware of other obstacles therefore do not have ArrayLists

Note3:
The World class should be aware of all obstacles in its domain so will have a single ArrayList of Obstacles. This list will hold both Grass and Champi objects.

Note4:

This is challenging because we have to test every new Obstacle against all Obstacles created so far to make sure there is no overlap. The problem is two fold
(1) The time taken to locate n obstacles is proportional to n*n. So doubling the number of Obstacles would quadruple the time and that is the best scenario.
(2) As the number of obstacles increases the chances of overlap increases and eventually it becomes impossible to find a location that would not cause overlap and the program will go into an infinite loop and appear to freeze. The sketch code below will stop creating obstacles if it takes longer than 100 milliseconds to find the next position without overlap.

In the code below I have used Mushroom and Tree for obstacles but you should be able to see how it all fits together. Anyway the sketch runs in Processing and produced the following world.

world

World w;

public void settings() {
  size(400, 400);
}

public void setup() {
  w = new World(this);
  w.makeObstacles(20, 40);
  w.render();
  save("world.png");
}

public class World {
  PApplet p;
  ArrayList<Obstacle> obs = new ArrayList<Obstacle>();

  public World(PApplet parent) {
    p = parent;
  }

  public void makeObstacles(int nbrTrees, int nbrMushrooms) {
    for (int i = 0; i < nbrTrees + nbrMushrooms; i++) {
      PVector next = findSuitablePosition(100);
      if(next == null){
        break;
      }
      if (i < nbrTrees) {
        obs.add(new Tree(p, next));
      } else {
        obs.add(new Mushroom(p, next));
      }
    }
  }

  private PVector findSuitablePosition(int maxTime) {
    PVector pp;
    boolean found;
    int time = p.millis();
    do {
      found = true; // Assume it will not overlap
      // Random position avoiding very edges of world
      pp = new PVector(20 + p.random(p.width - 40), 20 + p.random(p.height - 40));
      // See if it overlaps
      for (Obstacle ob : obs) {
        if (PVector.dist(ob.pos, pp) < 32) {
          found = false; // overlap found
          break;
        }
      }
    } while (!found && p.millis() - time <= maxTime); // continue until no overlap
    return found ? pp : null; // return nul if taking too long
  }

  public void render() {
    p.pushMatrix();
    p.pushStyle();
    p.fill(200, 255, 200);
    p.rect(0, 0, p.width, p.height);
    for (Obstacle ob : obs) {
      ob.render();
    }
    p.popStyle();
    p.popMatrix();
  }
}

public class Obstacle {
  PApplet p;
  PVector pos = new PVector();
  int col;
  int diam;

  Obstacle(PApplet parent, PVector pos) {
    p = parent;
    this.pos.set(pos);
  }

  public void render() {
    p.pushMatrix();
    p.pushStyle();
    p.noStroke();
    p.fill(col);
    println("Render " + this);
    p.translate(pos.x, pos.y);
    p.ellipse(0, 0, diam, diam);
    p.popStyle();
    p.popMatrix();
  }
}

public class Tree extends Obstacle {

  public Tree(PApplet p, PVector pos) {
    super(p, pos);
    diam = 16;
    // Note you cannot use p.color(0,176, 0) bug in Processing
    col = 0xFF00AA00; // darkish green
  }
}

public class Mushroom extends Obstacle {

  public Mushroom(PApplet p, PVector pos) {
    super(p, pos);
    diam = 6;
    // Note you cannot use p.color(0,176, 00
    col = 0xFF667722; // some other colour
  }
}

#15

wow thanks for the explainations, i gonna assimilate that and come back tomorow :slight_smile: probably with some questions


#16

i imagine that the lists can differenciate what’s inside.
exemple : the player can eat mushroom, so when he touch a mushroom, he eat it and this mushroom is removed from the obstacle list.

am i right ?


#17

There is only one list here and it can hold objects of type Obstacle or any class that inherits (extends) from Obstacle, in this case Mushroom and Tree.

The actual list does not differentiate between Mushroom and Tree but we can tell the difference in our code. Java provides two different mechanisms.

Mechanism 1
Java provides the keyword instanceof to test the type of an object. Assume we have a random object from the list (obs) like this.
Obstacle ob = obs.get( (int) random(obs.size()) );
as far as the program is concerned ob is an Obstacle, but we know it can be of type Mushroom or Tree and we can test it like this

if(ob instanceof Mushroom){
  // eat it
}
if(ob instanceof Tree){
  // don't eat it
}

Mechanism 2 (Preferred)
Since we are using an object orientated (OO) language we can make use of inheritance and polymorphism. We have already used inheritance where Obstacle is a parent class with two child classes Mushroom and Tree. Now we need to use polymorphism :smile:

Lets consider adding a new method to our classes, in Mushroom we add

  public boolean isEdible() {
    return true;
  }

and in Tree

  public boolean isEdible() {
    return false;
  }

To make this work the method must also appear in the Obstacle class but do we return true or false? In this case neither, since we never want to create instances of Obstacle we make the class abstract like this

abstract public class Obstacle {

This will prevent an obstacle object being created so the statement obstacle = new Obstacle() would be rejected by the compiler.
Now our class is abstract we can add an abstract method

  abstract public boolean isEdible();

Notice that the method has no definition it is simply a declaration.
So now we get to the good bit - polymorphism.
Start again with a random object from our list :slight_smile:

Obstacle ob = obs.get( (int) random(obs.size()) );

What gets returned when we try this

ob.isEdible()

Java will determine the actual class of ob and call the method in that class. So if it is a Mushroom it returns true, if it is a Tree it returns false.

So time to see it in action, I have modified the previous sketch to include these changes. When the mouse button is clicked it calls a new method in the World class called collision() which simply selects an obstacle at random and if edible removes it from the list.

World w;

public void settings() {
  size(400, 400);
}

public void setup() {
  w = new World(this);
  w.makeObstacles(20, 40);
}

public void draw() {
  w.render();
}

public void mouseClicked() {
  w.collision();
}

public class World {
  PApplet p;
  ArrayList<Obstacle> obs = new ArrayList<Obstacle>();

  public World(PApplet parent) {
    p = parent;
  }

  // This is a dummy method to demonstrate polymorphism
  public void collision() {
    // Pick one obstacle at random from
    Obstacle ob = obs.get( (int) random(obs.size()) );
    // If edible eat it :-)
    if (ob.isEdible()) {
      obs.remove(ob);
      print("A " + ob.getClass().getSimpleName().toLowerCase());
      println(" was consumed after " + millis() + " milliseconds");
    }
  }

  public void makeObstacles(int nbrTrees, int nbrMushrooms) {
    for (int i = 0; i < nbrTrees + nbrMushrooms; i++) {
      PVector next = findSuitablePosition(100);
      if (next == null) {
        break;
      }
      if (i < nbrTrees) {
        obs.add(new Tree(p, next));
      } else {
        obs.add(new Mushroom(p, next));
      }
    }
  }

  private PVector findSuitablePosition(int maxTime) {
    PVector pp;
    boolean found;
    int time = p.millis();
    do {
      found = true; // Assume it will not overlap
      // Random position avoiding very edges of world
      pp = new PVector(20 + p.random(p.width - 40), 20 + p.random(p.height - 40));
      // See if it overlaps
      for (Obstacle ob : obs) {
        if (PVector.dist(ob.pos, pp) < 32) {
          found = false; // overlap found
          break;
        }
      }
    } while (!found && p.millis() - time <= maxTime); // continue until no overlap
    return found ? pp : null; // return nul if taking too long
  }

  public void render() {
    p.pushMatrix();
    p.pushStyle();
    p.fill(200, 255, 200);
    p.rect(0, 0, p.width, p.height);
    for (Obstacle ob : obs) {
      ob.render();
    }
    p.popStyle();
    p.popMatrix();
  }
}

abstract public class Obstacle {
  PApplet p;
  PVector pos = new PVector();
  int col;
  int diam;

  Obstacle(PApplet parent, PVector pos) {
    p = parent;
    this.pos.set(pos);
  }

  public void render() {
    p.pushMatrix();
    p.pushStyle();
    p.noStroke();
    p.fill(col);
    p.translate(pos.x, pos.y);
    p.ellipse(0, 0, diam, diam);
    p.popStyle();
    p.popMatrix();
  }

  abstract public boolean isEdible();
}

public class Tree extends Obstacle {

  public Tree(PApplet p, PVector pos) {
    super(p, pos);
    diam = 16;
    // Note you cannot use p.color(0,176, 0) bug in Processing
    col = 0xFF00AA00; // darkish green
  }

  public boolean isEdible() {
    return false;
  }
}

public class Mushroom extends Obstacle {

  public Mushroom(PApplet p, PVector pos) {
    super(p, pos);
    diam = 6;
    // Note you cannot use p.color(0,176, 00
    col = 0xFF667722; // some other colour
  }

  public boolean isEdible() {
    return true;
  }
}

#18

and so i can make a collision() class who check :
if the player(assuming i have a player) is colliding with a mushroom, the player eat it and the world remove this specific mushroom from the list.

am i correct ? (you dont need to make another exemple, the two you gave me are amazing and i think i can extrapolate :slight_smile: )


#19

You don’t need a class for collisions you test for these in the Player class

public class Player {

  public Obstacle collision(ArrayList<Obstacle> list){
    // return the obstacle it collides with or null if no collision
  }

]

So the world update method algorithm would be

  • move the player
  • test for collision
  • if collision and obstacle edible remove it from list

#20

ok many thanks for your explainations, exemples and most of it, your time. I gonna assimilate all of that, work on it and i gonna show you what i make