Unity开启篇(七) —— Unity动画简介 (二)

版本记录

版本号 时间
V1.0 2019.01.05 星期六

前言

Unity是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。Unity类似于Director,Blender game engine, Virtools 或 Torque Game Builder等利用交互的图型化开发环境为首要方式的软件。其编辑器运行在Windows 和Mac OS X下,可发布游戏至WindowsMacWiiiPhoneWebGL(需要HTML5)、Windows phone 8和Android平台。也可以利用Unity web player插件发布网页游戏,支持Mac和Windows的网页浏览。它的网页播放器也被Mac 所支持。网页游戏 坦克英雄和手机游戏王者荣耀都是基于它的开发。
下面我们就一起开启Unity之旅。感兴趣的看下面几篇文章。
1. Unity开启篇(一) —— Unity界面及创建第一个简单的游戏 (一)
2. Unity开启篇(二) —— Unity界面及创建第一个简单的游戏 (二)
3. Unity开启篇(三) —— 一款简单射击游戏示例 (一)
4. Unity开启篇(四) —— 一款简单射击游戏示例 (二)
5. Unity开启篇(五) —— 一款简单射击游戏示例 (三)
6. Unity开启篇(六) —— Unity动画简介 (一)

Switching Between Animations – State Machines 101

到目前为止,您已创建了动画片段(Animation Clips)。 您可以运行它们中的每一个,但无法更改在游戏过程中播放哪一个动画。 这是状态机用武之地的地方。

当您创建第一个动画片段时,Unity已经为小丑创建了一个状态机。 您可以在Animator View中查看它。 为此,请在层次结构中选择Clown,然后从菜单中选择Window \ Animator。 您现在应该看到Game选项卡旁边的Animator选项卡。

已经有几种状态:MoveHorizontallyMoveVerticallyHitEntryExitAnyState。 基本上,每个状态对应于只要状态处于活动状态就正在播放的动画片段。

您还会看到一个从EntryMoveHorizontally的箭头。 这意味着MoveHorizontally是默认状态,即状态机首次激活时所处的状态。 它是橙色的。

注意:如果您的屏幕很小并且没有看到所有状态,请不要担心。 只需按住alt键并用鼠标左键移动鼠标即可在Animator View中导航。

状态的布局不会影响行为,所以请随意以适合您的方式安排状态 - 只需拖动它们即可。

1. Your First Transition

到现在为止还挺好。 现在,您希望小丑在相应动画结束后立即在MoveHorizontallyMoveVertically之间切换。 从一种状态切换到另一种状态称为转换。

要创建第一个过渡,请右键单击MoveHorizontally。 从下拉菜单中选择Make Transition,然后单击MoveVertically。 这创造了两个状态之间的过渡。 对于相反的方向,从MoveVerticallyMoveHorizontally执行相同的操作。

玩游戏:小丑现在从左向右移动,然后向上和向下无限移动。

但是有一些奇怪的事情发生了:小丑在各状态之间切换时cutting corners。 你从来没有告诉它这样做。 这是怎么回事?

要回答这个问题,请在游戏运行时选择Inspector中的Clown并切换到Animator View。 您将看到处于当前活动状态的进度条(progress bar )。 仔细观察并看到,当MoveHorizontallyMoveVertically两个状态同时具有进度条时,存在短暂的时间段。 这意味着Unity一次运行两个状态,将一个状态与另一个状态混合。

混合状态可能很有用;例如,当你有一个从步行过渡到跑步的角色时,这看起来更自然。 但是也有一些情况你不想混合两种状态。 幸运的是,Unity为您提供了允许您控制转换的设置。

Animator View中,单击从MoveHorizontallyMoveVertically的过渡箭头。 在Inspector中,您现在可以看到控制转换的设置。 通过单击旁边的三角形展开设置。 将Exit Time设置为1,将Transition Duration设置为0。对从MoveVerticallyMoveHorizontally的过渡执行相同操作。

运行游戏。 现在,小丑将水平和垂直移动,但不能同时移动。

再看一下过渡设置:

  • 退出时间(Exit Time)确定是否可以在任何时间触发转换,或仅在指定的退出时间之后触发转换。
  • 退出时间是转换开始之前的最早时间。它以标准化时间表示。退出时间0.75表示仅在动画完成75%时才开始转换。
  • Transition DurationFixed Duration允许您指定转换所需的时间。如果启用了Fixed Duration时间,请以秒为单位指定持续时间。否则,请在标准化时间内指定持续时间。
  • Transition Offset控制在转换到的目标状态下开始播放的时间的偏移量。例如,值为0.5意味着目标状态将在其自己的时间轴的50%处开始播放。
  • 中断源控制(Interrupt Source)是否可以中断转换,例如,当触发另一个转换时。

有时很难想象这些参数意味着什么。值得庆幸的是,转换图(Transition Graph)直接位于检查器中的转换设置下方,可以精确地显示每个动画的配置方式:

2. Just do it! – The Any State

无论小丑目前处于什么状态,每当小丑被蛋糕击中时,你都会想要运行一个命中Hit动画。你怎么能实现这个目标?

