我目前正在开发一款游戏,而且我的设计遇到了问题。即我的物品和能力系统。
我首先使用继承来为我的项添加功能,比如通过拥有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;
}