Система генерации предметов в Unity - Как сохранить возможность редактирования объектов сценариев после создания сценариев - PullRequest
0 голосов
/ 15 мая 2018

Я сейчас работаю над игрой, и у меня возникли проблемы с моим дизайном.А именно, мои системы предметов и способностей.

Я начал с использования наследования, чтобы добавить функциональность к моим предметам, скажем, с базовым классом Item и наследованием от него обоих ConsumableItem и Equipment.Но потом я начал хотеть предметы, где были и расходные материалы, и снаряжение (скажем, набор стрелок).Поскольку я использую 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;
}
...