在 Unity 中以编程方式创建动画?
Posted
技术标签:
【中文标题】在 Unity 中以编程方式创建动画?【英文标题】:Create animations programmatically in Unity? 【发布时间】:2021-05-17 01:55:22 【问题描述】:在我的游戏中,我有一个很大的装备目录:盔甲、武器和盾牌。这些之间的组合可能非常巨大。
除此之外,玩家还可以选择在游戏中切换到不同的盔甲武器组合。最后为了解决这个问题,我使用了以下对象结构。
每当我切换武器时,我都会激活/停用必要的游戏对象。动画是这样设置的:
现在,问题在于创建动画。我首先考虑以编程方式预渲染所有组合,但我的目录非常庞大,以至于它会创建 100 多个动画,如果不是 1000 多个动画。所以我选择了不同的解决方案。一旦我知道玩家会选择什么装备,就可以在播放时间创建动画。为此,我创建了一个脚本来处理它。问题是我一直在使用来自UnityEditor
的 API,现在我意识到构建将无法正常工作。特别是因为 2 个不同的类:EditorCurveBinding
和 ObjectReferenceKeyframe
。
这是我在创建动画时如何使用这些类的几个 sn-ps:
static EditorCurveBinding GetEditorCurveBinding(string path = "")
EditorCurveBinding spriteBinding = new EditorCurveBinding();
spriteBinding.type = typeof(SpriteRenderer);
spriteBinding.path = path;
spriteBinding.propertyName = "m_Sprite";
return spriteBinding;
static ObjectReferenceKeyframe GetKeyframe(float time, Sprite sprite)
ObjectReferenceKeyframe keyframe = new ObjectReferenceKeyframe();
keyframe.time = time / FRAMERATE;
keyframe.value = sprite;
return keyframe;
现在,曲线的问题,我想我设法解决了,用这段代码替换它,用 AnimationCurve
替换 EditorCurveBinding
:
AnimationClip clip = ...
AnimationCurve curve = new AnimationCurve();
clip.SetCurve(path, typeof(SpriteRenderer), "m_Sprite", curve);
但我不知道如何为每个动画设置精灵。我认为使用curve.AddKey
可能会有所帮助,但我没有看到在那里添加精灵。
如何重写该代码以避免使用UnityEditor
?
Full code
【问题讨论】:
如果动画对于一类设备(例如剑)总是相同的,为什么不创建一个包含动画的父对象,然后将特定剑添加为子对象?这将使动画与齿轮分离,您只需要创建一组有限的动画。 您的意思是为每个齿轮创建单独的动画,并将动画分散到不同的游戏对象上?我理解正确吗? 不是针对每个单独的装备,而是针对每个类别的装备。例如一个动画用于所有剑,一个用于所有长矛,一个用于所有盾牌等。然后您可以拥有一个没有任何图形处理动作的游戏对象,并在小时候附加齿轮的实际图形/统计/逻辑。 问题在于动画师。状态机一次只能控制一个动画。它无法为每一类齿轮控制单独的动画。 为什么不让每个装备一个动画师,然后在你的播放器脚本中使用参数触发它?否则无论如何你都必须处理多个并发动画,例如同时砍杀和行走。 【参考方案1】:就我个人而言,我会完全避免使用内置的 Animator 和 Animations,因为该工具的用途非常狭窄,即以预定义的方式为单个对象设置动画(例如:用于过场动画)。
题外话 - 性能
除此之外,玩家还可以选择在游戏中切换到不同的盔甲武器组合。最后为了解决这个问题,我使用了以下对象结构。
您可能知道这在内存方面非常低效,并且会降低性能(禁用的对象仍然有边际 CPU 开销)。并且会增加新对象的加载时间和实例化时间。
我可以使用 Animator 或 Animation 吗?
因为 Animator 没有 API 来访问它的内部结构和动画类型,总的来说,除了告诉 Play or Stop 之外,你不能对它做任何事情。 由于我了解您的动画是“基于 Sprite”而不是“基于变换”的,因此任何理智的想法都是低效的!
我发誓反对的最佳解决方案如下:
创建可以“动画化”的“触发点” 基于触发点 - 改变精灵 public class AnimationController : MonoBehaviour
public int AnimationIndex;
public Sprite[] AnimationSprites;
public SpriteRenderer SpriteRenderer;
private void Update()
SpriteRenderer.sprite = AnimationSprites[AnimationIndex];
更好的解决方案?
由于我们已经需要自定义结构来管理我们的 sprite,我们可能想要优化整个事情,因为我们几乎没有使用 Animator 的任何功能,我们可以编写自定义控制器来替换这种情况下的 Animator。这应该会显着提高性能,因为 Animator 非常重!
// MonoBehaviour is optional here
public class SpriteRendererAnimationHandler
// More fields that would control the animation timing
public Sprite[] AnimationSprites;
public SpriteRenderer SpriteRenderer;
public void OnAnimationUpdate(int index)
var resolvedIndex = ResolveIndex(index);
SpriteRenderer.sprite = AnimationSprites[resolvedIndex];
private int ResolveIndex(int index)
// Resolve animation index to sprite array index
// One controller per character - or global per game that synchronize all animations to locked FPS 12.
public class AnimationController : MonoBehaviour
private List<SpriteRendererAnimationHandler> Handlers = new List<SpriteRendererAnimationHandler>();
public void FixedUpdate()
foreach (var handler in Handlers)
// Calculate animation index
int calculatedAnimationIndex = ...;
handler.OnAnimationUpdate(calculatedAnimationIndex);
【讨论】:
构建我自己的动画系统似乎真的有点矫枉过正!没有其他现有的可以使用吗? 第一个解决方案是您可以与现有动画系统一起使用的最佳解决方案,该系统是一个自定义类,用于存储您的图像并“动画”索引。否则,正如您提到的,您将需要数千个可以通过编辑器脚本生成的动画。 但这是否意味着我必须在每个关键帧上设置动画事件? 我不知道我是否正确理解了你的问题。您不必在每个关键帧上都设置动画事件。当精灵需要更改时,您需要经常制作动画事件。正如您目前使用精灵一样,但使用索引。例如:如果在你的攻击动画中盾牌总是相同的精灵,但与空闲动画不同,那么你需要在动画开始时设置索引(精灵)。 "您不必在每个关键帧上都设置动画事件。当精灵需要更改时,您需要经常制作动画事件"以上是关于在 Unity 中以编程方式创建动画?的主要内容,如果未能解决你的问题,请参考以下文章