Unity中的项目生成系统 - 如何在脚本实例化后保留脚本化对象编辑功能

时间:2018-05-15 17:18:41

标签: c# unity3d save decorator wrapper

我目前正在开发一款游戏,而且我的设计遇到了问题。即我的物品和能力系统。

我首先使用继承来为我的项添加功能,比如通过拥有Item基类并继承ConsumableItemEquipment继承它。但后来我开始想要那些消耗品和设备(比如一组箭头)的物品。因为我使用Unity 3D和C#,我不能从多个类继承,加上我读它可能会导致问题。

我听说过接口,它可以解决我的问题,但仍然需要我手工编写每一个属性组合的硬编码。

我开始阅读有关设计模式的内容,并想知道我是否可以使用装饰器模式来组合属性和方法,以便在编辑器中创建自定义对象。

我希望有可能创建一个基类ItemBlueprint类,它将一系列功能作为enum值。然后,我将该ItemBlueprint对象传递给另一个具有名为Build的方法的类,并通过将所有相关属性和方法添加到Item对象来构建项目。然后可以将输出产品作为组件添加到游戏对象的场景中,或者作为scriptableObject直接保存到资源。然后我就可以手动编辑公共字段了。

到目前为止,我已经能够使用下面的代码生成项目。但是,统一检查器中显示的唯一字段是与最后应用的装饰器对应的属性。因此,当耗材被设置为蓝图特征数组中的最后一个条目而不是description属性时,我无法修改equipmentSlot

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

public class ItemBuilder : MonoBehaviour {
    public ItemBluePrint bp;

    private List<Decorator> items;

    public void OnValidate()
    {
        items = new List<Decorator>();
    }

    [ContextMenu("Build Item")]
    public void Build ()
    {
        // Create Item and Decorators
        DiscreteItem newItem = ScriptableObject.CreateInstance<DiscreteItem>();

        for (int i = 0; i < bp.properties.Length; i++) {
            if (i == (int) ItemProperties.Consumable) {
                items.Add(ScriptableObject.CreateInstance<ConsumableItem>());
            }
            if (i == (int) ItemProperties.Equipable) {
                items.Add(ScriptableObject.CreateInstance<EquipableItem>());
            }
        }

        // Link decorators
        Item previousItem = (Item) newItem;
        for (int i = 0; i < items.Count; i++) {
            items [i].SetItem (previousItem);
            previousItem = (Item) items [i];
        }

        AssetDatabase.CreateAsset (previousItem, "Assets/MynewItem.asset");
        Debug.Log ("Item created !");
    }

    abstract class Item : ScriptableObject
    {
        public abstract void Operation();
    }

    class DiscreteItem : Item
    {
        public override void Operation()
        {
            Debug.Log("Use item.");
        }
    }

    abstract class Decorator : Item
    {
        protected Item item;

        public void SetItem(Item item)
        {
            this.item = item;
        }

        public override void Operation()
        {
            if (item != null)
            {
                item.Operation();
            }
        }
    }

    class ConsumableItem : Decorator
    {
        public string description;

        public override void Operation()
        {
            base.Operation();
            Debug.Log("I consume the item.");
        }
    }

    class EquipableItem : Decorator
    {
        public int equipementSlot;

        public override void Operation()
        {
            base.Operation();
            AddedBehavior();
            Debug.Log("I equip the item.");
        }

        void AddedBehavior()
        {
            Debug.Log("I added the item to my equipment.");
        }
    }
}

蓝图类:

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

public enum ItemProperties
{
    Consumable = 0,
    Equipable = 1,
}

[CreateAssetMenu(fileName= "Item", menuName="Item")]
public class ItemBluePrint : ScriptableObject {
    public ItemProperties[] properties;
}

0 个答案:

没有答案