Returning an object type from an arraylist

Hi, I am trying to create a level editor for my game but I’ve encountered a problem where I want to select objects on the screen I tried to make an object called a Selector and change its value every time someone clicks on an object.

class Selector {
  ArrayList Object;
  Selector(ArrayList tempObj) {
    Object = tempObj.getType();
  }
  boolean getType() {
    return Object;
  }
}

That’s the selectors class which does not work.

boolean getType() {
    return BasicEnemy;
}

That’s a piece in the objects class code. The idea behind it is when they click on one of these kinds of objects it selects it and lets them remove the object or place more of it’s kind.

select = new Selector(be);

That’s run for every time they click on any one of the objects that are in it’s arraylist and yes “be” is an arraylist used for all of the objects type. But this selector won’t be used for just this arraylist but a menu with all of the enemies and other arraylists. Please explain how this does not work if you can.

…so BasicEnemy is a boolean? It is true or false?

1 Like

First of all, naming conventions! Variables shouldn‘t start with Capital letters.

Second, this is how methods work :

boolean <<The Type/Class that will be returned>> 

isTrue <<The name of the method>> 

(<<arguments>>)

{

boolean myResult <<has to be the same Type as stated above>>

//your code (should generally only use new variables or from arguments (though that‘s just for the sake of adaptability)

return <<return statement/ends the function/nothing after it is executed>> 

myResult <<the value to return/ has to be of the same Type/class as specified in the beginning>>

;

}

Hope it‘s readable… couldn‘t think of a better way to get the text in there :sweat_smile:

Please don’t call a list Object or objects or so.

That’s a keyword in Java.

Instead use screenItems or so

Also „be“ as a name is far too short and not a good name

—————————————

All in all I think that you think too complicate.

You want a Level Editor: so a map you draw on. For drawing you don’t select a color but the type: path/wall/enemy.

Now, to do this you have a button on the side. When you click it a menu opens. Here you select a type like path or wall. This is not boolean but int; for example

  • 0 is path,
  • 1 is way,
  • 2 is enemy type 1
  • et cetera.

Store the value in a global variable.

When drawing on the map use this variable and bring it into the cell of the map/grid.

Don’t use new on the selector every time

Chrisir

Sorry man, usually all [edited] sometimes your texts are hard to read or understand for me :woozy_face:

:thinking: In this case I think you are saying something like this (similar):

boolean method (argument1,argument2,...){
  boolean myResult;

  return myResult;
}

boolean << Is the Type/Class that will be returned >> 

method << Is the name of the method>> 

(argument1,argument2,..) << Are the arguments>>

{  << Is the open curly bracket of the method that indicates
      the start of definition>>

boolean myResult; << Is a variable of boolean type>>
//your code should generally only use new variables or from arguments
// (though that‘s just for the sake of adaptability)

return << Is the return statement, ends the method and nothing
          inside the method is executed after>> 

myResult; << Is the value given to "return" >>
// Has to be of the same type/class decelerated at 
// the beginning of the method (boolean in this case)

}  << Is the closed curly bracket of the method
      that indicates the end of the definition>>

Is just in order to understand better, not to bother you; in this case, the example at the begging, I think is necessary to understand that you are going to talk about every single part of the method :sweat_smile: :+1:

2 Likes

Yup, that‘s what i meant :sweat_smile: i tend to just talk about stuff that makes total sense to me, but without any context for others to get what i‘m even talking about :sweat_smile: i just don‘t realize it most of the time :sweat_smile:

1 Like

read also a discussion of functions:

But that’s the problem, I need the selector so for example if they click on any one of the enemies they previously placed down before it will pop up a menu on the side that will say all the info of the enemy like damage, size, color, remove function, ect. So that’s what the idea was for the selector. I guess I can make a global variable for the placements but I will need to use the selector for the objects they place. I have an idea on what to do but if it doesn’t work I’ll come back for help.

This is a perfect opportunity to learn interfaces. You want to be able to select enemies, items, obstacles, … whatever. In a level editor, you could do this with a Tile object, but using class inheritance with extends is a real pain. Instead, use an interface with implements.

  1. Create a simple infobox. What does it need to know about any clicked thing in your editor?
class InfoBox {
  Info selected;
  void select(Info selected) {
    this.selected = selected;
  }
  void render() {
    text("INFOBOX", 5, 10);
    if (selected != null) {
      text(selected.getName(), 5, 20);
      text(str(selected.getX()) + ", " + str(selected.getY()), 5, 30);
    }
  }
}

Okay, so it wants the x, y, and name of any Info object. What is an info object? It is any object – of any class – that promises to answer those methods by implementing the Info interface.

interface Info {
  String getName();
  float getX();
  float getY();
}

