Monday, March 20, 2017

How to decide which GameObject should handle the collision?


In any collision, there are two GameObjects involved right? What I want to know is, How do I decide which object should contain my OnCollision*?


As an example, let's suppose I have a Player object and a Spike object. My first thought is to put a script on the player that contains some code like this:


OnCollisionEnter(Collision coll) {
if (coll.gameObject.compareTag("Spike")) {

Destroy(gameObject);
}
}

Of course, the exact same functionality can be achieved by instead having a script on the Spike object that contains code like this:


OnCollisionEnter(Collision coll) {
if (coll.gameObject.compareTag("Player")) {
Destroy(coll.gameObject);
}
}


Whilst both are valid, it made more sense to me to have the script on the Player because, in this case, when the collision happens, an action is being performed on the Player.


However, what's making me doubt this is that in future you may want to add more objects that will kill the Player on collision, such as an Enemy, Lava, Laser Beam, etc. These objects will likely have different tags. So then the script on the Player would become:


OnCollisionEnter(Collision coll) {
GameObject other = coll.gameObject;
if (other.compareTag("Spike") || other.compareTag("Lava") || other.compareTag("Enemy")) {
Destroy(gameObject);
}
}


Whereas, in the case where the script was on the Spike, all you would have to do is add that same script to all the other objects that can kill the Player and name the script something like KillPlayerOnContact.


Also, if you have a a collision between the Player and an Enemy, then you likely want to perform an action on both. So in that case, which object should handle the collision? Or should both handle the collision and perform different actions?


I have never built a game of any reasonable size before and I'm wondering if the code can become messy and difficult to maintain as it grows if you get this sort of thing wrong in the beginning. Or maybe all ways are valid and it doesn't really matter?




Any insight is much appreciated! Thank you for your time :)



Answer



I personally prefer to architect systems such that neither object involved in a collision handles it, and instead some collision-handling proxy gets to handle it with a callback like HandleCollisionBetween(GameObject A, GameObject B). That way I don't have to think about what logic should be where.


If that's not an option, such when you're not in control of the collision-response architecture, things get a bit fuzzy. Generally the answer is "it depends."


Since both objects will get collision callbacks, I'd put code in both, but only code that is relevant to that object's role in the game world, while also trying to maintain extensibility as much as possible. This means if some logic makes equal sense in either object, prefer to put it in the object that will likely lead to fewer code changes in the long run as new functionality is added.


Put another way, between any two object types that can collide, one of those object types generally has the same effect on more object types than the other. Putting code for that effect in the type that affects more other types means less maintenance in the long run.



For example, a player object and a bullet object. Arguably, "taking damage on collision with bullets" makes logical sense as part of the player. "Applying damage to the thing it hits" makes logical sense as part of the bullet. However, a bullet is likely to apply damage to more different types of objects than a player (in most games). A player won't suffer damage from terrain blocks or NPCs, but a bullet still might apply damage to those. So I'd prefer to put the collision handling for imparting damage into the bullet, in that case.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...