【Unity】使用反射动态修改脚本属性值

需求描述

  • 需要在运行时修改脚本的属性值
  • 某个对象只在特定场景或时机表现出特殊属性,其余时表现正常属性(属性值修改不能直接修改玩家的默认配置)

分析

本质就是希望对象在不同条件下应用不同的属性,以表现出不同的特性(如玩家的移动速度在某些场景变慢/变快)。
但凡是有参数依赖的配置,都应该用配置的方式去做依赖注入,不应该使用反射破坏性的修改,更不应该在运行时使用反射。
反射是邪恶的,但在架构完整,流程完善的情况下,无法短时间低成本的建立一个新的配置注入的机制,反射能快速完成需求并很好的与代码结构解耦。
我不愿意这样做,但确实能提供一种极细粒度,极高灵活性的问题解决方案。

解决方案

  • 一个参数注入器
public class ComponentInjector : MonoBehaviour
    {

        // 目标物体 这里限定为脚本
        public MonoBehaviour TargetObj;
        
        // 参数配置列表
        [SerializeField]
        private List<PropertyConfig> _propertyConfig;
        

        protected virtual void Start()
        {
            // 示例 在需要的时刻调用Inject注入参数
            if (TargetObj)
            {
                Inject();
            }
        }
        public virtual void Inject()
        {
            // 遍历参数配置
            foreach (var VARIABLE in _propertyConfig)
            {
                // 拿到配置的值和希望注入的类型
                var result = VARIABLE.GetActiveConfig(out Type type);

                if (type != null)
                {
                    // 反射拿到目标物体的字段信息
                    // GetField(字段名,标识位)
                    // 字段名指示了需要获取的指定脚本的字段名称 
                    // 标志位指定了一些过滤信息
                    // 注意 GetField 方法只能拿到没有Get/Set方法的字段
                    FieldInfo field = TargetObj.GetType().GetField(VARIABLE.PropertyName,BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

                    // 判断指定名称的字段合法且类型与反射配置一致
                    if (field != null)
                    {
                        if (field.FieldType == type)
                        {
                            // 注入反射配置
                            field.SetValue(TargetObj, result);
                        }
                        else
                        {
                            Debug.LogError($"Inject Error: {TargetObj.name} {VARIABLE.PropertyName} type is not match");
                        }
                    }
                }
            }
        }
        
    }
  • 反射参数配置
    [Serializable]
    public class PropertyConfig
    {
        public string PropertyName;
        public PropertyType PropertyType;
        public bool isString => PropertyType == PropertyType.String;
        
        public bool isFloat => PropertyType == PropertyType.Float;
        
        public bool isInt => PropertyType == PropertyType.Int;

        public bool isCurve => PropertyType == PropertyType.Curve;

        [NaughtyAttributes.ShowIf(nameof(isString))]
        [AllowNesting]
        public string StringProperty;
        
        [NaughtyAttributes.ShowIf(nameof(isFloat))]
        [AllowNesting]
        public float FloatProperty;
        
        [NaughtyAttributes.ShowIf(nameof(isInt))]
        [AllowNesting]
        public int IntProperty;
        
        [NaughtyAttributes.ShowIf(nameof(isCurve))]
        [AllowNesting]
        public AnimationCurve CurveProperty;

        public object GetActiveConfig(out Type type)
        {
            switch (PropertyType)
            {
                case PropertyType.String:
                {
                    type = typeof(string);
                    return StringProperty;
                }
                case PropertyType.Float:
                {
                    type = typeof(float);
                    return FloatProperty;
                }
                case PropertyType.Int:
                {
                    type = typeof(int);
                    return IntProperty;
                }
                case PropertyType.Curve:
                {
                    type = typeof(AnimationCurve);
                    return CurveProperty;
                }
                
            }
            type = null;
            return null;
        }
    }

    public enum PropertyType
    {
        String,
        Float,
        Int,
        Curve
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值