Great, now that we have defined it we can define any class that implements Info. This means it must contain the promised methods – getName(), getX(), and getY(). Because those are promised, InfoBox can use anything that implements Info and know that it will have those methods – no matter what class it is.

class Square implements Info {
  float x, y, s;
  String name;
  Square(float x, float y, float s, String name) {
    this.x = x;
    this.y = y;
    this.s = s;
    this.name = name;
  }
  String getName() { 
    return name;
  }
  float getX() { 
    return x;
  }
  float getY() { 
    return y;
  }
  void render() {
    rect(x, y, s, s);
  }
}

Okay, let’s put the two classes and one interface them together in a quick sketch and run it.

void setup(){
  Square sqr = new Square(50, 50, 40, "squarename");
  InfoBox ibx = new InfoBox();
  ibx.select(sqr);
  sqr.render();
  ibx.render();
}

Screen Shot 2019-12-17 at 11.22.48 AM

As you can see, we selected the Square, and – because it implements Info – its data was displayed by the InfoBox. We can create a bunch of other classes – either totally unrelated, or extended from our Square class – and as long each one implements Info then we can ibx.select(foo) to show its data.

How do we make this interactive with the mouse? We click the mouse, then check to see if we hit an object. If we did, we pass it on to ibx.select().

if (sqr.hit(mouseX, mouseY)) ibx.select(sqr);

But in order for that to work, we need to add a boolean hit(float x, float y) method to our class. It will tell us the answer using collision detection.

  boolean hit(float mx, float my) {
    if (mx >= x && mx <= x + s && my >= y && my <= y + s) {
      return true;
    }
    return false;
  }

Okay, to wrap it all up, let’s make an interactive sketch with two different class objects, a Square and a Bounce (which moves). When the mouse is pressed we will check them with collision detection and, if there is a hit, we will select that object with the infobox.

InfoBox ibx = new InfoBox();
Square sqr = new Square(60, 120, 60, "squarename");
Bounce bnc = new Bounce(100, 60, 80, "bouncename");

void setup() {
  size(200, 200);
}
void draw() {
  background(128);

  sqr.render();
  bnc.render();
  ibx.render();

  if (mousePressed) {
    // reset infobox and detect
    ibx.select(null);
    if (sqr.hit(mouseX, mouseY)) ibx.select(sqr);
    if (bnc.hit(mouseX, mouseY)) ibx.select(bnc);
  }
}

interface Info {
  String getName();
  float getX();
  float getY();
}

class InfoBox {
  Info selected;
  void select(Info selected) {
    this.selected = selected;
  }
  void render() {
    text("INFOBOX", 5, 10);
    if (selected != null) {
      text(selected.getName(), 5, 20);
      text(str(selected.getX()) + ", " + str(selected.getY()), 5, 30);
    }
  }
}

class Square implements Info {
  float x, y, s;
  String name;
  Square(float x, float y, float s, String name) {
    this.x = x;
    this.y = y;
    this.s = s;
    this.name = name;
  }
  String getName() { 
    return name;
  }
  float getX() { 
    return x;
  }
  float getY() { 
    return y;
  }
  // point-rect collision detection
  // see http://www.jeffreythompson.org/collision-detection/point-rect.php
  boolean hit(float mx, float my) {
    if (mx >= x && mx <= x + s && my >= y && my <= y + s) {
      return true;
    }
    return false;
  }
  void render() {
    rect(x, y, s, s);
  }
}

class Bounce extends Square {
  int dy;
  Bounce(float x, float y, float s, String name) {
    super(x, y, s, name);
    this.dy = 1;
  }
  String getName() { 
    return name;
  }
  float getX() { 
    return x;
  }
  float getY() { 
    return y;
  }
  @Override
    void render() {
    super.render() ;
    y+=dy;
    if (y<0||y+s>width) dy*=-1;
  }
}

SelectionInfo--screenshot

5 Likes

This is amazingly helpful and I did not know you could do this kind of stuff, I already began something I thought might work and am currently working on it because what I want is exactly like that an info box with the info for the objects but I wanted you to be able to enter new variables in it for changing its size, speed, damage, etc. If my way doesn’t work I’ll try this way for sure and if that doesn’t work I’ll come back for help. Also the problem I see here is this works for individual objects and what all of the objects they will be selecting on my screen will be in array lists so could I get the value of it in the array list so they can select and remove objects using this?

1 Like

Just loop over your list.

for(MyClass o : mylist){
  if (o.hit(mouseX, mouseY)) ibx.select(o);
}

Or make a list of lists:

ArrayList<ArrayList<MyClass>> lists;
lists.append(enemies);
lists.append(obstacles);
// ...
for(ArrayList<MyClass> list : lists){
  for(MyClass o : mylist){
    if (o.hit(mouseX, mouseY)) ibx.select(o);
  }
}
1 Like

