3rd-person-combat: Extending state machine for OnCollision callbacks

Hi folks,

I’m using the state machine setup from the 3rd person combat tutorial for a 2D platformer to try and take some of the implementation over to another game I’m working on.

So far, everything seems to be working fine, but I can’t get OnCollisionEnter2D events firing inside states, even if they fire properly if not in a state machine implementation (literally copy-pasting the OnCollisionEnter2D code over)

Can anyone point me in the right direction for where I may be missing things? Is there some special way of referencing OnCollisionEnter2D in a state that I need to do, perhaps?

It SEEMS like it’s not a case of having collisions register or be set up properly, since I have a non-statemachined implementation of collisions running fine (in an alternate script I can toggle off) and looking at the debug information on the Collider, it’s registering a contact.

is it marked as Trigger?

This will not work. The Unity messages - which OnCollisionEnter2D is - are only called on MonoBehaviour. State is not a MonoBehaviour. You will either need to ‘relay’ the event to the state, or have some other way of doing it.

In the past I have created a CollisionDetector script that is somewhat similar to the ForceReceiver or InputReader scripts from the 3rd person course. It’s just a script that will fire an event. Something like

public class CollisionDetector : MonoBehaviour
{
    public event EventHandler<Collision2D> CollisionEnter;
    private void OnCollisionEnter2D(Collision2D collision)
    {
        // Fire the event with the provided collision data
        CollisionEnter?.Invoke(this, collision);
    }
}

You would then reference this in the same way you do ForceReceiver or InputReader and in the states that care about collisions’ Enter() and Exit() you can hook and unhook the event.

Another option is this; since the StateMachine is in fact a MonoBehaviour you could add OnCollisionEnter2D there, and just call the method on the current state in the same way you call Tick in Update().

private void OnCollisionEnter2D(Collsion2D collision)
{
    _currentState?.OnCollisionEnter2D(collision);
}

This would reuse the code you already have. Personally this is not the way I would do it.

There are more ways to do this, but this is the simplest ones I can think of right now.

1 Like

Amazing - I knew I was missing something conceptually about the way the statemachines were set up.

And, I think I get why avoid using StateMachine for it (since… well, it would get really messy and more or less un-state-like to be using that for collision callbacks and just get the usual issues)

Thanks, this makes a lot of sense to me! And, I’ll even have the references for the ForceReciever and InputReaderto subscribe to events or something similar.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.