1

The Built-in eventsystem for unity UI keeps trying to access a button after I have used Destroy() on its gameobject. it stops and doesn't start again when I pause but will continue every frame otherwise. the object is just the right click-> UI -> button - text mesh pro. The following is the function the button executes and the function to make the button (in that order)

    public void makeProgram(int i, Button button)
    {
        GameObject obj = Instantiate(ProgramObject, programHolder);
        programs.Add(obj.GetComponent<Program>());
        obj.GetComponent<Program>().gameManager = this;
        obj.GetComponent<RectTransform>().localPosition = button.transform.localPosition;
        Destroy (button.gameObject);
    }
    public void makeButton(int i)
    {
        Button button = Instantiate(ProgramBuyButton, programHolder)
        .GetComponent<Button>();
        button.name = i+"";
        button.GetComponent<RectTransform>().localPosition = Tools.makeProgramPosition(i - 1);
        button.onClick.AddListener(() => makeProgram(i, button));
    }

The error references InputSystemUIInputModule:476, which is the second line in the following code.

            // now issue the enter call up to but not including the common root
            Transform oldPointerEnter = eventData.pointerEnter?.transform;
            eventData.pointerEnter = currentPointerTarget;

The problem with this is that it stops the user from interacting with any other UI objects. The error is:

Your script should either check if it is null or you should not destroy the object.
UnityEngine.Object+MarshalledUnityObject.TryThrowEditorNullExceptionObject (UnityEngine.Object unityObj, System.String parameterName) (at <adbae017f0374fce9921b97a33a4e8ca>:0)
UnityEngine.Bindings.ThrowHelper.ThrowNullReferenceException (System.Object obj) (at <adbae017f0374fce9921b97a33a4e8ca>:0)
UnityEngine.GameObject.get_transform () (at <adbae017f0374fce9921b97a33a4e8ca>:0)
UnityEngine.InputSystem.UI.InputSystemUIInputModule.ProcessPointerMovement (UnityEngine.InputSystem.UI.ExtendedPointerEventData eventData, UnityEngine.GameObject currentPointerTarget) (at ./Library/PackageCache/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs:476)
UnityEngine.InputSystem.UI.InputSystemUIInputModule.ProcessPointerMovement (UnityEngine.InputSystem.UI.PointerModel& pointer, UnityEngine.InputSystem.UI.ExtendedPointerEventData eventData) (at ./Library/PackageCache/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs:402)
UnityEngine.InputSystem.UI.InputSystemUIInputModule.ProcessPointer (UnityEngine.InputSystem.UI.PointerModel& state) (at ./Library/PackageCache/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs:352)
UnityEngine.InputSystem.UI.InputSystemUIInputModule.Process () (at ./Library/PackageCache/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs:2257)
UnityEngine.EventSystems.EventSystem.Update () (at ./Library/PackageCache/com.unity.ugui/Runtime/UGUI/EventSystem/EventSystem.cs:530)

I have tried to find a way to "safely" destroy the button but i cant find any that relate to the eventsystem, I feel like moving it away from the cursor and using a coroutine to destroy it after a little would (edit: I tested it and it does, but still would like a nicer solution) work but also wouldnt be the most elegant and I wish to find a better way to deal with this. Thank you for reading and I hope that there is a better resolution for this.

3
  • 1
    Quickly edit your question to include the Pastebin error. We dont like having to view other sites when you could have just included it here. Commented Oct 24, 2024 at 6:22
  • Why do you Destroy(button.gameobject)? Commented Oct 24, 2024 at 6:28
  • @Raildex the button is in the place of a "program" (pretty much a box with text and a progress bar) and I want to remove the button and replace it with the program. Sorry if I misunderstood your question and if so please elaborate. Commented Oct 24, 2024 at 6:34

1 Answer 1

2

Sounds like they tricked themselves when implementing the InputSystemUIInputModule!

eventData.pointerEnter is of type GameObject which is a UnityEngine.Object. You can read the details here (Why does C# null-conditional operator not work with Unity serializable variables?) but in short:

You can't/shouldn't use the ?. (nor ?? and !.) operator on anything derived from UnityEngine.Object because Unity has their own custom == null check override which operates on the native c++ engine basis. However, the ?. (and related) operator works on a pure System.Object level and bypasses their custom check.

=> This check

eventData.pointerEnter?.transform

is invalid! The c# level System.Object is not null at this point - which is actually also the reason why you are getting a custom MissingReferenceException including the information that you destroyed the object, rather than just the normal NullReferenceException.

At this point the object is only destroyed on the c++ engine level and therefore their custom operator returns true for == null, but when exactly the c# level System.Object for this instance is actually GC collected you can't tell, usually at least not during the current frame!


Long story short, you either customize that line in the source code (if possible)

Transform oldPointerEnter = eventData.pointerEnter != null ? eventData.pointerEnter.transform : null;

which now works on the UnityEngine.Object level and properly uses their custom == operator.


Alternatively a simple workaround without requiring touching the source code or a Coroutine might be to use the delay parameter of Destroy and do e.g.

button.gameObject.SetActive(false); 
Destroy(button.gameObject, 1);

This will only deactivate the button and destroy it after 1 second.

One second is probably overkill but just to be sure

Sign up to request clarification or add additional context in comments.

1 Comment

your first solution worked, thank you so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.