Collision between different maps (2d lwjgl)

Let’s say you have a Level object. It has a public field that is an ArrayList of all the entities. You initialize the level object, load it from a file, and make all the entities. For each entity made, you have to pass the same level object that’s loading the entities to the entity itself, as shown in the code sample below. Then in your entity class, you can store said level object (when passed) and use it whenever you need to. That is how you pass the list (rather, it’s the entire level) to the entity.


public class Level{

   public ArrayList<Entity> entities = new ArrayList<Entity>();

   public Level(String filePath){
      // do the loading here or whatnot
      // when you init your entities
      Entity e = new Entity(this); // pass the level instance to the entity
   }

}

public class Entity{
   
   Level level;

   public Entity(Level lvl){
      level = lvl; // store the level instance
      // then you can use the entity arraylist that's in the level instance
      level.entities.doWhatever();
   }
}

I think chrislo27 has offered a good solution. Personally, I might just keep track of the current level in your GameMain class (maybe a variable called currentLevel and a method getCurrentLevel() to retrieve it), and then whenever something needs to look at the list of objects in the current level, you can do GameMain.getCurrentLevel().getEntities(). This would work if you really only need to care at one level at a time. When you switch levels, GameMain makes a new Level(String filePath) and assigns it to currentLevel. All the old stuff goes away, and everything only cares about currentLevel.

But chrislo27’s solution is just fine.

Question: when you say you’re doing a new class for each level, do you actually mean a new java source code file with a new class definition? Or do you mean you are instantiating the class as a new object, i.e. levelOne = new Level(“levelOne.lvl”)? If you meant the second one all along, that might be part of the confusion.

Question: for passing the ArrayList around, I’m a little fuzzy on what the problem is there. Are you saying that you want a single object (say, the player) to be able to check its collisions against the other objects in the same level, but you don’t want to make a separate player object for each level, and you don’t want to have a separate list of objects for each level? Are you trying to figure out how to keep track of where the objects are in each level separately, even though multiple levels sometimes share the same objects? In other words, are you trying to figure out how to make sure you’re only getting the objects from the current level instead of the objects from all levels without having to hardcode a bunch of separate lists?

When you were talking about pass-by-ref and pass-by-value, it really sounded like you had something backwards, even though you said you understood it. You can have multiple entities share the same list of objects just by having them all use the same level.getEntities() method that gives them all the same list of the same objects. They could get to level.getEntities() either by chrislo’s way (give each entity a reference to the level when you make the entity) or by my way (have a single currentLevel that everything can access).

Lol, I think people just don’t understand my problem here.

First Question: Yes, a brand new java class file. As of right now I would create an instance of it in my main driver whenever clicked, but that’s just how I’m doing it right now.

Second Question: The only issue I’m having personally is updating the arraylist. I tried with an earlier copy of my game passing the arraylist to each creature… and it worked fine. The issue though was like for each bullet, to actually remove health from an existing creature. The point is, I can access an arraylist just fine, but updating the original one which is being drawn I just don’t know how to do. I mean, the point is atm I’m using a static arraylist and hardcoding that in each creature (Player, Enemy).

Thus why I said putting Level.objectlist… cause I thought Jesse said I should use a Level class for every level. I just need a way to both access and update the arraylist in the level class (for multiple levels, not just the first one). Maybe I’m just being a huge derp, but if I pass the level to each creature, that’s just a copy. So… I couldn’t really update health that way.

Of course, if this isn’t a good idea I’m always open to new ideas for collision.

With by ref and by val… I clearly do understand it. My whole issue is java is by-val, which is why I’m asking for help. I know the way I’m doing it is bad (with the arraylist), but that’s why I’m here. I don’t know why you all think I don’t understand it, as I clearly do.

Now what you were saying in the main, you’re saying no matter what I do, I’m accessing GameMain. That may actually work. Cause then I could access the updated/live arraylist, and update data in it. After thinking about this more, I get why I would just use a Level class… but I still feel like using a new class file for each level will be 10000 times easier.

If I did levelOne = new Level(“levelOne.lvl”) (which wasn’t what I was talking about btw), then the only thing unique to that level is the pieces being put into the map. Therefore I can’t actually code anything special to that map… unless you’re saying to add it through an object (so like a wave is created, and 3 enemies are added to the arraylist, and the wave could like create invisible walls to stop the user from going further until all 3 enemies are dead).

