Skip to main content

第四部分:Avatar功能的基本构成


很多Avatar的功能确实都很神奇。你可能已经见过了那些功能完备的武器和"特效"。但你的目标很简单,最起码先学会做一个物体开关。接着你在各大视频网站和贴吧论坛找教程,两个小时,昏昏欲睡,最后一步一步跟着做出了一个开关。

But Why?

Avatar的任何功能都基于这样的结构:

Input -> Parameter -> State(Animation)

你进行输入,输入会改变参数,参数满足条件使动画播放

举例,我想要我的手里有一个可以开关的方块,我希望:

当我打开开关的时候,我的手里出现一个方块

当我关闭开关的时候,我的手里的方块消失

而我可以设计一个这样的系统:

有一个参数t用来代表 开 / 关, 初始值是 false (关)

参数t = true时,打开方块:

  • 播放方块c被打开的动画

参数t = false时,关闭方块:

  • 播放方块c被关闭的动画

 那么它的逻辑就是:

我在轮盘菜单里打开方块:

  • 变化参数t = true
    • 方块被打开

我在轮盘菜单里关闭方块:

  • 变化参数t = false
    • 方块被关闭

当在菜单中打开功能时,实际上做的事是将参数t设置为true,参数t是true时播放方块打开的动画

当在菜单中关闭功能时,实际上做的事是将参数t设置为false,参数t是true时播放方块关闭的动画

但你需要知道,输入不仅仅只有菜单。有一些行为也会使得一部分参数变化,你可以未来自己发掘。

e5869904a31c6b6ecb0ed5975c8169db.png

开关方块的流程图

如果你理解方块的开关,那么你也能理解这个

65ec7924e9694ae22be872f32a456991.png

Avatar功能的结构和逻辑关系

Avatar的功能实际上就是利用参数变化和条件来控制不同的动画播放与否

借此来控制不同物体的开关,行为,状态...

什么是动画

动画是Avatar功能中最核心的一环。如果Parameter和逻辑是一台车的车体和传动,那么动画就是发动机和车轮,实际让车动起来的东西。它不仅仅是一系列图片,在Unity中,动画记录任何物体属性无数时刻中某一刻状态比如:

物体A 在开始的瞬间处于位置 (0, 0, 0)

物体A 在第三帧时处于位置 (1, 0, 0)

或者

物体A的位置:

帧1:处于(0, 0, 0)

帧2:处于 (0.5, 0, 0)

帧3:处于 (1, 0, 0)...

 如此一来,当这个动画开始播放的时候,起始时,物体A会移动到位置(0, 0, 0),第二帧时移动到(0.5, 0, 0),第三帧移动到(1, 0, 0)... 以此类推。

任何功能都是通过动画执行达成

image.png

Animation Window,展示一个叫做Sleeve的动画

什么是Parameter

Parameter是Avatar功能中至关重要的一环。它是一台车中的传动系统,要做任何事情都必须通过它来驱动,它记录一个状态

  • 方块是否打开?(是)
    • Bool
  • 启用第几套服装?(第4套)
    • Int
  • 颜色变换多少?(35%)
    • Float

image.pngimage.png

左图:Animator的Parameter; 右图:VRC Expression Parameters的Parameter

同一个Parameter为什么要写在两个地方

你看过的教程都告诉你要将Parameter写在Animator和Expression Parameters里。写在两处有不同用途:

Animator:用于Animator的过度条件

 如果你想使用一个Parameter作为过度的条件,它必须在Animator的参数表里。

Expression Parameter:用于与远端玩家同步,控制Animator的参数以及用于Expression Menu

想象你的游戏在一个盒子中,别人的游戏也在他自己的盒子中,两个盒子有一模一样的场景,物件,安排...等等。你们有在一起的感觉是因为你们看到了对方对这个世界造成的影响。如果要让对方看到你造成的影响,你必须要把信息传递过去

玩家A推动了方块x 到(0, 5, 0)

如果玩家B始终收不到这条信息,那么玩家B的盒子里永远也不会发生玩家A推动方块这件事情,他就永远看不到这个事情发生,即没有同步

 如果把这个情景换成VRChat的Avatar,情况就是:

玩家A的Avatar上一个名为cube_1的parameter从true变成false

  • 方块被关闭了

当一个Parameter被写在了Expression Parameters时,这个Parameter就会被发送给其他人,确保其他人总是会跟上你的Parameter变化

