Почему GameObject.GetComponent<T>() возвращает null, Unity 2018

157
22 июня 2019, 18:50

Unity выдает сразу 2 ошибки:

NullReferenceException: Object reference not set to an instance of an object
TreeTile.StartUp (Vector3Int position, UnityEngine.Tilemaps.ITilemap tilemap, UnityEngine.GameObject go) (at Assets/Scripts/TileScripts/TreeTile.cs:12)
Error running StartUp for Tile.NullReferenceException: Object reference not set to an instance of an object
TreeTile.StartUp (Vector3Int position, UnityEngine.Tilemaps.ITilemap tilemap, UnityEngine.GameObject go) (at Assets/Scripts/TileScripts/TreeTile.cs:12)

которые указывают на строку

    go.GetComponent<SpriteRenderer>().sorting = -position.y * 2;

Понимаю, что где-то ссылаюсь на null, но где - понять не могу.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.Tilemaps;
[RequireComponent(typeof(SpriteRenderer))]
public class TreeTile : Tile
{
    public override bool StartUp(Vector3Int position, ITilemap tilemap, GameObject go)
    {
        go.GetComponent<SpriteRenderer>().sortingOrder = -position.y * 2;
        return base.StartUp(position, tilemap, go);
    }
#if UNITY_EDITOR
    [MenuItem("Assets/Create/Tiles/Treetile")]
    public static void CreateTreetile()
    {
        string path = EditorUtility.SaveFilePanelInProject("Save Treetile", "New Treetile", "asset", "Save Treetile", "Assets");
        if (path == "")
        {
            return;
        }
        AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<TreeTile>(), path);
    }
#endif
}

Для справки: я пытаюсь добавить в тайловую палитру (Tile Palette) префаб дерева с колайдером и объектом. Это мне, вроде, удалось, но деревья ставились друг на друга. Я использую новый скрипт, чтобы они не наслаивались и сортировались. Проект компилируется, всё запускается и отображается без проблем. Но вот сама ошибка печатается, и это напрягает.

Ниже приведены картинки для наглядности.

Answer 1

Очевидно, null вы получаете от метода GetComponent<T>(), т.к. к объекту не прикреплен искомый компонент:

GetComponent Unity API

Returns the component of Type type if the game object has one attached, null if it doesn't.

Скорее всего банальная человеческая ошибка, чтобы "не забывать" вешать необходимые компоненты на префабы - пользуйтесь RequireComponent:

[RequireComponent(typeof(SpriteRenderer))]
public class TreeTile : Tile
...

Причем данный атрибут можно установить на базовый класс Tile, и он, очевидно, будет работать и для всех его потомков.

UPDATE

Изучив документацию по теме тайлов в Unity стало ясно, что метод StartUp используется для кастомного кода для кастомных спрайтов. Причем этот метод вызывается, видимо, для инициализации самой TilePallete, а значит не для инстанциированных объектов.

Другими словами Unity за кулисами не передает никакой объект параметром в StartUp, что в этой строке:

go.GetComponent<SpriteRenderer>().sorting = ...;

Равносильно

null.GetComponent<SpriteRenderer>().sorting = ...;

Если посмотреть на пример реализации собственных тайлов в API, видно, что в переопределенном StartUp методе нужно вручную проверять условие go != null:

public override bool StartUp(Vector3Int location, ITilemap tilemap, GameObject go)
{
    if (go != null)
    {
        go.transform.rotation = Random.rotation;
    }
    return true;
}
READ ALSO
Загрузочная страница Xamarin.Forms

Загрузочная страница Xamarin.Forms

Хочу сделать загрузочную страницу приложения (на 5 секунд высвечивается страница, а потом убирается (Navigationpopasync())), однако высвечивается на 5 секунд...

180
DataGridView C# добавление изображения, имя которого берется из dataset

DataGridView C# добавление изображения, имя которого берется из dataset

Доброе утро, столкнулся с проблемой следующего характераЕсть база данных ms sql которую подключаю через источники данных в visual studio, таблица...

197
Ajax запрос с использованием json в проекте asp.net mvc

Ajax запрос с использованием json в проекте asp.net mvc

Изучаю javascriptДошёл до ajax запросов

149
В чем разница при вызове переменных?

В чем разница при вызове переменных?

В чём разница использования следующих вызовов переменных? Как я понял, одни из них устарели и не безопасны, но в чём это заключается я так...

147