To me that just seems like it would get sloppy, as I would be making a firstwave… only for that level. I guess it just seems like using the data driven way takes me on a path I’m not used to, so I don’t see how I would do certian things.

What I will do is try your way through the GameMain, but I still feel like I should make a separate class for each level. I just still don’t get why I wouldn’t I guess.

[quote]but if I pass the level to each creature, that’s just a copy.
[/quote]
Elaborate on what you mean by this. If you intended what I think you did, you are very much misinformed.

General architecture tips:

Entities probably shouldn’t know anything about Level or how they are tracked. That’s Level’s job. Don’t ‘pass the list to each creature.’ Have Level call their constructors and add them to it’s internal list (as in nobody else sees it, they don’t need to).

Make each class responsible only for what it needs.

Don’t hardcode specialized new classes if you can avoid it. A Class is supposed to be a ‘Kind of thing’ or ‘Type’of thing’. Instead specialize with data within a common class, i.e. each instance of the common class contains it’s own special data, but they’re all still the same kind of thing, right? (E.g. Level1, Level2, etc. are all just [icode]Level[/icode]s, they just have different level data in their fields. This is why objects/instances exist, so you don’t have to specialize from scratch for each slightly-different-but-related thing.

Typically the only thing that should be [icode]static[/icode] if you’re going the java way is [icode]public static void main(…)[/icode] and helper/utility functions. Everything else can just be instances, even if you only ever make one instance of a particular class per game lifecycle.

But you DO know that a simple assignment of a Java reference-typed value/object (like your ArrayList) from one field or local to another field or local does NOT create a (deep) copy of the assigned object?

The same goes with an actual argument to a method parameter of a reference type.

You probably know that C++'s type modifier for references (the ampersand) does not exist in Java. But personally I never really ever needed such by-reference semantics in Java.

You surely know that you only need by-reference semantics if you wanted a method invocation to change the value that an actual argument holds after the method returns, provided the actual argument was an l-value, in order for the caller to see that effect.

I never wanted to do that in Java, ever. You only need that in C++ because there you have stack-allocated memory. And to avoid allocating temporary values (even for deep structs) when passing actual values around, you would use that reference modifier (trick).

In Java, all objects are allocated on the heap (conceptually), and basically behave like pointers in C/C++. The asterisk on variables known from C/C++ (meaning “pointer of”) is just implicit in Java.

So whenever you are passing any values/expressions of a reference type (everything except primitive types) around, you would pass a “reference” (with that reference itself being a value) to that same object around. So everywhere you assign that same reference, it would mean the “exact same object”.

To be correct, java is all pass by value.

Although you pass a reference into a method, it actually gets converted to a value, so primitives and objects are both passed by value.

Yes, of course. Was there some place in my post that said otherwise? If so, I will edit it.

EDIT: Ah, I figured where there could be a possible confusion, so I edited the last sentence accordingly.

When can everyone just call it ‘pass by pointer?’ That’s what it is; potential confusion completely circumvented.

I agree ‘pass by pointer’ would make it so much less confusing, but we can’t having it be to easy for people, we have to make it as hard as possible.

Just like one of my lecturers, answers must be word by word correct to the textbook, wrote one word wrong and lost 3 marks, even though the word still made it work.

EDIT: and after rereading your post, I got to what you were saying, reading through it quickly then reading the last paragraph made it seem wrong, but probably better having the value part there for people to know.

Ok now I just feel like I’m doing collision wrong in general from what you’re saying.

At the moment I’m creating an arraylist, and adding every object in the level to it. Then, In each player/enemy I’m looping through that list, and checking if the place I want to move to collides with any other object. Then within bullets, I do that same thing, but with the bullet. If the bullet collides, it deals damage to any creature object, and then destroys itself.

Is it bad to do that for collision? I know everything should be by itself, and again that’s why I’ve felt like I’m doing something wrong. Do you have a better suggestion about what to do for collision?

P.S. … everything you said about by-ref / by-val I agree with, and I knew that already. I don’t know C++ yet, but I want to learn it going into college hopefully. I don’t know what it is that I say that makes you feel like I don’t understand by-ref and by-val.

Okay, I just tried to rule out a misunderstanding of the language by trying to scan where your origins are (the language you did before transitioning to Java).
Chances were that could have been C or C++. :slight_smile:

As for physics and collision detection: Just use a library like JBox2D for your 2D physics. I my opinion this is the best way to do it and to learn from the experienced Box2D authors there.

The principal idea is to have a separate spatial data structure, which holds your physics objects and then do more sophisticated querying algorithms than O(n2) and also to separate cheap, inaccurate but conservative collision detection (broad-phase) from expensive but more accurate methods applied later.

From what I read your still a bit confused by javas approach to pass by value.

try this code out for example



public class Main {
	public static void main(String [] args) {
		Test a = new Test();
		a.a = 50;
		a.b = 60;
		exampleA(a);
		System.out.println("passing a object to a method " + a.a + "  "+a.b);
		
		int d = 50;
		exampleB(d);
		System.out.println("passing a primitive to a method "+d);
	}

	public static void exampleA(Test b) {
		b.a *= 10;
		b.b *= 5;
		b = null;
	}
	
	public static void exampleB(int c) {
		c = 500;
	}

}

public class Test {
	public int a;
	public int b;
}

you can update variables inside of a object that you pass around, but you cant physical change where that object points to on the heap.

The object does get updated everywhere, but the primitive doesn’t. Except for setting a object to null, that wont update it everywhere.

Well, this is a big one. Sorry for the giganto post, but I did see stuff to reply to throughout your post. :slight_smile:

Ok, thanks for clarifying. I think I agree with those who have been saying you are better off with a single Level class and making a new instance of it for each level, setting that instance up with whatever is unique to the level, which you obtain by reading a file. Someone earlier explained why this can be useful. You have to have the data somewhere (place a foo enemy here, start the player there, mark these tiles to explode when the player touches them, etc.), either in your code or in separate files, and I recommend doing it in separate files. It won’t make a ton of difference if you’re in a small game and the only person working on it, but it’s huge when you’re working with other people: now they don’t all have to launch an IDE and learn Java and recompile the game every time they want to make a change.

[quote]With by ref and by val… I clearly do understand it. My whole issue is java is by-val, which is why I’m asking for help. I know the way I’m doing it is bad (with the arraylist), but that’s why I’m here. I don’t know why you all think I don’t understand it, as I clearly do.
[/quote]
I think this is where some confusion lies. I’ll take your word for it that you know by-val means “copying” and by-ref means “both are still pointing at the same thing”, but Java passes the arraylist by reference. If you think that passing an arraylist around makes copies of it and everything in it, I believe you are mistaken. It works better than you think!

[quote]Now what you were saying in the main, you’re saying no matter what I do, I’m accessing GameMain. That may actually work. Cause then I could access the updated/live arraylist, and update data in it. After thinking about this more, I get why I would just use a Level class… but I still feel like using a new class file for each level will be 10000 times easier.
[/quote]
Here, when you talk about each entity accessing the same live arraylist, this only works because the objects can get they arraylist by reference. When they access it, they’re not getting a copy. This would be the case no matter how you did it unless you were making a new arraylist every time, giving it the items from the old list. Even if you did that, the items in the list would still be the same, so if you have enemy1 in listA and also in listB, any changes to enemy1 will be reflected in both lists, because enemy1 is the same object. However, if you removed enemy1 from listA, it would still be in listB.

If you pass a listEntities around to every entity that asks for it, and an entity makes a change to another entity in that list, the change sticks. The entity in that list has been updated. The next thing to ask for the list will get the exact same list with the exact same objects, and if it asks for the same changed entity, it will get that changed entity. If entityFoo changes entityBar in listA, then entityCow looks at entityBar in listA, entityBar will have the change.

[quote]Second Question: The only issue I’m having personally is updating the arraylist. I tried with an earlier copy of my game passing the arraylist to each creature… and it worked fine. The issue though was like for each bullet, to actually remove health from an existing creature. The point is, I can access an arraylist just fine, but updating the original one which is being drawn I just don’t know how to do. I mean, the point is atm I’m using a static arraylist and hardcoding that in each creature (Player, Enemy).

… I just need a way to both access and update the arraylist in the level class (for multiple levels, not just the first one). Maybe I’m just being a huge derp, but if I pass the level to each creature, that’s just a copy. So… I couldn’t really update health that way.

Of course, if this isn’t a good idea I’m always open to new ideas for collision.
[/quote]
Alright, let me define the problem here: you need to check if a bullet entity is colliding with a creature entity that is on the same level as the bullet entity. Example fake code:

//in wherever you handle movement
for(Entity e : GameMain.getCurrentLevel().getEntities()) {
  entity.moveThyself(); //or whatever. if this entity is a bullet, it would move itself based on whatever rules bullets use
}

//in Entity
public Rectangle getCollisionBox() {
  //get or create a rectangle indicating the area that this entity takes up for purposes of collision
}
public void takeDamage(int amount) {
  //modify our hp, check if we're dead, etc.
  //if we are dead, either ask level to remove us (maybe a Level.removeEntity() method)
  //or just wait and have a spot at the end of every game loop where something tells
  //the level to removeDead(). level.removeDead() could then go through and remove
  //any dead entities from its entity list
}

//in Bullet, which extends Entity
public void moveThyself() {
  //blah blah blah, we move around really fast in a direction we decided when we made the bullet
  ArrayList<Entity> collidedWith = GameMain.getCurrentLevel().checkCollisions(this, movementVector); //tell the level that this thing moved a certain amount in a direction
  for(Entity e : collidedWith) { //damage everything the bullet touched
    e.takeDamage(power); //power is a field here on Bullet
  }
  //if you only want to damage the first thing the bullet touched,
  //check that collidedWith.size() > 0, then do collidedWith.get(0).takeDamage(power)
}

//in Level
//assuming we have an arraylist of entities that can be gotten by getEntities()
public ArrayList<Entity> checkCollisions(Entity mover, Vector v) {
  ArrayList<Entity> collidedWith = new ArrayList<>();
  for(Entity e : getEntities()) {
    if(e != mover && mover.getCollisionBox().intersects(e.getCollisionBox())) { //I'll just assume you use rectangles for collision
      collidedWith.add(e);
      //do stuff with the vector info if we care about that
    }
  }
  return collidedWith;
}

[quote]If I did levelOne = new Level(“levelOne.lvl”) (which wasn’t what I was talking about btw), then the only thing unique to that level is the pieces being put into the map. Therefore I can’t actually code anything special to that map… unless you’re saying to add it through an object (so like a wave is created, and 3 enemies are added to the arraylist, and the wave could like create invisible walls to stop the user from going further until all 3 enemies are dead).

To me that just seems like it would get sloppy, as I would be making a firstwave… only for that level. I guess it just seems like using the data driven way takes me on a path I’m not used to, so I don’t see how I would do certian things.
[/quote]
Your level file (in my example, “levelOne.lvl”) would have info like “enemy here, player starts there”, but it can have more than that. If there is such a thing as a “wave” of enemies in your game, it could also have a list of waves, specifying what’s in each one. The levelOne file doesn’t need to know what that means. It’s just tagging stuff and listing things. The game is the part that has to know what it means when levelOne says it has a wave of 3 enemies. When the level is reading it’s file, it would say, “Ah, wave: foo, bar, charlie. Ok, make a new wave, make or grab these enemies, put them in the wave, and add the wave to my list of waves, which would be empty if I was a level with no waves.” Somewhere in your game programming, you’d check if the current level had any waves, if it was time to start one, if the wave was finished, etc.

[quote]What I will do is try your way through the GameMain, but I still feel like I should make a separate class for each level. I just still don’t get why I wouldn’t I guess.
[/quote]
I get why this doesn’t seem necessary. I thought the same way at first, but as I programmed more, making a single level class and having them vary by data started to make more and more sense. We can talk about this more if you want.

So… should I do collision through an arraylist in the level, or through JBox2D?

Also regarding the level setup, I guess it just seems like it’s 10 time more complicated using data, but once I understood it, everything may be simpler.

Also with arraylists… you’re saying they are always passed by reference, unlike other data which is passed by value?

Welp…

Sorry lol the school I was at this past year taught in VB and never taught ArrayLists, so I had to think back to sophomore year when I took AP Computer Science (Where I first learned java/programming).

So really my whole issue was never an issue in the first place because ArrayLists handled the situation anyway?

Lol so ya, ArrayLists vs JBox2d (Collision Library)

and the whole thing with data I guess is a way I could do it. You know what, I’m going to attempt to do this.

So I know this has been explained multiple times, but would i just create separate objects that do stuff on their own, and use an identifier in the “data” for the level to spawn that in? Cause wouldn’t I need to hardcode each identifier then? Also if I used data, and let’s say I want one block to be 100 x 100, while I want that same block to be 150 x 100 in another place. Every time I would want to change the size, I would need to make a new identifier… which may get kinda sloppy and tedious. Is this correct in what I’m thinking? Or is there a better way of using data for a level. Lol sorry if I sound like I don’t know what I’m talking about, but I just wanna ask any possible questions regarding this now so I have a much better understanding.

Thank you by the way everyone for the help/advice.

If you had an exam question, java is pass by value.

Although it seems to be pass by reference, its not pass by reference, as long as you remember.

You can send your ArrayList to any class and modify it, and every other class will update it too. But if you set an ArrayList in one of your entities to null, it WILL NOT set every other reference to it to null.

EDIT: can replace ArrayList with any Object and the same thing applies.

So Object = Pass by Reference
Lower data types = pass by value

Well why do they teach us in school that objects are passed by value in java… Lol ok.

But still, should I use arraylists like I used to use them (passing them to each object), or should I use another library like JBox2D?

I don’t think the two are mutually exclusive. Box2d will I assume do your collision checking for you (I’ve never used it before), and you can give it your entities in whatever form, stored whatever way, that it wants. For your purposes, levels can still have arraylists of entities. You can have different collections (like arraylists) for different things. You could have a list of entities the level uses for “what is alive”, a list of entities that are used for “what can collide”, etc. Some entities might be in more than one list, and if you modify an entity in one list, it will also be modified in whatever other lists it’s in, because it is the same object. Don’t imagine that a list has objects inside of it. Imagine that a list has a bunch of wires connecting it to other objects.

[quote]Also regarding the level setup, I guess it just seems like it’s 10 time more complicated using data, but once I understood it, everything may be simpler.
[/quote]
It’s not, strictly speaking, simpler. But it is much more flexible and reusable.

[quote]So I know this has been explained multiple times, but would i just create separate objects that do stuff on their own, and use an identifier in the “data” for the level to spawn that in? Cause wouldn’t I need to hardcode each identifier then? Also if I used data, and let’s say I want one block to be 100 x 100, while I want that same block to be 150 x 100 in another place. Every time I would want to change the size, I would need to make a new identifier… which may get kinda sloppy and tedious. Is this correct in what I’m thinking? Or is there a better way of using data for a level. Lol sorry if I sound like I don’t know what I’m talking about, but I just wanna ask any possible questions regarding this now so I have a much better understanding.
[/quote]
If you have an entities that needs to appear in multiple levels, you have two choices. 1) Maintain a list of universal entities and, whenever a new level is made, tell the level to add that list to its list so it has both the common objects and the unique-to-itself objects. Again, these are references/pointers/whatever, they still only exist as one thing (in terms of logic), you’re just wiring multiple lists to connect to them. 2) When a level is made, include in that level’s data file the info you need to recreate the object. You’re technically forgetting about the old object (let’s say an entity called Foo) and then making a new one (also called Foo) that serves the same purpose. It just depends what makes more sense to you.

