Method return null (A: Order of execution)

问题描述 投票:0回答:1

Im new to c# and Unity, can't solve this problem about 2 days.

I don't know why, but in ItemOnGround class on Debug.Log line always getting this error:

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

I tried use FetchItemById method, but it still wont work. Even if i just copy and paste everything from Slot class, it still wont work. I tried to attach it to different GameObject but it still wont work. Is it some thread problem or i do something wrong?

Thank you for any help

Here how scripts attached in Unity : Screenshot

So i have 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);
    }
}

And 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"
    }
]
c# unity3d
1个回答
0
投票

Unity Engine has a specific Order of Execution.

This defines the order at which Unity Callbacks are executed in every script.

For instance, all the Awake() callbacks in your MonoBehaviours will be executed before any Start() callback.

That said, it doesn't mean that it governs the order of execution of individual Start() callbacks from different behaviours.

In your example. It is possible that the Start() callback of the ItemOnGround behaviour is invoked before ItemDatabase's. In which case, you're making calls to an ItemDatabase that hasn't been initialized yet. So here is what I suggest:

Approach 1:

Knowing that Awake() is called before Start() you could initialize your ItemDatabase by changing Start() to:

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

Approach 2:

You could adjust the Script Execution Order settings. in Edit > Project Settings.

This allows you to give a priority order to each of your MonoBehaviours.

By giving the script ItemDatabase a lower number (higher priority) than ItemOnGround's, you're telling the engine to invoke ItemDatabase.Start() before ItemOnGround.Start().

© www.soinside.com 2019 - 2024. All rights reserved.