C#中如何用泛型枚举参数实现模块化动画控制器?
问题描述
我想要制作一个可对任意3D模型播放动画的泛型类,现有AnimationController类的ChangeAnimation方法使用string类型作为第一个参数,代码如下:
public class AnimationController { public void ChangeAnimation(string animation, int priority = 0, float crossfadeDuration = 0.2f, float animationSpeed = 1f) { if(priority is higher && this animation isn't already playing) { model.PlayAnimation(animation); } } }
但我希望将第一个参数替换为枚举类型,而非FireballAnimation这类特定枚举:
public void ChangeAnimation(FireballAnimation animation)
否则该类会失去模块化特性。同时我也不想每次调用ChangeAnimation()时都调用.ToString()方法。
我希望在同一代码库中实现如下调用:
// 在火球类的上下文下: public enum FireballAnimation { Casted, Flying, Impact, } AnimationController.ChangeAnimation(FireballAnimation.Impact); // 在玩家类的上下文下: public enum PlayerAnimation { None, Idle, Walking, StrafingLeft, StrafingRight, WalkingBackwards, Jumping, Casting, } AnimationController.ChangeAnimation(PlayerAnimation.Jumping);
这要求ChangeAnimation方法的第一个参数为泛型枚举类型,请问这在C#中是否可行?
解决方案
这在C#中完全可行,通过泛型方法搭配枚举类型约束即可实现你的需求,既保留AnimationController的模块化,又无需调用者手动转换字符串。
实现思路
- 给
ChangeAnimation方法添加泛型参数,并用where T : Enum约束限制参数必须为枚举类型; - 在方法内部完成枚举到字符串的转换(调用者无需关心这一步);
- 保留原有的优先级判断、动画播放逻辑。
修改后的完整代码
public class AnimationController { // 假设这是你的3D模型实例,根据实际类型替换 private Model model; // 记录当前播放的动画状态 private string _currentAnimation; private int _currentPriority; public void ChangeAnimation<T>(T animation, int priority = 0, float crossfadeDuration = 0.2f, float animationSpeed = 1f) where T : Enum { // 将枚举值转为对应的动画名称 string animationName = Enum.GetName(typeof(T), animation); // 优先级判断+播放状态检查(修正原代码的语法问题) if (priority > _currentPriority && !IsAnimationPlaying(animationName)) { model.PlayAnimation(animationName); // 更新当前状态 _currentAnimation = animationName; _currentPriority = priority; } } // 辅助方法:判断指定动画是否正在播放 private bool IsAnimationPlaying(string animationName) { return _currentAnimation == animationName; } }
调用示例
完全符合你期望的调用方式,直接传入不同枚举类型的值即可:
// 火球类中调用 var controller = new AnimationController(); controller.ChangeAnimation(FireballAnimation.Impact); // 玩家类中调用 controller.ChangeAnimation(PlayerAnimation.Jumping);
额外优化点
如果枚举成员名称和实际动画文件名不一致(比如枚举是Flying但动画名是fireball_flying),可以给枚举添加自定义属性来映射:
// 自定义属性 public class AnimationNameAttribute : Attribute { public string Name { get; } public AnimationNameAttribute(string name) => Name = name; } // 修改枚举 public enum FireballAnimation { [AnimationName("fireball_casted")] Casted, [AnimationName("fireball_flying")] Flying, [AnimationName("fireball_impact")] Impact, }
然后在ChangeAnimation方法中通过反射读取属性值,替换Enum.GetName的逻辑,进一步提升灵活性。
内容的提问来源于stack exchange,提问作者MaybeAFish
相关产品推荐
相关产品推荐

