Override method not being called

Hi everyone, I have two methods for using a pressure plate to activate effects on another object. The first script is a component on the pressure plate, and waits for an allowed trigger object to touch it in order to call TriggerEffect(). The idea is that TriggerEffect() can be overridden in order to produce new effects, however the method TriggerEffect() in the second script below is not overriding the base method. Unity says that the pressure plate is indeed being triggered, but the override method is not being called. Why is this?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PressureTrigger : MonoBehaviour
{
    // VARIABLES
    public GameObject target; // target object for pressure plate effect
    public GameObject trigger; // trigger object for pressure plate effect

    // used for all pressure plate interactions
    public virtual void TriggerEffect()
    {
        // This method is meant to be overriden when coding different interactions
    }

    // detect if object is on pressure plate
    private void OnTriggerEnter(Collider other)
    {
        if (other.GetType() != typeof(SphereCollider))
        {
            // trigger effect when collding object matches parameters
            if (other.name == trigger.name)
            {
                Debug.Log("Triggered");
                TriggerEffect();
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TriggerMove : PressureTrigger
{
    // VARIABLES
    public Vector3 wishPosition; // desired position
    public float speed; // speed to reach desired position

    // overrides TriggerEffect() in PressureTrigger
    public override void TriggerEffect()
    {
        Debug.Log("Called");
        target.transform.position = wishPosition;
    }
}

I should clarify that the second script, which overrides the TriggerEffect() method, is attached to the object I want the pressure plate to influence, though that shouldn’t really change anything :frowning:

I suspect it’s because reflection is being used to fire the OnTriggerEnter method (as it is for all “magic methods” in Unity, like Awake, Start, etc), and the method is defined on the base type but not the derived type. I would still expect the override for TriggerEffect to be called honestly, so this is a bit surprising- I may have known about this limitation at some point, and just forgot about it since I use MonoBehaviours for very little anymore.

If you want to force it to work, you can probably set OnTriggerEnter itself to protected virtual, and override it in the derived type just calling base.OnTriggerEnter() in the function body so you’re not repeating yourself. Then reflection will call the OnTriggerEnter method in the derived type, the object’s class would be set properly, and the override should be called for TriggerEffect. Copying the private OnTriggerEnter method into the derived type would also work- those reflection calls are essentially like having automatic overrides, so if it exists in the derived type, the base type method won’t get called anyways, but then you have a copy of the function logic in two places, which is annoying.

Alternatively, you may be able to set TriggerEffect to abstract instead of virtual, and force it to register that it doesn’t exist on the base type (I give that a decent chance of working, but it’s sort of hack-ish- it may also cause an error). Then PressureTrigger would need to be abstract as well though, and you wouldn’t be able to use it as a Component, so it’s only an option if that’s not an issue.

Have you put a Debug.Log statement in the base class to make sure that the base version of TriggerEffect is really being called? Without knowing more, I’d have to assume the OnTriggerEnter just isn’t firing, or the other.name == trigger.name is false, or something else. The override behavior you’re describing should work fine.

Why the hell Unity changes how c# works? This stuff should be written in the documentation, I’ve been spending hours trying to understand why the overridden method wasn’t being called by the LateUpdate function.
I don’t have a solution for this and I really need the overriding behaviour for my code to work. Does anyone know any workaround? Setting the base class abstract is not an option for me.
I’m using Unity 2019.3.2f1

I’m not sure why you’re having any problems with this. I just took a few minutes to test this out, and the override behavior works fine. Here are the scripts, simplified down:

public class PressureTrigger : MonoBehaviour
{
    public virtual void TriggerEffect()
    {
        Debug.Log("This is the base class");
    }

    // detect if object is on pressure plate
    private void OnTriggerEnter(Collider other)
    {
        TriggerEffect();
    }
}
public class TriggerMove : PressureTrigger
{
    public override void TriggerEffect()
    {
        Debug.Log("This is the sub-class");
    }
}

Attaching the TriggerMove component to a trigger collider, and then walking into the trigger, the only logging I get is “This is the sub-class”. So, for me this works fine.

If you try out this code in a brand new project, does it work properly? Are you maybe using IL2CPP, or some other .NET platform in this project?

Hi dgoyette, thanks for the reply.
I already tried the code you proposed and it actually works fine.
I just found the problem, which is a particular thing of C# that I wasn’t aware of.
In my code I wrote:

var object = GetComponent<FatherClass>();
object.Hello();

As I used “var” C# didn’t cast the object to the ChildClass, so the Hello() will print the parent name.
This is easily fixable replacing “var” with “FatherClass”.

The overriding logic works fine in Unity!

That still doesn’t make sense.

First, using ‘var’ has no effect on the behavior of an object. ‘var’ is purely a bit of syntactic sugar. There is no difference between var object = GetComponent<FatherClass>(); and FatherClass object = GetComponent<FatherClass>();. Just mouse over the ‘var’ in Visual Studio, and it will show you what class it’s using.

Second, even if you cast an object to its base class, as you’re doing here, that won’t change its runtime behavior. Consider these two methods:

public class BaseClass : MonoBehaviour
{
    public virtual void TheVirtualMethod()
    {
        Debug.Log("This is the base class");
    }

    public void Hello()
    {
        TheVirtualMethod();
    }
}
public class SubClass : BaseClass
{
    public override void TheVirtualMethod()
    {
        Debug.Log("This is the child class");
    }
}

Now, I added a “SubClass” component to my game object, and ran the following method:

public void ABC()
{
    var thing = this.gameObject.GetComponent<BaseClass>();
    thing.Hello();
}

Running that code prints “This is the child class”. The same is true if, instead, I use BaseClass thing = this.gameObject.GetComponent<BaseClass>();

So, the behavior you’re describing just doesn’t make sense to me, unless you’ve simplified your example, and you’re actually doing something more complicated.

1 Like

Hello dgoyette,
I didn’t simplify my example, my implementation was very minimal.
Changing var into BaseClass fixed it immediately.
Don’t know what’s happening under the hood, but it looks like var is not casting the object.

I’m happy to be proven wrong, but to my knowledge, if a sub-class overrides a base class’s method, there’s no way to call the base class’s implementation of that object if you have an instance of the sub-class. It doesn’t matter whether you cast the object as the base class; the sub-class implementation will still be called.

Note: Obviously the sub-class method itself can call the base implementation from within the method, but to someone just having an instance of the object, they can only call the sub-class’s implementation.

Anyway, I’d be interested in seeing the code the way you’ve fixed it, because the way you describe it, it’s doing something impossible. Glad it’s working, but I suspect something else is going on. Or I have something to learn.

1 Like

Maybe Unity Editor didn’t compiled your changes with the override method ?
And changing the code made it compile everything ?

I disabled auto-refresh and it happens sometime. Have to hit ctrl+r to compile to the last version.

1 Like

Hey i had the same problem and ended up copying your code for testing but it writes “this is the base class”. Im kinda confused.