Saving objects from different classes into the same array

This is my first post here ever so I’m gonna format it intuitively. I’m attempting to remake a game I already made months ago (using scratch) into processing. Here’s the game in scratch…
https://scratch.mit.edu/projects/240948644/ (if it doesnt load I’ll try to post link that does)

Here’s the code in processing…

float x = 0;
float y = 0;

Level[] level1 = {

Wall[] walls = new Wall[100];

Player1[] player = new Player1[1];
void setup(){
// Scratch area size = (480, 360)
//scratch + 20% X and Y (624, 468)
//Size I originally wanted size(1210, 610);
//Size of actual scratch area plus 5% of each X and Y size(504, 378);
//Size of scratch area doubled then added 5% (1008, 756);
size(624, 468);
}

void draw(){
//Default background to every level
background(255);

walls[1] = new Wall(-20, -20, 60, height+20);
walls[1].draw();
walls[2] = new Wall(width-40, -20, width+20, height+20);
walls[2].draw();
walls[3] = new Wall(-20, -20, width+20, 60);
walls[3].draw();
walls[4] = new Wall(-20, height-40, width+20, height+20);
walls[4].draw();

//All 4 "rect"s are the walls of the game universally
/*fill(0);
rect(-20, -20, 60, height+20);
fill(0);
rect(width-40, -20, width+20, height+20);
fill(0);
rect(-20, -20, width+20, 60);
fill(0);
rect(-20, height-40, width+20, height+20);
*/

//Level 1
fill(0);
rect(40, 40, width/3, height/2);
fill(0);
rect(width0.6, height0.35, 564, 387);

/*
//Level 2:
//right-most wall
fill(0);
rect(width0.65, 0, width0.15, height*0.7);

//bottom left chunk
fill(0);
rect(0, height0.5, width0.5, height*0.5);

//middle wall
fill(0);
rect(width0.3, height0.2, width0.2, height0.3);

//top left lip
fill(0);
rect(width0.15, height0.2, width0.2, height0.1);
*/

/*
//Level 3:
//Top portion
fill(0);
rect(0, 0, width, height*0.3);

//Bottom portion
fill(0);
rect(width0.3, height0.6, width*0.4, height);
*/

//Level 4:
//fill(0);

}

class Key{
float x;
float y;
float xS;
float yS;
float red;
float green;
float blue;
Key(){
}
Key(float xPos, float yPos, float xSize, float ySize, float r, float g, float b){
float x = xPos;
float y = yPos;
float xS = xSize;
float yS = ySize;
float red = r;
float green = g;
float blue = b;
}
void draw(){
fill(red, green, blue);
ellipse(x, y, xS, yS); //need to draw key universally

}
}

class Player1{
float x;
float y;
float xSi;
float ySi;
float xSp;
float ySp;
//boolean isTouchingOuterWall;
//boolean isTouchingInnerWall;
boolean collisionWithRect;

Player1(){
}

Player1(float xPos, float yPos, float xSize, float ySize, float xSpeed, float ySpeed){
float x = xPos;
float y = yPos;
float xSi = xSize;
float ySi = ySize;
float xSp = xSpeed;
float ySp = ySpeed;
}

void draw(){
fill(255, 255, 0);
rect(x, y, xSi, ySi); //will make it more than just a rectangle
}

void move(){
if (keyPressed){
if (key == CODED){
if (keyCode == LEFT){
x -= xSp;
if (collisionWithRect == true){
x -= -xSp;
}
} else if (keyCode == RIGHT){
x += xSp;
if (collisionWithRect == true){
x += -xSp;
}
} else if (keyCode == DOWN){
y += ySp;
if (collisionWithRect == true){
y += -ySp;
}
} else if (keyCode == UP){
y -= ySp;
if (collisionWithRect == true){
y += -ySp;
}
}
}
}
}
}

/*boolean collision(Wall wall){

}*/

class Wall{
float x = 0;
float xSize = 0;
float y = 0;
float ySize = 0;
Wall (float xOne, float yOne, float xTwo, float yTwo){
x = xOne;
y = yOne;
xSize = xTwo - xOne;
ySize = yTwo - yOne;
}

void draw(){
fill(0);
rect(x, y, xSize, ySize);
}
}

My general question is what is the most efficient/easy way to “save” each level’s walls, keys, doors, and anything that stays stationary into an object array called “level1[]” and so on. And boolean statements which make the entire array turn off and on. “on” means everything in array draws itself and is visible, and “off” means the entire array hides.

At first, I want an array of walls and keys up to 100 or so, and when I need to use 1/100 of them for a level, I simply create it specifically for the level but then add it to an array titled “level1”.

All the logic to do with collision only needs to do with the walls. Keys can be moved right through, and enemies anyway reset everything. I want a universal “reset” boolean for each level.

Looks like you’ve got a great start! The way I would suggest going about this is not to store multiple objects of different types in one array. This generally leads to bugs when trying to access the array. I suggest you create a level class to store all the elements associated with that level. Also using an ArrayList will help you in some cases. ArrayList is a dynamic sized array so you can add and remove stuff without worrying if there’s enough space. If you want to learn more about ArrayLists check out this video. Here’s a framework for how I’d start to layout a level class:

class Level {

  ArrayList<Wall> walls;
  ArrayList<Key> keys;
  ArrayList<Door> doors;

  Level() {
    walls = new ArrayList<Wall>();
    keys = new ArrayList<Key>();
    doors = new ArrayList<Door>();
  }

  display() { // I suggest using display or show as a name rather than draw
    for (int i = 0; i < walls.size(); i++) { // normal for loop
      walls.get(i).show(); // use .get() on ArrayLists
    }
    for (Key k : keys) { // for each loop, effectively the same as above but a little quicker to write once you understand how it works
      k.show(); // k is equal to the current key so no need for .get()
    }
    // loop through doors also
  }

}

// In your main program store all the levels in another ArrayList and just key a variable to say what level you're on
ArrayList<Level> levels = new ArrayList<Levels>();
int currentLevel = 1;

// You can start creating level in setup by doing by doing something like this
Level level = new Level();
level.walls.add(new Wall(some parameters));
level.keys.add(new Key(some parameters));
// so on and so forth
// then add level to levels ArrayList and repeat
levels.add(level);

// then in draw you can just say
levels.get(currentLevel).display();

Note: In the future please use control + t to format your code in processing then paste it bettween ``` ``` This will make it much easier to read and follow.

Thank you for your reply I spent a while trying to configure my code to work with your suggestions and logic and I do need a little assistance understanding it all.
Creating a level class allows me to create objects for each level. I can pass various variables and objects as constructors.

ArrayList walls;
ArrayList keys;
ArrayList goals;

these 3 lines creates the notion of “a list of walls, a list of keys, and a list of goals”. implying that any level can be expressed as a list of objects ranging between walls keys and goals. Now I can place the specific wall, key, and goal objects through the level object by creating constructors. Those level constructors r list of objects of each.
when creating a level object, keep in mind not every level contains everything, so when making constructors, b sure to make multiple constructors for every level possibility. every level contains walls, the main player, and a goal. Keys arent introduced til level 3, enemies at level 5, and moving walls til level 3 (which might not matter) so many level constructors must be created.
I’m making a list of levels using Level[] level = new Level[100]; then in draw I’m calling upon each level using levels[0] = new Level(walls[0 through 3], player[0], goals[0]); and Ill use whatever list range that I need for those specific level.
In general spending several hours a day thinking through all this will help but I somehow feel a bit stuck. This comment is mostly me thinking out loud.

The advantage of using ArrayLists is that if you don’t have anything in the list then it doesn’t cause any problems. So you don’t really have to worry if one is empty. I think trying to do this all through a constructors would be difficult. You can modify a level after creating it like:

Level[] levels = new Level[100];

void setupLevels() { // call in setup
  levels[0] = new Level(player[0], goals[0]);
  // Could add play and goals in constructor if each level has one.
  for (int i = 0; i <= 3; i++) {
    // will add walls 0 through 3 to level 0 (or 1 depending on numbering)
    levels[0].walls.add(walls[i]);
  }
  // skipping a couple levels
  // level 7 (or 8 depending on numbering)
  levels[7] = new Level(player[0], goals[1]);
  for (int i = 2; i <= 4; i++) { // could reuse walls
    levels[7].walls.add(walls[i]);
  }
  levels[7].walls.add(walls[10]); // could add some other walls not in range
  levels[7].keys.add(keys[2]);
  levels[7].keys.add(new Key(xLocation, yLocation)); // can create an object inline
  // then do similar stuff for other levels
}

Does that make sense? I’m not sure if it helps or not.

You definitely helped me understand logically and syntactically how to engage with lists of level objects and how to add other objects to them. This implies to me 2 things, I can either prematurely create every wall for every level rn, so I have walls[0] through walls[50] depending on how I decide to draw the levels out, then simply add the corresponding walls to each level as they should be. This’ll allow me to have multiple level-walls which can be looped through similarly to how u showed me in ur code.
But you added that I can reuse walls, which gave me another idea. When adding a wall to a level object, I just pass parameters for where and how big the wall for the specific level will be (the parameters will go through the wall class and it’ll figure out how to “draw” the wall itself, then return the wall object as a draw-able object.

Problem is I’m overthinking all this… and confusing myself…

Then there’s the notion of the raw syntax of levels[i].walls.add(walls[10]; , which specifically adds walls[10] to the level “i”. the dots represent different increments of classes and objects.

I can assume that all we r currently focusing on rn is having multiple level objects which carry with them all the walls, keys, players, enemies, and goals that correspond with them. “drawing” these things at the level intervals will be next step. Once i can call a level and have it just draw out everything that should exist then I can work on level transitions and player and enemy movement. Once i have my level object I can loop through it "for every wall, draw it, for every key, draw it, " and so on. I may just choose to go with not reusing objects, for simplicity sake.
Can a level list contain walls and keys? can i have:

Level1[] = wall[0 - 4], key[0], player[0], enemies[0-1]; or does it not work that way.

When u wrote levels[7].keys.add(keys[2]); , It means to me that your going inside the level[7] object’s key list and adding a key to it. Ok ye by typing that I understood it more.

levels[7].keys.add(new Key(xLocation, yLocation)); is why I thought of adding walls to the level objects directly instead of prematurely making the wall objects then placing in the respective ones into the levels, but im rambling at this point.

So instead of doing this:

levels[0] = wall[0], wall[1], wall[2];
levels[1] = wall[0], wall[1];
levels[2] = wall[0], wall[1], wall[2], wall[3], wall[4];

imma do this:

wall[0] = wall(parameters);
wall[0] = wall(parameters);
wall[0] = wall(parameters);

I didnt finish typing that last one, quick edit.

So instead of doing this:

levels[0] = wall[0], wall[1], wall[2];
levels[1] = wall[0], wall[1];
levels[2] = wall[0], wall[1], wall[2], wall[3], wall[4];

imma do this:

wall[0] = wall(parameters);
wall[1] = wall(parameters);
wall[2] = wall(parameters);
wall[3] = wall(parameters);
wall[4] = wall(parameters);
wall[5] = wall(parameters);
wall[6] = wall(parameters);
wall[7] = wall(parameters);
wall[8] = wall(parameters);
wall[9] = wall(parameters);
wall[10] = wall(parameters);

levels[0] = wall[0] - wall[3];
levels[1] = wall[4] - wall[7];
levels[2] = wall[8] - wall[10];

Looks like you understand all the concepts but you’re syntax might be a little off in places. So If you get stuck check the reference page because it’s good examples on most of what you can do. I suggest working on getting something like 5 levels done and running, before working on the rest because it’s a pain to do a bunch of work and then have to throw it away because you realize it’s not working right. But it’s easy to expand on code you already know works.

There’s something called an interface that will allow you to put a bunch of different things in a ArrayList (or an array). It’s a bit more advanced but if you want to check it out it can be really useful. Here’s a tutorial on interfaces. And here’s an example in processing. This is how I would do it in your project:

interface GameElement {
  void show();
}

class Level {
  ArrayList<GameElement> elements = new ArrayList<GameElement>();
  // Anything that implements GameElement can go in this list
  // Add constructor
  void show() {
    for (GameElement g : elements) {
      g.show(); // can call show because every GameElement is forced to have a show method
    }
  }
 // Add whatever else you need
}

class Key implements GameElement {
  // Whatever you have in this class
  void show() {
    // should get an error if the Key class doesn't have a show method because it implements GameElement
    // however you would show your key
  }
}
1 Like

Ok I think Im going to use that cuz I c how it works. Does the “interface GameElement void show” have to be in it’s own place (its own tab, like a class would) or does it not matter. It prob doesn’t matter.
So any class which implements GameElement must include the thing inside game element. can I add variables? like how you have “void show”, so every class implementing game element must contain a show method, therefore if i place “int x” in game element, every class implementing game element must have a variable “x”.

So now I can have multiple level objects, each with it’s own ‘elements’ list containing all the items that level should have, then in my main class (where everything is actually drawn and done) just loop through the level1elementList, level 2elementList and so on.

In class level, where I add any GameElement object, where it says "ArrayList elements = new ArrayList(); , can I do the same with a normal array? I assume not cuz it might defeat the purpose of doing GameElement… idk I’ll experiment and c what happens.

I have my arrays set like this in my main area:

Wall[] walls = new Wall[100];
Gate[] gates = new Gate[100];
Player1[] player = new Player1[100];
Goal[] goals = new Goal[100];
Key[] keys = new Key[100];
Enemy[] enemies = new Enemy[100];
Level[] levels = new Level[100];

The levels array creates an error.
Once I have my arbitrary blank array of levels i can then say levels[0].append(walls[0]);
Or loop through a specific number of walls like

for (int i = 0; i <= 4; i ++){
levels[0].append(walls[i]);
}

and do that for every set of walls, players, gates, and everything for levels[0], then levels[1], until I’m done with everything, then I have all my levels set in a neat array.

I completely forgot about the implements ArrayList thing… I can just append every element corresponding to particular levels into objects levels[i]…

My level class has a mistake or two cuz there’s different arraylists at beginning which I don’t need.

class Level{
  ArrayList<Wall> walls;
  ArrayList<Key> keys;
  ArrayList<Goal> goals;
  
  ArrayList<GameElement> elements = new ArrayList<GameElement>();
  
  

  Level() {
    walls = new ArrayList<Wall>();
    //gates = new ArrayList<Gate>();
    keys = new ArrayList<Key>();
    goals = new ArrayList<Goal>();
  }

  void draw() { 
    for (int i = 0; i < walls.size(); i++) { // normal for loop
      walls.get(i).draw(); // use .get() on ArrayLists
    }
    for (Key k : keys) { // for each loop, effectively the same as above but a little quicker to write once you understand how it works
      k.draw(); // k is equal to the current key so no need for .get()
    }
    // loop through doors also
  }

}

// In your main program store all the levels in another ArrayList and just key a variable to say what level you're on
ArrayList<Level> levels = new ArrayList<Level>();
int currentLevel = 1;

// You can start creating level in setup by doing something like this


// so on and so forth
// then add level to levels ArrayList and repeat

I think the constructor confuses me, shouldn’t there be an object of some kind in the constructor so when I implement the specific level objects and append an element, the level class knows where to put the element?