Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on March 30, 2023, between 5 am & 1 pm EST, in the Performance Profiling Dev Blitz Day 2023 - Q&A forum and Discord where you can connect with our teams behind the Memory and CPU Profilers.
    Dismiss Notice

Resolved Making a trigger for an icicle to drop

Discussion in 'Scripting' started by BrownBrew, Mar 19, 2023.

  1. BrownBrew

    BrownBrew

    Joined:
    Jan 6, 2023
    Posts:
    8
    Hello. I'm having a problem with seemingly a very simple task.

    I have an icicle that contains a trigger object and a damagebox object.
    2.jpg
    Trigger has a static rigidbody, a boxcollider2d and a script that is supposed to run a method of a IBasicTriggerable object (in this instance - make the icicle drop on the player)
    Code (CSharp):
    1. public class BasicTrigger : MonoBehaviour
    2. {
    3.     [SerializeField] private Object _object;
    4.  
    5.     private void OnTriggerEnter2D(Collider2D collision)
    6.     {
    7.         (_object as IBasicTriggerable).BasicTriggerEvent();
    8.     }
    9. }
    I drag n drop the Icicle object in the inspector
    4.jpg
    (Icicle itself has the IBasicTriggerable interface and the code to trigger the drop)
    But it gives me the nullreference error on collission proc:
    3.jpg
    I also tried to use UnityEvents and dragndrop the Icicle to call it's Drop method (the UnityEvent was on the child trigger object), but it gives me the same NullReferenceException.
    5.jpg
    Seems like there's something I fundamentally don't understand here.
    I also want to mention that I understand this is a really weird way to implement a trigger when you can easilly do this by just adding a boxcollider2d set as trigger on the icicle itself. But I want to understand how to do it this way exactly - by referencing an object on the trigger.
    Please help! Thank you in advance!
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    4,020
    You've probably referenced
    _object
    via it's game object, which mean it will never be
    IBasicTriggerable
    . When you cast with
    as
    , if the cast is invalid, you will be given
    null
    instead.

    You'll want to make sure you reference it via the component, though I believe that will be cumbersome with Unity's default inspectors. Probably easier to use
    TryGetComponent
    for the interface type instead.
     
    BrownBrew and Bunny83 like this.
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    2,894
    Right. When you just drag an object from the hierarchy into a serialized slot in the inspector, the Unity editor will actually drag the GameObject instance around. The editor is clever enough to detect component types when the field you try to assign a value to is a component. So dragging a GameObject onto a component field means the Unity editor searches for this component type on the dragged gameobject. So it tries to assign the dragged object and if it's not compatible it tries to use GetComponent of the field type. Since the field here is a UnityEngine.Object, any class that is derived from UntiyEngine.Object can be assigned to that field. So when you just drag an object, you would assign a GameObject.

    As it was mentioned, you can actually drag specific component instances as well. However it would require you to open two inspectors, lock one of them so you can actually grab the component header bar and drag that into the slot. In this case the object you're dragging is the actual component and not just the GameObject.

    I once made this SerializableInterface which may be useful in such cases. It also just stores a UnityEngine.Object (which can be a component or ScriptableObject instance) and does lazily convert the serialized UnityEngine.Object into the actual interface type. The property drawer actually filters out an appropriate instance. If more than one component exist on the dragged gameobject, it displays a drop down menu which lets you select one of the matching instances.

    edit

    So you could implement your BasicTrigger class like this:

    Code (CSharp):
    1.     public class BasicTrigger : MonoBehaviour
    2.     {
    3.         [SerializeField] private SerializableInterface<IBasicTriggerable> _target;
    4.    
    5.         private void OnTriggerEnter2D(Collider2D collision)
    6.         {
    7.             _target.Instance.BasicTriggerEvent();
    8.         }
    9.     }
     
    BrownBrew and spiney199 like this.
  4. BrownBrew

    BrownBrew

    Joined:
    Jan 6, 2023
    Posts:
    8
    Thank you guys. I'm also a complete idiot and the nullreference was caused by the method in the icicle, not the trigger, so it works perfectly with a UnityEvent as well.