开发者

MessagingSystem causes a NullReferenceException

开发者 https://www.devze.com 2023-04-12 15:09 出处:网络
I decided to implement a simple messaging system into my project. I\'m using this one: CSharpMessenger Extended (it\'s implemented with static methods).

I decided to implement a simple messaging system into my project. I'm using this one: CSharpMessenger Extended (it's implemented with static methods).

It's very strange that when I call a method directly everything is working correctly. But when I broadcast a message with the messaging system I get a NullReferenceException on some of the game objects. To my surprise adding the line if (_gameObject == null) return; solves the problem. However it's not an option to add a check if the object is null to 开发者_JS百科every place where I get this exception.

What might be the problem?

Here's my code for broadcasting a message:

public class Head : MonoBehaviour {

    public Snake snake;

    void OnControllerColliderHit (ControllerColliderHit hit)
    {
        if ( hit.gameObject.GetComponent<Terrain>() )
            return;

            //This way everything was working without any surprises.
            //snake.PropCollected( hit.gameObject.GetComponent<Prop>() );
            //Using messaging system instead
        if ( hit.gameObject.GetComponent<Prop>() )
            Messenger<Prop>.Broadcast( "prop collected", hit.gameObject.GetComponent<Prop>() );
            Destroy(hit.gameObject);

        }
    }

Here's how I subscribe to the event and respond to it:

public class Snake : MonoBehaviour {

    public GameObject headBlock;

    public GameObject snakeBlocks;

    int lastSnakeBlockId;

    private GameObject FindBlockWithId( int _id )
    {
            if (!snakeBlocks) return null;    //This line somehow solves the problem; However the object is 100% assigned in the editor.

            foreach (Transform child in snakeBlocks.transform) {
                if (child.gameObject.GetComponent<SnakeBlockScript>().blockId == _id)
                {
                    return child.gameObject;
                }
            }

        return headBlock;
    }

    void Awake()
    {
        //Set up message listeners
        Messenger<Prop>.AddListener("prop collected", AddBlock);    
    }

    public void AddBlock(Prop _prop)
    {
        GameObject lastBlock = FindBlockWithId(lastSnakeBlockId - 1);
        if (!lastBlock) return;

        //Some more code
        //...
    }
}

Thank you!


It sounds like you have a condition where "snakeBlocks" is re-initialized somewhere else in the application, and this thread happens to hit occasionally during that reference being set to something else.

Something Like:

snakeBlocks = null;

//Do some stuff.

snakeBlocks = someNewInstanceOfGameObject;

Just a thought.


First guess is that you're initializing multiple snakes, all of which are (accidentally?) getting lengthened whenever one of them catches something.

Since that init code and the constructor for Snake were not provided, I can't do much better than suggest that you initialize snakeBlocks to the equivalent of an empty collection rather than null.

Or that you don't create Snake objects that are not immediately going into play.


I note that, in the code you commented out that you say works, you are passing the Prop to the PropCollected method of Snake whereas, in the code you say does not work, you are passing it to the Snake class's AddBlock method. Perhaps this is your bug and it has nothing to do with the messaging system?


I'm not an unity expert, but if you google around "MonoBehaviour NullReferenceException", you will find a number of articles that seem to indicate this is related to Unity and the MonoBehavior class.

I believe you're trying to access a class before it is really created by Unity. Try to move all the code into Start() instead of Awake(), directly or indirectly.


You may have a race condition because you fetch the GetComponent twice, once to check for null and once to actually broadcast the message. That means if the object is removed between the two getters, you could be broadcasting null. I recommend you store a single get in a temporary and do the null check and the broadcast on the temporary variable. Make sense?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号