#How to prevent MissedReferenceException when dealing with multiple objects being assigned to value?

1 messages · Page 1 of 1 (latest)

slender laurel
#

Just some pre-info, some code was made by AI, so I understand the reluctance to help. Don't treat it as me wanting to debug it, though, since it was for a game jam that has just concluded and I want to learn what to do in the future.

In our game, player could possess any bot in the game. To do that, I made all bots use an interface with their own move, fire, etc. methods. Then the player controller would have an instance of this interface declared, and its methods would fire the instance's methods. Pseudocode time:

  void Move();
}```
```public class Bot : MonoBehaviour, IControllable{
  public void Move(){
    Debug.Log(name+" moves");
  }
 }```
```public class PlayerController : MonoBehaviour{
  public IControllable currentControllable;
  
  public OnKeyPress(){
    currentControllable.Move();
  }
}```

Then another system would choose the controllables for the player by just doing GetComponent<IControllable>(). If the Bot was to die, then a script would find another living one and become the player's currentControllable. The problem is that while playtesting we found a lot of null errors, mostly MissedReferenceException and NullReferenceException. Common situations were:
- Deleting multiple bots (i.e. in-game bomb calling Destroy() in a foreach loop for each bot)
- Two only bots on the map dying at the same time (even if we made sure that before the last one is deleted, a new one would be instantiated to prevent there being an empty map)

We managed to just obscure the errors because they tended to happen after player finishes a game, however no matter how many `PlayerController.currentControllable != null` I put, the code would still try to access it and throw the damned null errors. The PlayerController script was never in any of the spawned Bots, so it's not like it was being destroyed.

I just want to know if there is a better way to safeguard against these errors. We're talking about a system where bots with this system are instantiated dynamically, with a system listing them by updating its list through a FindObjectsByType().

Sorry if I don't happen to make much sense :c
jade isle
#

Well the main problem you had was that since you were using an interface, you didn't get Unity's "fake null" comparison that detects destroyed objects

#

that means your object wasn't actually null in the C# sense but it was destroyed in the Unity sense.

#

normally if you have a reference to a UnityEngine.Object derived class, Unity does a special comparison with null that cehcks for destroyed objects

#

when using an interface, the compiler doesn't know it's a Unity object so you don't get that automatically

#
GitHub

Unity C# reference source code. Contribute to Unity-Technologies/UnityCsReference development by creating an account on GitHub.

#

Long story short if you want to avoid the MissingReferenceExceptions and be able to check for destroyed objects when using an interface you have to do something like this:

if (((UnityEngine.Object)currentControllable) == null) {
  // The object has been destroyed
}```
slender laurel
jade isle
#

the other way around this would have been to put your own alive/dead check in the interface directly

slender laurel
jade isle
#

and then you wouldn't have to worry about Unity's destroyed stuff

jade isle
#

you'd get a MissingReferenceException when you try to do currentControllable.gameObject

#

because you can't access the .gameObject property on a destroyed object

slender laurel
#

yikes.. and here I kept using it when trying to get to the bot's other components like the health script..

#

currentControllable.gameObject.GetComponent<SomeOtherScript>();
even I can tell it looks like code gore :D

jade isle
#

bool alive = currentControllable as UnityEngine.Object != null; would be another way

slender laurel
jade isle
#

object meaning the C# concept of object here

#

(everything in C# is an object)

slender laurel
jade isle
#

that wouldn't compile

#

UnityEngine.Object doesn't have a GetComponent method

jade isle
#

a better architecture would have avoided that need in the first place

slender laurel
#

Yeah, I know that, offline game jams and AI make for bad bedfellows