玩家B收到了玩家A的Avatar上一个名为cube_1的parameter从true变成false

  • 玩家B看到你的方块被关闭了

如果Parameter没有被同步给远端玩家,一切变化只会在你的世界里发生,对方什么也看不到

 

Parameter同步,本地,远端的细节是高级话题,不在本篇范围内

image.png

VRC Expression Parameters界面

image.png

Animator主面板和Parameter列表

 

Transition, Condition和Animator

Animator中你需要手动创建动画层才能开始做任何事情。你可以想象动画层是很多张图片叠在一起每一层都会执行它当前所在的动画,然后和下一层叠加起来。如果下一层正在执行的动画和上一层的动画影响了同样的东西,那么以下一层的动画为主

动画层具有权重,这个权重会决定这一层和其他的层如何混合在一起,一般来说会将它设置为

image.png

调整动画层的属性,Weight是权重

你的一切功能都必须在Animator的某一层中完成,而一个动画层中可能包括:

  • 状态
      • 代表了当前这一层所处的状态
  • 动画
      • 一个 状态 里的动画
  • 参数
      • 过度条件以 参数 作为判断条件
  • 过度
      • 允许从一个 状态 前往另一个状态
    • 条件
      • 过度的条件

image.png

Animator,展示了一个动画层,一些状态和过度条件

任何功能都只不过是不同的动画,Parameter和过度一同运作产生的结果。妥善的构思和设计好你的功能应该如何实现。

构思一个功能

如果你想做一个功能,你就必须构思如何去实现它。

如果我想做一把能收起来能开火的最基本的枪,这把枪就可以分成这两个部分:

  • 这把武器有一个开关来控制它拿出来或者收起来
  • 这把武器在我的右手做出开枪手势的时候就开火

那么,首先构思怎么做开关:

用一个Parameter (Bool)来控制武器的开关,当开关 = ture的时候就是把武器拿出来,当开关= false的时候就是收起来

武器开关 = true  播放 武器打开的动画

武器开关 = false 时 播放 武器关闭的动画

然后构思怎么做开火:

右手的手势 = 开枪手势时开火,其他时候什么都不做,而且只有在枪拿出来时才能开火

右手的手势 = 开枪手势 以及 武器开关 = true时 播放开火动画

其中任何一个条件没有满足  播放 武器什么都不做

 到此,这把枪的功能逻辑就基本构思好了,接下来就去把它实现:

image.png

Animator,展示了武器的开关逻辑

image.png

Animator,展示了武器的开火逻辑

Entry, Exit和Any State

Entry, Exit和Anystate是Animator中的一些特殊状态,它们有不同于一般状态的功能

Exit

Exit是一个出口,当过渡到这个State离开的时候,就会从Entry再开始。你需要注意的是,任何动画层都不一定最后必须从Exit离开只要达到了目的,从Exit离开与否并不重要

Entry

Entry是Animator中一层开始的地方,当一个Avatar加载完成时或者经由Exit离开时,就会从这里开始。

Anystate

这是最特殊的一个State。一般来说,State之间必须有Transition才能进行过度。但如果某一个State和Anystate相连,只要满足了条件无论当前是在哪个State上都会过渡到与Anystate相连并且满足条件的State。

image.png

Animator界面,展示一个Anystate用途的情景

在这个例子中,理论上永远也无法到达状态C,但将状态C与Anystate连接并且设置条件之后,无论当前是在状态A还是B,只要满足条件就会从Anystate过渡到状态C,但到达状态之后就无法回到状态A和B了,因为没有过度

VRC Expressions Menu

这是控制Parameter最常见的方式。Expression Menu包含Avatar的轮盘菜单里的内容,用于控制Expression Parameters列表里的Parameter,你可以在一个菜单页面内设置最多8个控制

虽然一个页面最多只有8个控制,但你可以选择菜单里设置二级菜单,设置三级菜单... 以此类推。除此之外,你也可以选择某个控制展示的文字图标类型(按住,切换,转轮... 以此类推) 以及最重要的,它控制的Parameter

Expression Menu只可以控制在Expression Parameters表内的Parameter

image.png

VRC Expression Menu的界面

Expression Menu和其他组件的关系看起来像这样:

f7c5ea84645d0e32b954a7d78d4d9f0d.png

Expression Menu和其他组件的逻辑关系