如何根据类型填充 Enum 的值

问题描述 投票:0回答:1

我正在尝试在 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)。

我已经创建了所有类和接口的基本版本。

c# unity-game-engine generics enums
1个回答
0
投票

听起来你想要

  • 自动跟踪实现您的接口或具有特定属性的现有类型。

    通常您必须使用反射,但幸运的是 Unity 已经通过

    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());
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.