根据您到目前为止所学到的,您可能只需创建两个到Hit状态的转换:一个来自MoveHorizontally状态,另一个来自MoveVertically状态。 虽然这会起作用,但它不会扩展。 想象一下,你有一个使用十个状态的更复杂怪物的游戏。 你可以创建十个转换,但它会变得混乱,我们希望尽可能简单。

您可能已经注意到任何状态(Any State)的绿松石盒子。 它基本上是绘制从所有状态到单个目标状态的转换的简便方法。 完善!

右键单击AnyState,选择Make Transition,然后单击Hit状态。 现在您的Animator View应如下所示:

Hit动画完成后,状态应转换为MoveHorizontally状态。

尝试自己做。 如果你遇到困难,请查看:

右键单击Hit,然后选择Make Transition并单击MoveHorizontally以创建过渡。 选择它。 在Inspector中,将Exit Time设置为1,将Transition Duration设置为0。

3. Control State Switches Using Parameters and Conditions

接下来你需要告诉Unity何时应该在Any StateHit之间进行转换,因为这不应该自动发生。 你只希望Animator在小丑被击中时切换到Hit状态。

为此,您可以使用参数和条件(parameters and conditions)。 参数是您在Animator上指定的变量。 您可以使用它来定义特定转换发生的条件。

以下是它在实践中的工作原理:

Animator View的左上角,选择Parameters选项卡。 单击+按钮。 从下拉菜单中,选择Trigger。 这会创建一个新的触发器。 命名它hit。 而已! 您现在是第一个参数的自豪拥有者。

CreateParameterCropped

接下来,选择从任意状态到Hit的过渡箭头(transition arrow)。 在“检查器”中,滚动到Conditions部分。 现在它显示List is Empty。单击+按钮。 这会将命中触发器添加为条件。

一旦参数hit变为true,现在将触发转换。

要手动尝试,请将动画视图拖放到游戏视图旁边,以便您可以同时查看两者。 运行游戏。 在Hierarchy中,选择Clown。 在Animator视图中,单击hit参数后的radio button。 你会听到飞溅声,然后小丑重置。 很棒 - 您的动画控制器按预期工作。

4. Types of Parameters and Combining Conditions

触发器很有用,但当然可以使用更多参数类型:

  • Float:分数(0.1,0.999,6.31,......)
  • Int:整数(1,5,13,1005,......)
  • 布尔:True or False
  • 触发器:布尔参数,一旦转换消耗,就会重置为false

可根据您的要求使用每种类型。 例如,Int可以计算玩家第10次击中小丑并播放特殊动画的频率。

此外,您可以为Animator View的参数列表中的每个参数指定默认值。

条件(Condition)用于决定何时应发生转换。 您可以在转换上定义多个条件。 在这种情况下,必须满足所有条件才能触发转换。

你还可以表达,例如,如果小丑被击中或者时间限制到了,小丑应该转换到命中状态。 为此,在Any StateHit状态之间创建第二个转换。 在Inspector中,您现在可以看到两个过渡。 对于每个转换,您可以单独定义触发条件。


Bull’s Eye – Combine Animations and C# Scripts

到目前为止,您已经看到Unity的动画系统有多强大和灵活,即使没有一行代码也是如此。 但是,当然,使用代码非常有趣,因此从脚本中触发动画就是接下来要学习的内容。

1. Trigger an Animation From Code

在对碰撞做出反应之前,您需要能够检测到它。 在层次结构中展开小丑并选择其子皮肤(Skin)。 在Inspector中,单击Add Component并选择Physics \ Mesh Collider。 在新的Mesh Collider组件中,勾选Convex

你现在可以看到小丑皮肤周围的薄绿色边框。 当然,形状并不完全适合小丑,但它足够接近。

试试看。 运行游戏 - 蛋糕(因为它也有一个Collider)不再飞过小丑。

要在代码中检测此冲突,请在“检查器”中选择Skin。 单击添加组件Add Component,然后选择新脚本New Script。 将脚本命名为CollisionBehavior,将Language设置为C Sharp,然后按Create and Add

当另一个Collider碰到小丑的Mesh Collider时,它会触发OnCollisionEnter。 通过双击项目浏览器中的文件,在MonoDevelop中打开CollisionBehavior

在行void Start()上面的CollisionBehavior中添加以下代码:

// 1
public bool collided;

//2
void OnCollisionEnter(Collision collision) {
  if (!collided) {
    collided = true;
    // 3
    GameObject clown = gameObject.transform.parent.gameObject;
    Animator clownAnimator = clown.GetComponent<Animator> ();
    // 4
    clownAnimator.SetTrigger ("hit");
  }
}

下面进行详细分解:

  • 1) 创建一个bool变量,记住小丑是否已经碰撞过。
  • 2) 如果小丑还没有碰撞,则仅触发动画。 下一行设置collidedtrue,以确保您只触发一次Hit动画。
  • 3) 获取Clown GameObject,它是当前gameObject的父级,然后使用GetComponent检索Animator
  • 4) 在clownAnimator上调用SetTrigger。 这使得动画师进入了Hit状态。 对于其他参数类型,您可以使用SetFloatSetIntSetBoolResetTrigger

