MessagingSystem вызывает исключение NullReferenceException - PullRequest
4 голосов
/ 13 октября 2011

Я решил внедрить в свой проект простую систему обмена сообщениями. Я использую это: CSharpMessenger Extended (реализовано статическими методами).

Очень странно, что когда я вызываю метод напрямую, все работает правильно. Но когда я передаю сообщение с системой обмена сообщениями, я получаю исключение NullReferenceException для некоторых игровых объектов. К моему удивлению, добавление строки if (_gameObject == null) return; решает проблему. Однако нельзя добавить проверку, является ли объект нулевым, для каждого места, где я получаю это исключение.

В чем может быть проблема?

Вот мой код для трансляции сообщения:

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);

        }
    }

Вот как я подписываюсь на событие и отвечаю на него:

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
        //...
    }
}

Спасибо!

Ответы [ 5 ]

2 голосов
/ 28 октября 2011

Похоже, что у вас есть условие, при котором «snakeBlocks» переинициализируется где-то еще в приложении, и этот поток случайно попадает во время установки этой ссылки на другое значение.1003 *

snakeBlocks = null;

//Do some stuff.

snakeBlocks = someNewInstanceOfGameObject;

Просто мысль.

1 голос
/ 01 ноября 2011

Я не эксперт по единству, но если вы заглянете в «MonoBehaviour NullReferenceException», вы найдете ряд статей, которые, кажется, указывают, что это связано с Unity и MonoBehavior классом.

Я полагаю, что вы пытаетесь получить доступ к классу до того, как он действительно будет создан Unity. Попробуйте переместить весь код в Start () вместо Awake (), прямо или косвенно.

1 голос
/ 01 ноября 2011

Я отмечаю, что в коде, который вы закомментировали, что вы говорите, работает, вы передаете Prop методу PropCollected в Snake, тогда как в коде, который вы говорите, не работает, вы передаете его методу AddBlock класса Snake,Возможно, это ваша ошибка, и она не имеет ничего общего с системой обмена сообщениями?

1 голос
/ 27 октября 2011

Первое предположение: вы инициализируете несколько змей, каждый из которых (случайно?) Удлиняется, когда один из них что-то ловит.

Так как этот код инициализации и конструктор для Snake не были предоставлены, я не могу сделать намного лучше, чем предложить инициализировать snakeBlocks эквивалентом пустой коллекции, а не нулевым.

Или что вы не создаете объекты Snake, которые не сразу вступают в игру.

0 голосов
/ 01 ноября 2011

Возможно, у вас есть состояние гонки, потому что вы получаете GetComponent дважды, один раз для проверки на ноль и один раз для фактической трансляции сообщения. Это означает, что если объект удален между двумя получателями, вы можете передавать ноль. Я рекомендую вам сохранить один раз во временном хранилище и выполнить нулевую проверку и трансляцию во временной переменной. Имеет смысл?

...