动作游戏

还记得读书的时候熬夜打《波斯王子》的时光,我们的王子通过跳跃穿过墙壁的小洞、在高层建筑上进行攀爬和跳跃,还有在操作失误掉下高楼和触发必死机关后使用时之沙的时光倒流功能回归死亡之前的开挂技能。

而现在这些功能使用Unity3D的Mecanim都可以非常简单的实现了!

这篇笔记主要记录下Mecanim的3个高级功能:

  1. Animation Curve:可以根据动画的运行时间自定义一条曲线,在播放动画时可以获得这条曲线对应的值,可以实现跳跃穿过小洞的功能;
  2. Target Match:匹配一个预先定义好的点进行动画播放,可以实现人物攀爬的功能;
  3. Animation Record:可以对动画进行录制,然后可以播放录制好的动画,可以实现时之沙的时光倒流功能;

可以说Unity3D现在已经具备了开发一款媲美国际大厂的动作游戏的能力了。

Animation Curve

这里我们直接使用官网给出的示例,打开场景Scale Capsule:

运行游戏,我们发现此时人物是不能通过跳跃穿过墙上的小孔的:

unity右侧工具栏怎么打开_3d

原因很简单,人物的胶囊碰撞体比小孔要大。当我们勾选了右上角的Apply Scale之后,再跳跃试试看:

unity右侧工具栏怎么打开_unity右侧工具栏怎么打开_02

此时我们发现当人物跳跃时,胶囊碰撞体就会进行缩小,而我们的人物就可以钻过这个小洞了,在跳跃之后胶囊体会进行恢复。

我们找到动画文件Dive,就可以看到其设置了两个Curve:

unity右侧工具栏怎么打开_html_03

而其中的ScaleOffsetCapsule就是用来控制胶囊体缩放的曲线,我们可以发现其呈现了1->0->1的一个区间。

然后我们看看参数的设置:

unity右侧工具栏怎么打开_3d_04

参数必须是Float类型同时名称必须和动画文件中的Curve名称一致,这样当我们播放跳跃动画时该参数就会根据预设好的曲线来取值了,注意该参数后方的输入框已经禁用了,不能输入。

最后我们看下脚本ScaleCapsule的实现:

unity右侧工具栏怎么打开_html_05

通过每帧获取参数的值来实现跳跃的碰撞体变小的功能。

Target Match

核心是使用到了Animator的MatchTarget方法,帮助如下:

http://docs.unity3d.com/ScriptReference/Animator.MatchTarget.html

这里我们还是直接使用官网给出的示例,打开场景Target Match:

unity右侧工具栏怎么打开_html_06

我们发现在箱子上方已经做好了一个目标点,我们的人物的右手会匹配到这个点进行动画播放。

需要注意的是,使用MatchTarget的动画必须位于Base Layer层。Match Target会将我们人物的一个部位的位置和目标点的位置进行插值来移动我们人物,结果就是可以通过一个指定高度的攀爬动画来匹配任意高度的攀爬。

我们看下调用的脚本:

1 // Update is called once per frame
 2 void Update () 
 3 {
 4 
 5     if (animator)
 6     {
 7         AnimatorStateInfo state = animator.GetCurrentAnimatorStateInfo(0);
 8 
 9         if (Input.GetButton("Fire1")) animator.SetBool("Jump", true);
10 
11         if (state.IsName("Base Layer.JumpUp") || state.IsName("Base Layer.FullJump")) 
12         {
13             animator.SetBool("Jump", false);
14                             
15             animator.MatchTarget(RightHand.position, RightHand.rotation, AvatarTarget.RightHand, new MatchTargetWeightMask(new Vector3(1, 1, 1), 0), animator.GetFloat("MatchStart"), animator.GetFloat("MatchEnd"));
16             hasJumped = true;
17         }
18 
19         if (hasJumped && state.normalizedTime > 1.2)
20         {
21             hasJumped = false;
22             Application.LoadLevel(0);
23         }
24     }
25 }