我正在尝试在 Unity 中创建一个角色能力系统。
在系统中,我有各种不同的类和接口,它们都是空的“IAbilitySystem”接口所固有的。
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TenkayCode
{
namespace Systems
{
public interface IAbility : IAbilitySystem
{
[Modifiable]
string Name { get; }
[Modifiable]
float BaseCooldown { get; }
[Modifiable]
int BaseCharges { get; }
void Action() { }
}
public interface IReloadableAbility : IAbility
{
[Modifiable]
float ReloadSpeed { get; }
[Modifiable]
int MaxAmmo { get; }
[Modifiable]
int AmmoPerReload { get; }
void Reload() { }
List<IModifier<IReloadableAbility>> Modifiers { get; }
}
public interface IOverheatAbility : IAbility
{
[Modifiable]
float MaxHeat { get; }
[Modifiable]
float HeatReduceRate { get; }
void Cooling() { }
void Heating() { }
List<IModifier<IOverheatAbility>> Modifiers { get; }
}
[CreateAssetMenu(menuName = "Assets/Ability")]
public class TenkayAbility : ScriptableObject, IAbility
{
String AbilityName;
float AbilityCooldown;
int AbilityCharges;
public string Name => AbilityName;
public float BaseCooldown => AbilityCooldown;
public int BaseCharges => AbilityCharges;
}
}
}
这些类具有各种 float 和 int 数据类型字段,系统使用它们来计算该能力的工作原理(即伤害、近战范围、传播、aoe、射弹速度等)。每个字段都使用自定义属性“可修改”。
我有一个“统计”界面,用于包含和计算角色统计数字(即角色生命值、力量、缺失法力百分比、等级等)
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TenkayCode
{
namespace Systems
{
public interface IStat : IAbilitySystem
{
[Modifiable]
int BaseValue { get; }
void getBonusFromEquipment() { }
void getBonusFromBuffs() { }
}
public interface IResourceStat : IStat
{
[Modifiable]
float BaseRegenRate { get; }
List<IModifier<IResourceStat>> Modifiers { get; }
}
}
}
我还有一个“Modifier”类,它可以采用自己的浮点“ModRatio”和“Stat”类中的一些数字,并在任何实现
IAbilitySystem
的类中增加任何“可修改”字段的值,只要该值是被其他东西召唤。
using System.Reflection.Emit;
using System.ComponentModel;
using System;
using UnityEngine;
using System.Reflection;
namespace TenkayCode
{
namespace Systems
{
[AttributeUsage(validOn: AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ModifiableAttribute : Attribute
{
public ModifiableAttribute() { }
}
public class IModifier<T> where T : IAbilitySystem
{
IStat ModifierStat;
[Modifiable]
float ModRatio;
/*im pretty sure this is wrong*/
// List<IModifier<T>> RatioModifiers { get; }
/*this is the part where Im stuck at...
enum ModifierTarget<T> {
// The names of all the fields and properties of type <T> which have the Modifiable Atribute
}
*/
}
}
}
我想设置这个系统,以便可以通用地使用“Modifier”类(即:
Modifier<T> where T : IAbilitySystem
)。
我的思考过程是,这将允许我在“修改器”中创建一个名为“修改器目标”的枚举,它可以动态地用与“T”类型相关的“可修改”属性的所有字段名称填充自身。这将允许我将特定类型“能力”的所有修饰符存储到单个列表中(
List<Modifiers<This.Type>> mods
),而不是为每个可以修改的字段提供一个列表,并且必须确保每个 Mod 都在右列表。这也让我能够继续将系统扩展至我想要的任意数量的IAbilitySystem
,而不会产生太多的意大利面条。
我的最终目标是能够将不同的能力创建为统一的可编写脚本的对象,并能够使用检查器来分配基本值并轻松编辑任何修改器。我喜欢 Unity 如何在下拉菜单中列出枚举字段的所有可能值。
我想知道我是否走在解决方案的正确道路上,或者是否有更好的方法来实现这种系统。
另外,我希望“修改器”也能够拥有自己的“修改器”列表(即:使用统计数据来调整修改器的 ModRatio)。
我已经创建了所有类和接口的基本版本。
听起来你想要
自动跟踪实现您的接口或具有特定属性的现有类型。
TypeCache
准确提供了该信息
然后生成一个填充该信息的枚举
InitializeOnLoadMethod
- 当项目打开或每次重新编译后都会调用它。
由于我没有掌握您的确切需求,这里只是一个虚拟样本
public static class MyEnumGenerator
{
private const string TARGET_FILE_PATH = "TenkayCode/Systems/ModifierTarget.cs";
[InitializeOnLoadMethod]
private static void Generate()
{
var sb = new StringBuilder("using System;/n/n");
sb.Append("namespace TenkayCode/n{ public enum ModifierTarget/n {/n");
// Use method according to your needs here
foreach(var type in TypeCache.GetTypesDerivedFrom(typeof(XY)))
{
sb.Append(" ").Append(type.Name).Append(",/n");
}
sb.Append(" }/n}");
File.WriteAllText(TARGET_FILE_PATH, sb.ToString());
}
}