Unity Game Engine has this nice methods to detect collisions:
All of them take a Collision object in order to implement logic on all of those cases. To implement those methods, I take a collidable object (AKA Player) and "listen" to it's collisions to implement some logic. Example:
public class PlayerController : MonoBehaviour
{
...
private void OnCollisionEnter(Collision collision)
{
Debug.Log("Colission detected with object");
}
...
}
However, there are some problems that may require the use of nested switch cases (ugly) or perhaps some Polymorphism or Dictionary - Delegates or something else.
First problem: The player can collide with whatever object in existence or to be created.
The collision's "state" can be either "enter" or "stay" or "exit"; therefore, I need to be able to manage 3 "states" times x amount of "objects" to collide with.
In order to "reference" the "collided with" GameObject Unity advices something AWFUL: To reference an object by it's "TAG" or "NAME":
private void OnCollisionEnter(Collision collision){
if (collision.gameObject.tag == "Ball"){
Debug.Log("Player collided with an object with TAG 'Ball'");
}
}
Please imagine when I'm thinking of implementing the 3 states (enter, stay, exit) for 30 objects. Switch/cases or nested ifs will become a nightmare and break all good code conventions.
The reason I'm doing this this is because I want some sort of "Event Listener" that I don't know how to implement in C# where:
public class PlayerController : MonoBehaviour
{
...
private enum CollisionState { ENTER, STAY, EXIT }
private enum CollisionableGameObject { COUNTER, SINK }
private Dictionary<CollisionableGameObject, Func<CollisionState, Collision, bool>> collisionEvent;
private void Start()
{
this.collisionEvent = new Dictionary<CollisionableGameObject, Func<CollisionState, Collision, bool>>
{
[CollisionableGameObject.COUNTER] = new Func<CollisionState, Collision, bool>(CollideCounter),
[CollisionableGameObject.SINK] = new Func<CollisionState, Collision, bool>(CollideSink)
};
}
private void OnCollisionEnter(Collision collision)
{
this.CollisionManager(collision, CollisionState.ENTER);
if (collision.gameObject.TryGetComponent(out ClearCounterController clearCounter))
{
Debug.Log("Colission detected with clear counter");
}
}
private void CollisionManager(Collision collision, CollisionState state)
{
if (this.collisionEvent.TryGetValue("")) {
//BY THIS POINT NO IDEA WHAT AM I DOING
}
}
private bool CollideCounter(CollisionState state, Collision collision)
{
return true;
}
First time using Dictionaries and delegates and now I don't even understand my own code. Perhaps I'm adding over complexity in trying to archive good programming practices. But since I'm new to Unity and C#, I know what I need but no idea how to do it and entry level unity tutorials make my eyes bleed.
If there is out there any Senior Engineers with C# experience, I'd love your opinion guys.
Thanks a lot in advance.
You do not have to save object's collision state. All of three collider detection functions can be called at same time and multiple times. You just need to try get component as you did in the your code.
But this comes with an issue like you said; lots of if controls. You shouldn't control 30 objects with that way. But you can control an interface.
For example create an interface named "ICollideable"
public interface ICollideable{
public void OnCollide();
}
And try to get ICollideable interface in your PlayerController class. Then call OnCollide function.
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.TryGetComponent(out ICollideable collideable))
{
collideable.OnCollide();
}
}
Don't forget to implement our interface to your classes.
public class ClearCounterController : ICollideable{
public void OnCollide(){
// Do whatever you want here.
}
}
You can create stay and exit functions too with this way.