Oh so in theory where I have multiple array lists (one for each type of enemy) I could just append them all together since every single enemy class uses the method “update()” and just update the list of array lists with:

ArrayList lists;
ArrayList<Sqaures> squares = new ArrayList<Squares>();
ArrayList<Circles> circles = new ArrayList<Circles>();

lists.append(squares);
lists.append(circles);

for (int i=0; i < lists.size(); i++) lists.get(i).update();

Is this achievable? Or I should just stick to updating each individual list. If this is possible then if I wanted to call a specific object couldn’t I still call them normally using there own list or would I always have to call them through lists?

1 Like

It did not work so it gives me an error on the append when I try to append a list to my list and I tried add and it didn’t give me an error but when I ran it, it did. So is there any way to do what I’m trying to do? Have it cycle the interface through multiple array lists?

As @jeremydouglass has shown, you‘ll have to use :

//i‘m not sure about this one... just going with what i understood from @jeremydouglass‘s explanation about Interfaces

ArrayList<ArrayList<ShapeInterface> lists = new ArrayList<ArrayList<ShapeInterface>();

ArrayList<Circle> circles = new ArrayList<Circle>();
ArrayList<Square> squares = new ArrayList<Square>();

//where 

class Circle implements ShapeInterface{}
class Square implements ShapeInterface{}

//or if you‘re not going with Interfaces

ArrayList<ArrayList<Shape>> lists;

ArrayList<Square> squares = new ArrayList<Square>();
ArrayList<Circle> circles = new ArrayList<Circle>();

//where 

class Square extends Shape{}
class Circle extends Shape{}

//and then just use this to add to the lists

lists.add(squares);
lists.add(circles);

@Lexyth
in what environment did you run this,
here in processing 3.5.3 things like

 ArrayList<ShapeInterface> circles = new ArrayList<Circle>();

or

ArrayList<Shape> squares = new ArrayList<Square>();

are not working.

insofar
implements interface
//or
extends class

does not help to make a

ArrayList of elements from different classes

( think that was the question here )

1 Like

I use the iCompiler, but turns out, something like :

String s = new PVector(24,43); //this works, which it shouldn‘t, unless it ignores the left class...

works too, so the example i just set up is useless… but this is what i was going for, and it should work :

class Animal {}

class Dog extends Animal {}

Animal myPet = new Dog();

//which for me means that this should work
//Edit: this one doesn‘t work
ArrayList<Animal> list = new ArrayList<Dog>();

//Edit: this one does
ArrayList<Animal> list = new ArrayList<Animal>();
list.add(new Dog());

How would you do it, cause the only other way i can see would be using Object as the main class, but that‘s pretty much the same, as far as i know…

Edit, nvm, i think i see what was wrong.

It should be :

ArrayList<Animal> list= new ArrayList<Animal>();
list.add(new Dog());
1 Like

thanks, with this i got something working,

but to make use of a ‘super’ class and its ‘super’ array
i needed following:

-a- a method must be declared in all 3 classes ( ‘super’, ‘sub’, ‘sub’ )
( and not needed any @overwrite )

-b- a variable must be declared in ‘super’ class,
NOT in ‘sub’ class,
but set in ‘sub’ class
using super.x =10; not required but worked too.

only then i was able to use like

Shape s = shapes.get(0);
println( s.x , s.y );
s.display();

good, but actually now i am at the same question this topic is about ( i think )
does this s know that it is a ‘sub’ class ‘Ball’ and its name is ‘ball’ ?
( back to the experts … )

so i just play with a work around:

// make a combined arrayList using
// extends class

void setup() { //__________________________________ SETUP
  size(500, 500);
  Ball ball = new Ball(width/2, height/2,0);
  all.add( ball );
  Paddle paddle1 = new Paddle(10, 30,1);
  all.add(paddle1);
  Paddle paddle2 = new Paddle(width-30, 30,2);
  all.add(paddle2);
  for (Shape s : all )  println( s.typ + " id " + s.id + " x "+ s.x+ " y "+ s.y);
  // still OP question: is it possible to ask for class "Ball" and name "ball" of 's'
}

void draw() { //___________________________________ DRAW
  background(200,200,0);
  for (Shape s : all ) s.display(); //_____________ a reason why this structure can make sense
}

//_________________________________________________ CLASSES and ARRAYS

ArrayList<Shape> all = new ArrayList<Shape>();

class Shape {
  public int x, y, id;
  public String typ = "Shape";
  public void display() { } //____________ with this above s.display() works
}

class Ball extends Shape {
  
  Ball(int _x, int _y, int _id) {
    x = _x;
    y = _y;
    id = _id;
    typ = "Ball";
  }

  public void display() {
    circle(x, y, 20);
  }

}

class Paddle extends Shape {
  