运行游戏,进行投掷。 当你设法击中小丑时,它会发出哗然的声音!

2. State Machine Behaviors: React to State Changes in Your Scripts

状态机行为(State Machine Behaviors)允许您编写依赖于状态的行为。 例如,只要它处于Hit状态,你就可以使小丑缩小。 试试看:

Unity中,转到Animator View并选择Hit状态。 在Inspector中,单击Add Behavior。 选择New Script,将其命名为ClownHitBehavior,然后按Create and Add

双击ClownHitBehavior打开它。 你可能会注意到Unity已经添加了一些被注释掉的方法。 不要担心它们 - 你会很快了解它们的作用。 而是专注于缩放小丑!

为此,请在ClownHitBehavior中添加startTime变量。

float startTime;

此变量将存储进入Hit状态的时间。 您可以使用它来控制动画的速度,具体取决于实际时间而不是帧速率。 这确保了无论游戏运行速度有多快,小丑都会以相同的速度收缩。

接下来,查找(注释掉)OnStateEnter方法。 在此方法中,您设置startTime的值。 替换为:

override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
  startTime = Time.time;
}

当状态机进入命中状态时调用OnStateEnter。 使用Time.time,您可以检索自游戏开始以来的秒数。 虽然创造一个时钟并不是那么好,但这对于缩小你的小丑还是很有效的。

接下来,查找OnStateUpdate方法并将其替换为以下代码:

override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
  GameObject clown = animator.gameObject;
  clown.transform.localScale *= Mathf.Lerp (1, 0, Time.time - startTime);
}

Hit状态处于活动状态时,每个帧都会调用OnStateUpdate。在每一帧中,您都可以调整小丑的大小。

为此,您首先需要找到Clown GameObject。当脚本在Animator组件上运行时,您不能像以前那样通过gameObject简单地访问它。相反,请为该gameObject询问该方法的animator变量,然后将其存储在clown变量中。

接下来,使用Mathf.Lerp更改Clown GameObject的比例。该方法在两个数值之间线性插值linearly interpolates

例如,屏幕上有两个不同的点。一个是y位于左边0,另一个是y位于右边的20处。传入.50Math.Lerp将返回中间的一个点。

使用三个参数调用Math.Lerp:它们之间插入的两个值,在本例中为10,以及自Hit动画开始以来的秒数。 Lerp然后计算得到的比例。例如,在0秒时它将返回1,在1秒时它将返回0,在0.75秒时它将返回0.25。

在小丑打击和投掷蛋糕直到你hit命中 - 小丑缩小,再也不会再出现。一场短暂的游戏!

注意:如果您想知道状态机行为中的其他方法是什么:

  • OnStateEnter:在正在播放的状态的第一帧上调用OnStateEnter
  • OnStateUpdate:在每个帧上更新MonoBehaviors之后调用OnStateUpdate,同时播放它所附加的行为的状态。
  • OnStateExit:在转换到另一个状态的最后一帧上调用OnStateExit
  • OnStateMove:只要状态正在播放,就会在每个帧的MonoBehaviors上调用OnStateMove而不是OnAnimatorMove
  • OnStateIK:Unity计算人形角色的反向运动学 Inverse Kinematics后调用OnStateIK - 例如,允许它抓取项目。

3. Animation Events: Trigger Code From Your Animation

是时候让小丑再次适应值班。 一个很好的方法是通过Animation Events,它允许您在动画片段运行时从游戏对象的脚本中调用函数。

首先,您需要一个脚本,其方法可以重置小丑的大小。 在层次结构中选择小丑。 在“检查器”中,滚动到底部,然后单击Add Component。 选择New Script并将脚本ResetClown命名为C Sharp。 点击Create and Add

MonoDevelop中打开ResetClown脚本并添加以下代码:

void ResetClownOnHit () {
  gameObject.transform.localScale = Vector3.one;
  gameObject.GetComponentInChildren<CollisionBehavior> ().collided = false;
}

在此方法中,将小丑的localScale设置为1以恢复其原始大小。 然后使用GetComponentInChildren()引用Skin上的CollisionBehavior并确保其碰撞变量设置为false。 如果你省略这一步,你的小丑仍然会移动,但不会再对碰撞作出反应。

现在您需要创建一个调用此方法的Animation Event。 在“层次结构”中选择“小丑”时切换到Animation View,然后选择Hit动画片段。 在时间线中将播放头设置为1:30。 如果您的时间线在1:00以后不可见,请使用滚轮将其缩小。 然后单击Add Event按钮。

双击刚刚创建的动画事件的marker

在对话框窗口中,选择ResetClownOnHit()

这将创建一个动画事件,在1:30调用ResetClownOnHit()方法。

运行游戏。 现在小丑缩小了,然后重新开始并再次开始移动,准备再被蛋糕破坏了!

在本教程中,您可以看到Unity动画系统的可能性。 但是要知道你还有很多需要学习,下面是一些阅读建议:

后记

本篇主要讲述了Unity动画简介,感兴趣的给个赞或者关注~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容