首页 > 解决方案 > 需要帮助使用 ScriptableObjects 列表创建库存系统

问题描述

解决了

感谢您花时间查看我的问题。

我目前正在使用 Unity3D 进行一个项目,并且在创建库存系统时遇到了一些困难。在做了一些研究后,我决定使用 ScriptableObjects (Item) 列表来创建这个库存系统,因为它易于管理和列表的扩展能力,这将符合我的最大利益。

举个例子,我有一个名为“Skull”的项目。当玩家指向头骨时,我的代码提示用户按 F 键来拾取物品,这反过来应该从游戏世界中删除物品实例并将该物品的实例添加到库存中。

给我带来最大麻烦的部分是我的 InventoryEditor 脚本,它控制着我之前提到的 RayCast 功能。

这是我的 InventoryEditor 脚本中的代码,但 Update 和 Start 方法除外,因为它们按预期工作

using UnityEngine;

public class InventoryEditor : MonoBehaviour
{
    private bool isOpen = false;

    public TMPro.TMP_Text itemIDTM;

    public GameObject currentObject;
    public GameObject inventoryUI;

    new Inventory playerInventory;


    public void CurrentObject()
    {
        RaycastHit itemHit;
        Ray itemFinder = new Ray(this.transform.position, transform.TransformDirection(Vector3.forward));

        if (Physics.Raycast(itemFinder, out itemHit))
        {
            if (itemHit.collider.tag == "Item")
            {
                // Rather than itemHit.collider.name I would prefer if it uses the Identifier of the
                        //Item ScriptableObject              V
                itemIDTM.text = "F - Pick up: " + itemHit.collider.name;

                if (Input.GetKeyDown(KeyCode.F))
                {
                    /*
                    I need to Add an Item When F is pressed
                    Something along the lines of:
                        playerInventory.AddItem(Item that is hit by RayCast);
                    */
                }
            }
            else
            {
                itemIDTM.text = "";
            }
        }
    }

}

这是我的 ScriptableObject 并没有给我带来任何问题

    using UnityEngine;

[CreateAssetMenu]
public class Item : ScriptableObject
{
    public string identifier;
    public GameObject model;
    public int value;
    public double weight;


    Item(string identifierStr)
    {
        this.identifier = identifierStr;
    }
}

这是我的库存类

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

public class Inventory : List<Item>
{
    public List<Item> itemList = new List<Item>();

    // Default Constructor
    Inventory()
    {

    }

    public override string ToString()
    {
        string itemListString = " ";

        for(int i = 0; i < itemList.Count; i++)
        {
            itemListString = itemListString += itemList[i].name;
        }

        return itemListString;
    }

    public void AddItem(Item itemToAdd)
    {
        for (int i = 0; i < itemList.Count + 1; i++)
        {
            if (itemList[i] == null)
            {
                itemList[i] = itemToAdd;
            }
        }
    }

    // Remove Item Not Finished
    public void RemoveItem(Item itemToRemove)
    {
        for (int i = 0; i < itemList.Count; i++)
        {
            if (itemList[i] == itemToRemove)
            {
                itemList.Remove(itemToRemove);
            }
        }
    }
}

我能想到的唯一解决方案是使用 ScriptableObject.CreateInstance 用我希望添加到库存中的项目填充我的游戏世界,但即便如此我也不确定如何同时使用:在代码中引用这些项目实例并使用一个 RayCast 来确定一个项目实例被击中。是否可以在没有代码的情况下统一创建 ScriptableObject 的实例,还是我必须通过代码填充我的世界?

任何帮助将不胜感激,我已经为此苦苦挣扎了一段时间。

标签: c#unity3d

解决方案


因此,与大多数事情一样,有很多方法可以给猫剥皮。资产商店中有一些出色而复杂的库存系统,如果您觉得这花费了太多时间,您可以使用它们。如果是我设置这个结构,我会为你创建一个名为“IInteractable”之类的界面,供你希望玩家能够拾取的项目。那个界面看起来像这样

public interface IInteractable
{
    //once a player has reference to this object they call this
    //method to get an item back (which is your scriptable object)
    Item GetItemInfo();
}

因此,在您的 OnCollision 方法中,您可以代替检查标签而不是检查这样的接口。

IInteractable item = itemhit.collider.gameobject.GetComponent<IInteractable>();            
if (item != null)
{
//Then you have found an item that needs to be picked up.
  string name = item.GetItemInfo().identifier;

}

从这里开始,您可以采取多种方式,具体取决于您希望库存对角色产生的影响。对于某些库存,您希望物品立即生效,而对于其他物品,您希望效果仅在装备时才有效。就生成这些物品而言,制作附有 SO 的预制件并生成它们可能是最简单的。如果您还有其他问题,请告诉我。


推荐阅读