简体   繁体   English

在 Unity 中以编程方式创建动画?

[英]Create animations programmatically in Unity?

In my game I have a big catalog of gear: Armors, weapons and shields.在我的游戏中,我有一个很大的装备目录:盔甲、武器和盾牌。 The combinations between these can be really immense.这些之间的组合可以是非常巨大的。

在此处输入图像描述

Besides that, the player has the option of switching in-game to a different set of armor-weapon combination.除此之外,玩家可以选择在游戏中切换到不同的盔甲武器组合。 In the end to solve this, I have used the following object structure.最后为了解决这个问题,我使用了下面的 object 结构。

在此处输入图像描述

Whenever I switch the weapons, I activate/deactivate the necessary GameObjects.每当我切换武器时,我都会激活/停用必要的游戏对象。 The animations are set in this way:动画是这样设置的:

在此处输入图像描述

Now, the problem is creating the animation.现在,问题在于创建 animation。 I first considered pre-rendering programatically all the combinations, but my catalog is so huge, that it would create 100s, if not 1000s of animations.我首先考虑以编程方式预渲染所有组合,但我的目录太大了,它会创建 100 多个动画,如果不是 1000 多个动画。 So I opted for a different solution.所以我选择了不同的解决方案。 Create in playtime the animation, once I knew what gear would the player select.在游戏时间创建 animation,一旦我知道播放器 select 将使用什么装备。 For that, I created a script to take care of that.为此,我创建了一个脚本来处理它。 The problem is that I have been using APIs from UnityEditor , and now I have realized the build will not work.问题是我一直在使用UnityEditor的 API,现在我意识到构建不起作用。 Specifically because of 2 different classes: EditorCurveBinding and ObjectReferenceKeyframe .特别是因为 2 个不同的类: EditorCurveBindingObjectReferenceKeyframe

This is a couple snippets of how I was using this classes when creating the animations:这是我在创建动画时如何使用这些类的几个片段:

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;
}

Now, the problem with the Curve, I think I managed to solve, replacing it with this code, replacing EditorCurveBinding with AnimationCurve :现在,曲线的问题,我想我设法解决了,用这段代码替换它,用AnimationCurve替换EditorCurveBinding

AnimationClip clip = ...
AnimationCurve curve = new AnimationCurve();
clip.SetCurve(path, typeof(SpriteRenderer), "m_Sprite", curve);

But I have no idea how to set the sprites for each animation.但我不知道如何为每个 animation 设置精灵。 I thought that using curve.AddKey could be helpful, but I have seen no way to add a sprite there.我认为使用curve.AddKey可能会有所帮助,但我没有看到在那里添加精灵的方法。

How could I rewrite that code to avoid using UnityEditor ?我如何重写该代码以避免使用UnityEditor

Full code完整代码

Personally, I would completely avoid built-in Animator and Animations, since this tool is for the very narrow purpose of animating a single object in a predefined way (eg: for a cutscene).就个人而言,我会完全避免使用内置的 Animator 和 Animations,因为该工具的用途非常狭窄,即以预定义的方式(例如:用于过场动画)为单个 object 设置动画。

Offtopic - performance题外话 - 性能

Besides that, the player has the option of switching in-game to a different set of armor-weapon combination.除此之外,玩家可以选择在游戏中切换到不同的盔甲武器组合。 In the end to solve this, I have used the following object structure.最后为了解决这个问题,我使用了下面的 object 结构。

As you probably know this is very inefficient memory-wise and will decrease performance (disabled objects still have marginal CPU overhead).正如您可能知道的那样,这在内存方面效率非常低,并且会降低性能(禁用的对象仍然有边际 CPU 开销)。 And will incread load time and instantiation time of new objects.并且会增加新对象的加载时间和实例化时间。

Can I use Animator or Animation?我可以使用 Animator 或 Animation 吗?

Because Animator has no API to access it's internals and animation type and overall you cannot do pretty mutch nothing with it except from telling it to Play or Stop .因为 Animator 没有 API 来访问它的内部结构和 animation 类型,所以总的来说,除了告诉它Play 或 Stop之外,你不能对它做任何事情。 Since I understand that your animation is "Sprite based" and not "Transform based" any sane idea is just inefficient!由于我了解您的 animation 是“基于 Sprite”而不是“基于转换”,因此任何理智的想法都是低效的!

Best solution that I vow against is as follows:我发誓反对的最佳解决方案如下:

  • Create "trigger points" that you would "animate"创建您将“动画化”的“触发点”
  • Based on trigger point - change sprite基于触发点——改变精灵
    public class AnimationController : MonoBehaviour
    {
        public int AnimationIndex;
        public Sprite[] AnimationSprites;
        public SpriteRenderer SpriteRenderer;
        
        private void Update()
        {
            SpriteRenderer.sprite = AnimationSprites[AnimationIndex];
        }
    }

在此处输入图像描述

Better solution?更好的解决方案?

Since we already need to have custom structure that manages our sprites we might want to optimize the whole thing, since we are not using almost any of the features of Animator we could write custom controller that would replace Animator in this case.由于我们已经需要自定义结构来管理我们的精灵,我们可能想要优化整个事情,因为我们几乎没有使用 Animator 的任何功能,我们可以编写自定义 controller 在这种情况下替换 Animator。 This should improve performance significantly since Animator is very heavy!这应该会显着提高性能,因为 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);
            }
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM