65.9K
CodeProject 正在变化。 阅读更多。
Home

掌握 Unity 2D 游戏开发 – 动画曲线

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2014年7月28日

CPOL

5分钟阅读

viewsIcon

12487

掌握 Unity 2D 游戏开发 - 动画曲线

此片段的示例项目和代码可在以下位置找到: AnimationCurves.zip

*编辑 – 我发布这篇文章似乎才 5 分钟,我们就发现了其他有用的框架来帮助独立使用动画曲线。这个 方便的小项目 提供了一些有趣的编辑器增强功能,允许复制、粘贴甚至从曲线中提取动画步骤。这里是 一篇不错的文章 ,它解释了这一切,真是太棒了!


动画曲线

masteringunity2d_03_14

(动画导表曲线视图)

对于那些有所涉猎的人来说,动画曲线主要由新的动画系统使用,它们可以让你精细地控制编辑器属性如何随时间变化,无论是渐变、急剧变化还是根据某种贝塞尔曲线样式。动画表中的曲线编辑器非常强大(并且在每个版本中都在不断更新!)。它基本上允许你

  • 设置一个动画在定义的时间长度内播放
  • 定义动画属性将发生变化的特定时间点
  • 组织动画如何在动画关键帧之间过渡,平滑、急剧、均匀等。
  • 在特定时间触发事件

还有更多,但这些是关键点。都很好,但你知道你可以在动画系统之外使用这个很棒的系统吗?

其核心是,所有动画曲线系统所做的就是根据预设的模式随时间上下改变一个值,这在某些圈子里也被称为缓动。那么,如果你可以创建自己的独立曲线来控制,比如

  • 一个淡入淡出周期——场景或菜单的淡入淡出
  • 控制角色在地图上移动的速度快慢
  • 射击游戏中的敌人路径

缓动系统(如资产商店中的 LeanTween、HoTween 和 iTween)在你的游戏中有很多应用场景。

注意,一条曲线显然无法完全取代上述高级缓动系统,这取决于具体情况,你需要为每个操作使系统复杂到什么程度。没有万能的方法!

那么,如何实现呢?实际上,非常非常容易。

脚本/编辑器属性

我们从需要访问曲线的任何脚本中的一个属性开始,首先创建一个新脚本,比如叫做 AnimationPath ,并用以下内容替换其内容

using UnityEngine;
public class AnimationPath : MonoBehaviour {     public AnimationCurve myTransitionPath;
}

这为我们的曲线提供了一个基础框架,以及一些属性来控制对象从何处开始、到何处结束以及一个计时器。

曲线属性检查器

如果你现在保存它,并在 Unity 中创建一个新场景,添加一个 GameObject(例如一个球体),然后将此脚本添加到它上面,你将在编辑器检查器中看到以下内容:

image

曲线编辑器

我们有一条曲线(孤零零地存在,没有动画系统可以归属),点击 My Transition Path 值的曲线检查器属性,将为你提供独立的曲线编辑器。

image

这有点无聊,因为我们还没有配置它,如果你点击窗口底部的一个预设,我们可以开始创建自己的曲线,或者直接使用预设。

image

从这里,你可以完成在动画导表曲线编辑器中(除了添加事件)可以做的绝大多数任务。你还可以保存你的曲线(如果你创建了一个非常复杂的想要重复使用的曲线),方法是点击左下角的齿轮图标。

image

有很多选项可供选择,但关于曲线本身就足够了,我们想实际使用它来做些事情。回到我们的脚本,我们将启用当用户点击或轻触屏幕时,它会移动附加到它的对象,但会根据我们配置的曲线进行,慢速、快速或以一种奇怪而摇摆的运动方式。

回到脚本

通过对之前脚本进行简单的增强,我们可以添加一些额外的属性来跟踪从一个点到另一个点的过渡,并使用计时器来跟踪时间差。

using UnityEngine;
public class AnimationPath : MonoBehaviour 
{
     public AnimationCurve myTransitionPath;
     Vector3 StartLocation;
     Vector3 TargetLocation;
     float timer = 0;
}

然后我们添加一个简单的 Awake 函数,以检查(提醒你)动画曲线是否已配置,如果没有配置则发出警告(这始终是一个好习惯)。

void Awake () 
{
    if (myTransitionPath.keys.Length < 1) 
    {
         Debug.LogWarning("Transition Path not configured");
    }
}

最后,一个 update 方法来检查输入并将附加到它的 GameObject 从当前位置移动到屏幕上的一个点。在此方法中,我们需要

  • 检查是否有触摸或点击输入
  • 将该触摸/点击转换为世界坐标(在此情况下,为 2D 零化 Z 值)
  • 将起始位置设置为当前 GameObject 的位置,并将目标设置为转换后的触摸/点击点。
  • 最后,根据过渡中的当前时间与曲线上位置的比例,从起始点到目标点对 GameObject 进行 Lerp。

最终的 Update 函数如下所示:

void Update () 
{
         Vector2 playerInputPosition = Vector2.zero;
         if (Input.GetMouseButtonUp (0)) {
             playerInputPosition = Input.mousePosition;
         }
         if (Input.touchCount > 0) {
             playerInputPosition = Input.GetTouch(0).position;
                }
         if (playerInputPosition != Vector2.zero) {
             timer = 0;
             StartLocation = transform.position;
             TargetLocation = Camera.main.ScreenToWorldPoint
                  (new Vector3(playerInputPosition.x,playerInputPosition.y,0));
                    TargetLocation.z = 0;
         }
         if (TargetLocation != Vector3.zero && 
              TargetLocation != transform.position && TargetLocation != StartLocation)
         {
             transform.position = Vector3.Lerp(StartLocation, TargetLocation, 
                                  myTransitionPath.Evaluate(timer));
             timer += Time.deltaTime;
         }
}

需要注意的行是以下这行:

transform.position = Vector3.Lerp
                     (StartLocation, TargetLocation, myTransitionPath.Evaluate(timer));

在这里,我们使用配置的曲线的 Evaluate 函数来确定 GameObject 在当前帧应该移动的量(在本例中)。这会产生以下运动:(请温柔对待,这是我的第一个动画 GIF,现在也得和那些酷孩子混在一起了)

AnimationCurves

正如你所看到的,取决于球体需要 travel 的距离,power curve 开始时很快,停止时很慢,但中间很稳定。只需更改曲线,我们就可以在不更改任何代码的情况下更改行为。

额外学分

为什么就此为止?如何使用两条曲线来创建路径?出于好玩,我创建了正弦和余弦曲线,并将它们应用于球体的 transform,如下所示:

正弦曲线

image

余弦曲线

image

脚本

using UnityEngine;
public class CirclingSphere : MonoBehaviour {
    public AnimationCurve sinPath;
    public AnimationCurve coSinPath;
    float timer = 0;
    void Awake () {
        if (sinPath.keys.Length < 1 || coSinPath.keys.Length < 1) {
            Debug.LogWarning("Transition Paths not configured");
        }
    }
    void Update () {
        timer += Time.deltaTime;
        var pos = transform.position;
        pos.x = sinPath.Evaluate (timer);
        pos.y = coSinPath.Evaluate (timer);
        transform.position = pos;
        if (timer > 2) { timer = 0;}
    }
}

产生以下动画:

AnimationCurvesCircle

诚然,上面的例子在代码中会简单得多,这只是一个更详细的例子。

只是一点额外的乐趣,但你明白了,当你想配置一条曲线来在一定范围内设置动画或插值一个值时,有无数的可能性。

不一定非得是平滑的,你可能会得到这样的结果:

masteringunity2d_06_09

天知道那会用它做什么。 张大嘴巴的笑脸


希望你喜欢这场表演

我希望你喜欢这个小片段。

此片段的示例项目和代码可在以下位置找到: AnimationCurves.zip

一定要在这里查看 AnimationCurves 编辑器扩展 以及关于这些扩展的文章 在这里 !太棒了,社区!

© . All rights reserved.