As far as differences between levels, here’s how you need to approach it.

  1. Decide all of the different things a level needs to be able to have. Events of various types, tiles of different sorts, waves that define what shows up when, entities that are always there, whatever. Each of those needs to have a blueprint (probably a class) somewhere in your code so that you can make however many things of that type whenever you need them.
  2. Figure out what the level needs to know about each thing in order to create it from that blueprint. For example, for an entity, it may need some kind of keyword that tells you what type of entity it is, some numbers for where it’s positioned, maybe a minutes:seconds value for when it needs to show up, etc. An event might need to have a keyword for what sort of event it is (trigger a wave of enemies, play a cutscene, etc.), along with whatever info is unique to that particular event and not shared by all events of that type.
  3. The level data file just needs to include that information.
  4. When a level loads, it reads that information, then creates all of the objects it needs using that info as a guide. One level might have 5 Wave objects and another might have 1 or 0, but all levels will, when they load, create a wave for each one specified in the data, using the information in the data (start time, list of enemies to create when the wave starts); create a list of waves (maybe sorted by when they’re supposed to show up); and add each wave to that list.

[quote]Thank you by the way everyone for the help/advice.
[/quote]
No problem! Feel free to click the appreciate/medal button on anyone’s posts that you, well, appreciated.

Just because I have nothing else to do right now :slight_smile: and I am feeling like it, I am trying to explain what by-reference usually means in languages that support that feature (unlike Java, that is!).

Even if you do not know C++, I’ll use the following example, because C++'s syntax is very close to Java. In the following example a value of the primitive ‘int’ type is used as an actual argument to a function with by-reference semantics:


void refFunction(int& calleeA) {
  calleeA = 2; // <- change the value of the original variable
}
int main() {
  int callerA = 1;
  refFunction(callerA); // <- call that function
  // here, callerA would be 2 !!!!
}

Explanation follows, but first another example.
This example uses a heap-allocated (what Java also would normally do) instance of MyClass:


void refFunction(MyClass*& calleeObject) {
  calleeObject = new MyClass(2);
}
int main() {
  MyClass* callerObject = new MyClass(1);
  refFunction(callerObject);
  // here, callerObject would now point to a MyClass instance with the 2 !!!!
  // So, the original value that callerObject had before the call would now be lost and
  // (in C++) we would now have a memory leak.
}

THIS is what by-reference means. It means that a function/method call can actually change the value/object that a variable (and ONLY a variable) holds on to at the caller side.
So the variable, when used as an actual function call argument, will not be “copied” before the call is made, but rather “referenced.”
Technically for C++ this is solved by actually having the function parameter holding the address of a variable whose value the function can then change. This is not to be confused with the address of an “object” that this variable might hold.
It is the address of the “variable” itself (i.e. the value container/holder) living in the caller scope which is passed to the function!
This is also the reason why by-reference only works when you use an actual variable as argument, and not some “expression” which eventually evaluates to some value/object which you then would pass to the function. This is because by-reference needs the address of a variable that it can reference. And an expression, other than a single variable, has no address.

