ЕДИНСТВО | Метод return null (A: порядок выполнения) - PullRequest
0 голосов
/ 28 мая 2020

Я новичок в c# и Unity, не могу решить эту проблему около 2 дней.

Не знаю почему, но в классе ItemOnGround в строке Debug.Log всегда появляется эта ошибка :

NullReferenceException: Object reference not set to an instance of an object

Я пробовал использовать метод FetchItemById, но он все равно не работает. Даже если я просто скопирую и вставлю все из класса Slot, это все равно не сработает. Я попытался прикрепить его к другому GameObject, но он все равно не работает. Это какая-то проблема с потоком или я что-то делаю не так?

Спасибо за любую помощь

Вот как скрипты прикреплены в Unity: Снимок экрана

Итак, я иметь 3 .cs

ItemDatabase

using System.Collections;
using System.Collections.Generic;
using System.IO;
using LitJson;
using UnityEngine;

public class ItemDatabase : MonoBehaviour
{
    private List<Item> database = new List<Item>();
    private JsonData itemData;

    void Start()
    {
        SetLanguagePath();
        ConstructItemDatabase();
    }

    public void SetLanguagePath()
    {
        itemData = JsonMapper.ToObject(File.ReadAllText(Application.streamingAssetsPath + "/en_Items.json"));
    }

    public Item FetchItemById(int id)
    {
        for (int i = 0; i < database.Count; i++)
        {
            if (database[i].Id == id)
            {
                return database[i];
            }
        }
        return null;
    }

    public Item FetchItemBySlug(string slug)
    {
        for (int i = 0; i < database.Count; i++)
        {
            if(database[i].Slug == slug)
            {
                return database[i];
            }
        }
        return null;
    }

    void ConstructItemDatabase()
    {
        for (int i = 0; i < itemData.Count; i++)
        {
            Item newItem = new Item();
            newItem.Id = (int)itemData[i]["id"];
            newItem.Title = itemData[i]["title"].ToString();
            newItem.Value = (int)itemData[i]["value"];
            newItem.Power = (int)itemData[i]["stats"]["power"];
            newItem.Defense = (int)itemData[i]["stats"]["defense"];
            newItem.Vitality = (int)itemData[i]["stats"]["vitality"];
            newItem.Description = itemData[i]["description"].ToString();
            newItem.Stackable = (bool)itemData[i]["stackable"];
            newItem.Type = itemData[i]["type"].ToString();
            newItem.Slug = itemData[i]["slug"].ToString();
            newItem.Sprite = Resources.Load<Sprite>("Sprites/Items/" + newItem.Slug);

            database.Add(newItem);
        }
    }
}

public class Item
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int Value { get; set; }
    public int Power { get; set; }
    public int Defense { get; set; }
    public int Vitality { get; set; }
    public string Description { get; set; }
    public bool Stackable { get; set; }
    public string Type { get; set; }
    public string Slug { get; set; }
    public Sprite Sprite { get; set; }
}

Slot

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Slot : MonoBehaviour
{
    bool hasItem = true;

    private void Start()
    {
        InitializeSlot();
    }

    void InitializeSlot()
    {
        if (hasItem)
        {
            ItemDatabase database = GameObject.Find("Inventory").GetComponent<ItemDatabase>();
            Item item = database.FetchItemById(0);

            Debug.Log(item.Slug);
        }
    }
}

ItemOnGround

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemOnGround : MonoBehaviour
{
    void Start()
    {
        InitializeItem();
    }

    void InitializeItem()
    {
        ItemDatabase database = GameObject.Find("Inventory").GetComponent<ItemDatabase>();
        Item item = database.FetchItemBySlug("apple");

        Debug.Log(item.Slug);
    }
}

И en_Items.json

[
    {
        "id": 0,
        "title": "Apple",
        "value": 1,
        "stats": {
            "power": 1,
            "defense": 1,
            "vitality": 10
        },
        "description": "Tasty apple",
        "stackable": true,
        "type": "food",
        "slug":  "apple"
    },
    {
        "id": 1,
        "title": "Plum",
        "value": 1,
        "stats": {
            "power": 1,
            "defense": 1,
            "vitality": 10
        },
        "description": "Juicy plum",
        "stackable": true,
        "type": "food",
        "slug": "plum"
    }
]

1 Ответ

0 голосов
/ 29 мая 2020

Unity Engine имеет специфику c Порядок выполнения .

Это определяет порядок, в котором обратные вызовы Unity выполняются в каждом скрипте.

Например, все обратные вызовы Awake() в вашем MonoBehaviours будут выполняться перед любым обратным вызовом Start().

Тем не менее, это не означает, что он управляет порядком выполнения отдельных Start() обратных вызовов с различным поведением.

В вашем примере. Возможно, что обратный вызов Start() поведения ItemOnGround вызывается до ItemDatabase. В этом случае вы звоните на ItemDatabase, который еще не был инициализирован. Итак, вот что я предлагаю:

Подход 1:

Зная, что Awake() вызывается до Start(), вы можете инициализировать ItemDatabase, изменив Start() на:

void Awake()
{
    SetLanguagePath();
    ConstructItemDatabase();
}

Подход 2:

Вы можете изменить настройки Порядок выполнения скрипта . в Edit> Project Settings.

Это позволяет вам назначить порядок приоритета для каждого из ваших MonoBehaviours.

Присваивая скрипту ItemDatabase меньшее число (более высокий приоритет), чем ItemOnGround вы говорите движку вызвать ItemDatabase.Start() перед ItemOnGround.Start().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...