  Paddle(int _x, int _y, int _id) {
    x = _x;
    y = _y;
    id = _id;
    typ = "Paddle";
  }
  
  public void display() {
    rect(x, y, 20, 100);
  }
}

think i found it:

  for (Shape s : all ) {
    if      ( s instanceof Ball)   println("a Ball");  
    else if ( s instanceof Paddle) println("a Paddle");
  }

looks good

1 Like

If you want to manage a list-of-lists using interfaces – so that you can loop over all entities, but also loop over any specific type of entity, for example – then here is an example of how to do that with interfaces.

I created an ArrayList of each type and then created an ArrayList to store them all. Notice the cast in this line:

for (ArrayList<ShowData> Entity : entities) {

So, to summarize, we have a Data class, an interface ShowData that lets any entity show its data, an Arraylist for each type of entity (Friend, Enemy) and then a list-of-lists to manage however many entities we have. We loop over the list of lists and show their data.

ArrayList<Friend> friends;
ArrayList<Enemy> enemies;
ArrayList<Stranger> strangers;
ArrayList<ArrayList> entities;

void setup() {
  friends = new ArrayList<Friend>();
  friends.add(new Friend("Dr. Ally"));
  friends.add(new Friend("Captain Helper"));
  enemies = new ArrayList<Enemy>();
  enemies.add(new Enemy(-5));
  enemies.add(new Enemy(-10));
  strangers = new ArrayList<Stranger>();
  strangers.add(new Stranger());
  strangers.add(new Stranger());
  strangers.add(new Stranger());
  strangers.add(new Stranger());

  entities = new ArrayList<ArrayList>();
  entities.add(friends);
  entities.add(enemies);
  entities.add(strangers);
  for (ArrayList<ShowData> Entity : entities) {
    for (ShowData obj : Entity) {
      Data e = obj.getData();
      e.log();
    }
  }
}

interface ShowData {
  Data getData();
}

class Friend implements ShowData {
  Data d;
  Friend(String name){
    d = new Data(name, random(1,10));
  }
  Data getData() { 
    return d;
  }
}

class Enemy implements ShowData {
  Data d;
  Enemy(float value){
    d = new Data("enemy", value);
  }
  Data getData() { 
    return d;
  }
}

class Stranger implements ShowData {
  Data d;
  Stranger(){
    d = new Data("stranger", random(-1,3));
  }
  Data getData() { 
    return d;
  }
}

class Data {
  String name = "";
  float value = 0;
  Data (String name, float value) { 
    this.name = name;
    this.value = value;
  }
  void log() { 
    println(name, value);
  }
}

Now you add InfoBox and collision detection methods to your interface as in my previous example. Notice that Friend and Enemy can have different constructors and different methods – they don’t need to be related by inheritence / extends. The only requirement is that they both implement the ShowData interface – that is, the getData() method.

2 Likes

good, but actually it is like i try first,
you give a class a variable name = "class";
so you later can from the combined list identify who is who…

but
-a- does entities still know like the listname ‘friends’ ( it has its content in .get(0) )
-b- it does know the Class ( sorry, but i can only ask for it like this )

  println("Friend? "+( entities.get(0).get(0) instanceof Friend ) );

any better way to do it?

-c- i failed to understand if that what you did here, could be called in SQL a
VIEW ( over tables )?

1 Like

RE:

No. Due to type erasure, you can keep a named index for each list, – friends = 0 – but an ArrayList can’t be checked with instanceof to retrieve Foo. For discussion see: java - Cannot perform instanceof check against parameterized type ArrayList<Foo> - Stack Overflow

If your sub-lists each contain one type of object, one way is to just check the first object for its type – then that is the type of the whole list. Another way is to store a list of type labels corresponding to your ArrayList index numbers.

Those name and value fields are just meant to demonstrate arbitrary metadata for the infobox – name field isn’t used for identifying the object class. I named all the enemies “enemy”, but could have named them anything, like “foo” “bar” – and I gave each of the friends a different funny name.

If you want to retrieve the individual object class name, you can use instanceof and a cast, as you already showed.

As far as I can tell, the original poster has this kind of design:

So in my example I showed how to work with that design –

  1. to have separate lists of arbitrarily different objects, like ArrayList<Enemy>
  2. to loop over all those lists – a list of lists – and retrieve shared information

Of course, you can also change the design and keep all those objects in one big list. It depends on the design – that could create really bad performance problems if you have to iterate over all your static objects in order to find a few dynamic ones to update – checking every rock each time a creature moves. But might not matter in a level editor when presumably everything is static.

So, if keeping all the objects in one list is acceptable, then the one list works fine. If keeping lists separate is better, that also works fine. There is no one right way.

One other small difference – I am not using extends in my solutions; objects only share an interface. Both work in a similar way with ArrayLists and casting – and type erasure.

2 Likes