This all is not possible with Java, because as many others have said rightly, Java ONLY has by-value call semantics!
So, in Java, whenever we pass an instance of a reference type (i.e. a class) to a method as an actual argument, internally, the JVM passes “some sort of” an address (called the “ordinary object pointer”) to be used by the called method.
This address is a “value” itself and is copied, and more importantly is NOT the address of a caller-side variable, but the address of an object. That’s why we say that Java always uses by-value, even for parameters of a reference type.
But this is the address of the object and NOT the address of the variable on the caller side holding onto that object!

I know, this is quite complicated because there is so many indirections involved, but this is how it works.

Regarding whether you should use a homebrew physics library or an existing one: I depends on what you want to achieve. If you want a working solution fast, use an existing library. If you want to know how to do it yourself and are willing to spend some months or even years to obtain that knowledge and put it to use, which can also be a viable way to go, because you will learn a whole lot, then make a library of your own (or incorporate that in your game). But this way will be full of frustration, time-consuming, but in the end even more rewarding.

A lot of discussion has passed, but just to clarify a couple points:

[quote]Thus why I said putting Level.objectlist… cause I thought Jesse said I should use a Level class for every level.
[/quote]
More specifically, an instance of a Level class. You actually could just use a Level class and make everything static if you wanted, although that’s generally discouraged for at least a few reasons.

[quote]Maybe I’m just being a huge derp, but if I pass the level to each creature, that’s just a copy.
[/quote]
As has been discussed, it’s not a copy. Maybe that’s what’s been hanging you up. In any case, if you’re clear now that it’s actually a reference you’re passing and not a copy, maybe that will resolve some of the issues you were having.

Ya I’m a derp. I just need to look into JBox2D for collision, and that may work out even better.

I’m gonna stay away from static variables from now on xD.

Thanks for the help though Jesse.