我的目标是创建一个模块化/尽可能通用的物料系统,该系统可以处理以下内容:
- 可升级物品(+6武士刀)
- Stat修饰符(+15敏捷)
- 物品修饰符(%X几率造成Y伤害,几率冻结)
- 充电物品(魔术师使用30次)
- 套装物品(装备4件X激活Y功能)
- 稀有度(常见,独特,传奇)
- 可分解的(分解成一些手工材料)
- 可制作(可以使用某些材料制作)
- 消耗(5分钟%X攻击强度,恢复+15 hp)
*我能够解决以下设置中加粗的功能。
现在,我尝试添加许多选项以反映我的想法。我不打算添加所有必要的功能,但是我希望能够按照自己的意愿实施它们。这些也应该与库存系统和数据序列化兼容。
我计划完全不使用继承,而是使用实体组件/数据驱动的方法。最初,我想到的系统具有:
- BaseStat:通用类,可随时随地保存统计信息(也可用于项和字符统计信息)
- Item:包含数据的类,例如列表,名称,itemtype和与ui,actionName,description等相关的事物。
- IWeapon:武器界面。每个武器都有实现IWeapon的自己的类。这将具有Attack(攻击)和对角色统计的引用。装备武器后,它的数据(物品类别的stat)将被注入角色stat(无论拥有什么BaseStat,它都会作为Stat奖励添加到角色类别中)因此,例如,我们想制作一把剑(想产生带有json的物品类),所以剑将对角色属性增加5点攻击。因此,我们有一个BaseStat为(“ Attack”,5)(我们也可以使用enum)。装备时,此属性将作为BonusStat(将是不同的类)添加到角色的“攻击”属性中。因此,名为Sword的类将实现IWeapon,项目类别已创建。因此,我们可以向这把剑注入角色统计数据,并且在攻击时,它可以从角色统计数据中检索总的攻击统计数据,并在Attack方法中造成伤害。
- BonusStat:是一种将统计信息添加为奖励而无需触及BaseStat的方法。
- IConsumable:与IWeapon相同的逻辑。添加直接属性相当容易(+15 hp),但是我不确定要使用此设置添加临时武器(%x攻击5分钟)。
- IUpgradeable:可以使用此设置来实现。我正在考虑将UpgradeLevel作为基本属性,在升级武器时会增加它。升级后,我们可以重新计算武器的BaseStat以匹配其升级级别。
在此之前,我可以看到该系统相当不错。但是对于其他功能,我认为我们还需要其他东西,因为例如,我无法在其中实现Craftable功能,因为我的BaseStat无法处理该功能,这就是我遇到的问题。我可以将所有成分添加为统计信息,但这没有任何意义。
为了使您更轻松地进行此操作,以下一些问题可能会对您有所帮助:
- 我是否应该继续执行此设置以实现其他功能?没有继承就可能吗?
- 您有什么办法可以想到,在没有继承的情况下实现所有这些功能?
- 关于物品修饰符,如何实现?因为它的性质非常通用。
- 有什么建议可以做些什么来简化构建这种架构的过程?
- 有没有我可以挖掘的与此问题相关的来源?
- 我确实尽力避免继承,但是您认为在保持相当可维护性的同时,可以轻松地通过继承解决/实现这些继承吗?
由于我的问题范围很广,因此可以随意回答一个问题,这样我就可以从不同的方面/人那里获得知识。
编辑
遵循@ jjimenezg93的回答,我用C#创建了一个非常基本的系统进行测试,它可以正常工作!看看是否可以添加任何内容:
public interface IItem
{
List<IAttribute> Components { get; set; }
void ReceiveMessage<T>(T message);
}
public interface IAttribute
{
IItem source { get; set; }
void ReceiveMessage<T>(T message);
}
到目前为止,IItem和IAttribute是基本接口。不需要(我可以想到)具有消息的基本接口/属性,因此我们将直接创建一个测试消息类。现在开始测试课程:
public class TestItem : IItem
{
private List<IAttribute> _components = new List<IAttribute>();
public List<IAttribute> Components
{
get
{
return _components;
}
set
{
_components = value;
}
}
public void ReceiveMessage<T>(T message)
{
foreach (IAttribute attribute in Components)
{
attribute.ReceiveMessage(message);
}
}
}
public class TestAttribute : IAttribute
{
string _infoRequiredFromMessage;
public TestAttribute(IItem source)
{
_source = source;
}
private IItem _source;
public IItem source
{
get
{
return _source;
}
set
{
_source = value;
}
}
public void ReceiveMessage<T>(T message)
{
TestMessage convertedMessage = message as TestMessage;
if (convertedMessage != null)
{
convertedMessage.Execute();
_infoRequiredFromMessage = convertedMessage._particularInformationThatNeedsToBePassed;
Debug.Log("Message passed : " + _infoRequiredFromMessage);
}
}
}
public class TestMessage
{
private string _messageString;
private int _messageInt;
public string _particularInformationThatNeedsToBePassed;
public TestMessage(string messageString, int messageInt, string particularInformationThatNeedsToBePassed)
{
_messageString = messageString;
_messageInt = messageInt;
_particularInformationThatNeedsToBePassed = particularInformationThatNeedsToBePassed;
}
//messages should not have methods, so this is here for fun and testing.
public void Execute()
{
Debug.Log("Desired Execution Method: \nThis is test message : " + _messageString + "\nThis is test int : " + _messageInt);
}
}
这些是所需的设置。现在我们可以使用系统了(以下是Unity)。
public class TestManager : MonoBehaviour
{
// Use this for initialization
void Start()
{
TestItem testItem = new TestItem();
TestAttribute testAttribute = new TestAttribute(testItem);
testItem.Components.Add(testAttribute);
TestMessage testMessage = new TestMessage("my test message", 1, "VERYIMPORTANTINFO");
testItem.ReceiveMessage(testMessage);
}
}
将此TestManager脚本附加到场景中的组件上,您可以在调试中看到消息已成功传递。
为了说明问题:游戏中的每个项目都将实现IItem接口,并且每个属性(名称都不应使您感到困惑,这意味着项目功能/系统。如Upgradeable或Disenchantable)将实现IAttribute。然后,我们有了一种处理消息的方法(为什么需要消息,将在进一步的示例中进行说明)。因此,在上下文中,您可以将属性附加到项目,然后让其余的工作为您完成。这非常灵活,因为您可以轻松添加/删除属性。因此,一个伪示例将是可分解的。我们将在Disenchant方法中有一个名为Disenchantable(IAttribute)的类,它将要求:
- 列出成分(当分解物品时,应该给玩家什么物品)注意:IItem应该扩展为具有ItemType,ItemID等。
- int resultModifier(如果实现了某种增强分解功能的功能,则可以在此处传递一个int来增加分解时收到的成分)
- int FailureChance(如果分解进程有失败的机会)
等等
这些信息将由名为DisenchantManager的类提供,它将接收该物品并根据物品(被分解时物品的成分)和玩家进程(resultModifier和failureChance)形成此消息。为了传递此消息,我们将创建DisenchantMessage类,该类将充当此消息的主体。因此DisenchantManager将填充DisenchantMessage并将其发送到该项目。Item将收到消息并将其传递给所有附加的属性。由于Disenchantable类的ReceiveMessage方法将查找DisenchantMessage,因此只有Disenchantable属性将接收此消息并对其进行操作。希望这能为我带来更多的收获:)。