Unity3D的Animator.MatchTarget3D怎么用使用?

Unity——UGUI开发设计及案例讲解

Unity4.6跟以前嘚版本的最大区别首先在于在层级视图中点鼠标右键时出现的弹出菜单上它把以前许多的菜单项进行了归类,比如cube sphere capsule….等整合到“3D Object”子菜單中而且多出一个UI子菜单,它就是UI组件了

    当我们点击UI->Canvas时,就会在场景视图里创建一个画布不过视图默认是3D显示方式,在Unity4.3以后增加叻一个2D与3D转换按钮,单击此按钮可在3D与2D显示样式之间转换 

    UI是2D,为何还要3D呢在做一些比较复杂的项目时,给用户看时是2D但我们编辑时,有时还是要用到3D模式的

Canvas是画布,所有的UI组件就是绘制在这个画布里的脱离画布,UI组件就不能用

    创建画布有两方式。一是通过菜单矗接创建二是直接创建一个UI组件时,会在创建这个组件的同时自动创建一个容纳该组件的画布出来

    不管那种方式创建出画布时,系统嘟会自动创建出一个EventSystem组件这是UI的事件系统。

Canvas组件的三种渲染模式


此模式不需要UI摄像机UI将永远出现在所有摄像机的最前面(即在某个UI的湔面是不能再添加其他组件的),就好像是给摄像机贴上了一层膜它的最大好处是不需要摄像机,不需要灯光


此模式需要提供一个UICamera,咜支持在UI前方显示3D模型与粒子系统等内容

    当挂上摄像机并选择3D显示模式时,我们选中这个摄像机并移动它,可发现画布会跟随摄像机嘚移动而移动且Game视图显示的UI其位置与大小均保持不变,如下图所示:

    这种模式虽然UI的显示效果与第一种模式没有什么两样,然而因茬画布与摄像机之间可放置三维物体或粒子系统,那么就可做出许多绚丽的特效


这一项是设置Canvas与摄像机之间的距离,其值越大可在画咘与摄像机之间放很多的三维物体,默认是100建议设置为100与200之间即可。


这个就是完全3D的UI也就是把UI也当成3D对象,如摄像机离UI远了其显示僦会变小,近了就会变大

 当有多个画布时,决定谁在前谁先显示。




    在不同分辨率下控件显示的大小有所不同,这要根据实际情况综匼考虑

    此模式下会出现Match调节滑杆,调节其控块位置也会影响UI元素显示的大小。


当我们初次创建Panel后它会充满整个画布,如下左图:


此時通过拖动该面板控件的4个角点或四条边可调节面板的大小如上右图

面板实际上就是一个容器,在其上可放置其他UI控件当移动面板时,放在其中的UI组件就会跟随移动这样我们可以更加合理与方便的移动与处理一组控件。也就是通过面板我们可以把控件分组。一个功能完备的UI界面往往会使用多个Panel容器控件。而且一个面板里还可套用其他面板

当我们创建一个面板后,此面板会默认包含一个Image(Script)组件:


该組件中的Source Image是设置面板的图像

Color,可改变面板的颜色

当我们创建一个画布时,Unity系统会自动为我们创建一个EventSystem


该事件处理器中有3个组件:

如果我们将Event System (Script) 前的勾去掉,则管理整个场景的事件系统则不起作用了此时运行程序,如果有Button单击它时就不会有反应了。

在UGUI中我们所创建嘚所有UI控件,它们都有一个UI控件特有的Rect Transform组件:


我们所创建的三维物体是Transform,而UI控件是Rect Transform它是UI控件的矩形方位,其中的 指的是UI控件在相应轴仩的偏移量

UI控件除了上面Rect Transform控件外,每个UI控件都还一个 组件它是画布渲染,一般不用管它因它不能点开的。

Text控件的相关属性:

 :设置攵本在Text框中的水平以及垂直方向上的对齐方式

 :水平方向上溢出时的处理方式。它有两种:Wrap隐藏;Overflow溢出

 :垂直方向上溢出时的处理方式。它有两种:Truncate截断;Overflow溢出

隐藏了或截断了,信息显示不全当然不好但如果溢出又会破坏版面,想两全齐美的话就可选中: ,如果攵字多时它会自动缩小以适应文本框的大小,当选中该项后在其下边会出现Min Size与Max Size两输入框,可设置字体变化时的最小与最大值


Image是要显礻的源图像,但如果我们把一个普通的图像往里拖放时却不能成功放入,认真研究一下不难发现放图像的框中,除了None表示还没有图像外还有一个括号注释的Sprite,它的意思是精灵可理解为它是贴图的一种特殊形式,它不具备其他功能只给UI做显示图片用,故我们给它取叻一个特殊的名字:精灵Sprite所以在Unity4.6中,要想把一个图片赋给Image则需要把该图片转换成精灵格式,转换方法为在Project中选中要转换在图片,然後在Inspector检视图中单击Texture Type(纹理类型)右边的下拉框,在弹出的菜单中第三项Editor GUI and Legacy GUI是Unity4.6以前版本所用的,选中它时图片不会被拉伸,现在几乎不鼡是为了兼容,而第四项Sprite(2D and UI)就是4.6版本所用的,它虽然比前一项适用的范围更窄但其效率更高。我们选中该选项Sprite(2D and UI)并点击下方的Apply(应用)按钮就可把此图片转换成精灵格式随后就可拖放到Image的Source Imag中了,如下图所示:


另:当我们把一个普通的图片转换成精灵格式后在Project中,将发現该图片将包含一个子对象如图: 以后可以把一个图片划分为多个图片。

当我们把精灵图片赋给了Image后其组件样式如下图:


Color:可改变图爿的颜色;

Material:材质,这是针对一些复杂的贴图使用

Image Type:贴图的类型,这是最重要的属性



Preserve Aspect:翻译过来是:维持外貌,选中该项后该精灵圖片的长宽比将保持原状,当调节图片的大小时它将在保持原长宽比的前提下尽量铺展到图片框中,即不会拉伸或压缩以适应图片框而鋪满

Set Native Size:本来的大小。如果调整后大小变乱了单击此按钮,可将此图片设置成本来的大小

应用该种类型时应先将贴图进行“九宫格”處理后才可以应用。否则其下会出现黄色的警告  This Image doesn’t have a border:这个图片没有边框如下图:



在这个Sprinte Editor视窗中,我们可以拖动图像四条边上的绿色线調节九宫格的布局大小,调好后单击顶端的Apply按钮应用即可回到Image的检视图中,我们将发现原来的警告消失了:


在Image Type为Sliced时当对图像进行大小調节时,其中心会缩放以适合矩形但边界会保持不变,这样当你显示不同尺度图像时不用担心扩大与缩小时其轮廓会发生变化。如果伱只想要边界不要中心,可以禁用Fill Center(填充中心)属性


图像保持其原始大小,重复多次填补空白这往往用于做背景。

图像填充满整个Image矩形区域再结合Fill Amount属性,可做一些特效

当图片类型为Filled时,其Image组件的属性视图如上图所示其Fill Method(填充方法)选择框中有5种:

Horizontal:水平填充,洳果我们手动拖动Fill Amount(填充数量)滑块就可看到图片在水平方向上的填充变化(动画),如下图列所示:


Vertical:垂直填充同理当我们手动拖動Fill Amount滑块,就可看到图片在垂直方向上的填充变化(动画)如下图列所示:


Radial 90:径向90度填充,同理当我们手动拖动Fill Amount滑块就可看到图片在90度方向上的填充变化(动画),如下图列所示默认是以左下角为圆心,顺时针90度填充


Radial 180:径向180度填充,同理当我们手动拖动Fill Amount滑块就可看箌图片在180度方向上的填充变化(动画),如下图列所示默认是以底边中点为圆心,顺时针180度填充


Radial 300:径向180度填充,同理当我们手动拖动Fill Amount滑块就可看到图片在360度方向上的填充变化(动画),如下图列所示默认是以图片的中心点为圆心,顺时针360度填充

如果我们使用脚本來控制Fill Amount的值,就可制造出这五种动画来为特效的制作增加了一些有效的手段。


组件Image(Script)里的属性与前面所讲的Image控件的Image(Script)组件里的属性是一样的例如Source Image的图像类型仍为一个Sprite(精灵),通过为此赋值就可改变此Button的外观了,如果你为属性赋值了图片精灵那么此Button的外观就与此精灵一致了。

Button是一个复合控件它中还包含一个Text子控件: ,通过此子控件可设置Button上显示的文字的内容、字体、样式、字大小、颜色等与前面所講的Text控件是一样的。


如果你把其后的对勾 去掉此Button在运行时将点不动,即失去交互性了

它有四个选项 ,默认为Color Tint(颜色色彩)

None:没有过渡方式

Sprite Swap:精灵交换。需要使用相同功能不同状态的贴图


4) Animation:动画。最复杂效果最绚丽。


Contoller(新建动画控制器)窗口要求你选择动画存放的路径,所以我们要先在Project中新建一个文件夹专门用来存放动画,比如此文件夹取名为_Animator此时就可选中此文件夹,并给此动画取名(动畫的名默认为该Button的名字当然其扩展名为controller),创建成功后会在Project中的_Animator文件夹中可看到刚才创建的动画文件(动画的名默认为该Button的名字),苴在这个Button的Inspector检视图中可看到会为此Button增加一个Animator组件:


此组件的Controller的属性值就为刚才创建的动画双击它即可打开该动画的Animator窗口,其中记录的有㈣个动画:Normal、Highlighted、Pressed、Disabled(通常状态、鼠标经过状态、按下状态、失效状态)如下图所示:


其实这个动画还没有,要做出这个动画需先选中這个Button,然后点击系统菜单Window->Animation(注意不是Animator)就会打开一个Animation动画编辑窗口:


我们以此工具先来做一个简单的帧动画,在帧数框上单击一下原來的0便会选中,此时输入数字1表示对第1帧做动画,此时的录制按钮 以及系统的播放按钮 和动画编辑窗中的帧数线均会变红表示现在处於记录模式,你所做的操作会记录成动画的动作如下图所示:


假设我们想使它在第一帧时,该按钮变大一点我们就在Inspector中的Rect Transformr的Scale中操作,仳如在x与y轴向上均增大到原来的1.05倍(因UI是在x-y平面上显示故不需设置Z值),如下图所示:


同理当第一帧设置完后,我们在帧数框中直接輸入数字2就可编辑第2帧的动画了,比如在x与y轴向上均增大到原来的1.1倍再继续设置第3帧在x与y轴向上均增大到原来的1.15倍,假设我们现在就呮做这3帧动画已经完成了,那么我们点击一下那个处于红色晕光状态下的录制按钮 结束录制,再保存一下场景就会发现在Project视图中_Animator/Button1下會增加4个动画文件Disabled、Highlighted、Normal、Pressed(如果不保存将看不到这4个动画文件),这四个动画剪辑就是源于我们刚才的录制虽然刚才我们只录制了一次,而系统会为我们自动产生这四个动画文件

动画成功制作出来了,可运行起来看看效果了但当我们运行起来时,就会发现那个按钮会洎动无限次地播放那个动画看起来就是不断地颤动,那么是什么原因呢

我们在Project视图中,选中任意的一个动画剪辑比如Disabled在其Inspector视图中可看到它的Loop Time属性是处于选中状态,意思是循环播放那么我们把它去掉即可。


而这里如果我们只去掉Disabled的Loop Time还是不行的,当然把这4个动画剪辑嘚Loop Time全去掉是能成功的那么到底是那个剪辑在起作用呢?实际上是Normal所以我们只需去掉Normal的Loop Time即可。其原因请看下列叙述

我们先在Hierarchy视图中选Φ那个做了动画的Button,再单击系统菜单Window->Animation(注意不是Animator)就会打开刚才的动画编辑窗口:


单击其中的Normal框,会出现下拉选择:



在Button组件的下方有一個OnClick()选项这就是Button控件处理事件的重要机制。

OnClick()意思为当该按钮被点击时所发生的事件而此事件在UI中是委托机制,要理解这个机制我们先莋一些准备工作。







这是系统默认的文件内容现在我们要把它应用于UI,故必须引入UI的命名空间即脚本的首部增加一行:using UnityEngine.UI;。

假设我们单击┅个按钮后让系统在后台显示一句话:点击了Button!,那么我们可以在此脚本中增加一个方法该方法为公共的public,假设方法名为DisplayInfo:


此时整个腳本文件的内容如下:







2) 在Hierarchy视图的Canvas中创建一个空对象并假设命名为Event,并把上面的脚本作为组件挂到这个空对象上那么这个对象是具有倳件处理能力的object了。

为某个按钮添加其事件处理的委托对象

我们在层级面板中选中要产生单击事件的按钮比如Button1然后拖动其Inspector面板右边的滚動条,使其Button(Script)组件下的OnClick()显现出来:


此时其事件列表为空:List is Empty我们单击其下的“+”按钮为其添加一个事件:


此时事件虽被添加了,但其委托的倳件处理对象为空:None(Object)当然连事件处理对象都没有,其事件处理方法自然也就为空:No Function(Runtime Only此项我们可先不管它,以后用到时再讲)

那么怎樣委托事件处理对象与选择事件处理方法呢

很简单,我们把层级面板中刚才建好的并已挂上了事件处理脚本的Event对象拖放到None(Object)框中即可此時此框中显示的内容即为委托的此事件处理对象的名称了:Event,有了事件处理对象了然后使用该对象的什么方法来处理事件呢?这还需我們给它指定其方法是单击显示内容为No Function的那个事件方法框,会弹出菜单列表:


当我们的鼠标指向最后一项ButtonEvent时会继续展开其中就有我们在腳本中编写的事件处理方法:DiaplayInfo(),选中它即可这样就完成了事件的委托,当我们运行时单击那个Button,就会在后台里打印出“点击了Button!”

┅个按钮可以有多个处理事件。

下面我们采用另一种显示信息的方式

我们先在场景中的画布上增加一个Text控件,同时设置好相关的显示样式然后在那个脚本中增加一个公共变量:public Text Txt_Info,回到场景视图中在层级面板中选中挂有该脚本的对象Event,在其Inspector视图的ButtonEvent脚本组件里就会出现刚財增设的公共变量名:Txt_Info(脚本需保存且界面需刷新)我们可把增加的那个Text拖到此处即可为此变量赋值了,接下来我们就可通过脚本修改這个文本框控件的Text属性让打印在后台的信息显示在这个文本框上了。其脚本文件内容如下:













然后再给那个Button增加一个单击事件(委托的事件对象仍为Event方法则设为DisplayInfoText ()):


再次运行程序,单击按钮时后台输出“点击了Button!”的同时,场景中的Text文本框的内容内变为:Button被点击了!

仈 Anchor锚点与屏幕自适应

每个控件都有下Anchor的属性,其作用是当改变屏幕分辨率的时候当前控件做如何的位置变换。即控件的屏幕自适应

当峩们创建一个Canvas后,在层级视图中选中它后我们将发现这个Canvas在场景视图中的样式如下图所示:


这个Canvas除四边、四个角点外,其中心还有一个藍色的小圆圈这个小圆圈即为这个Canvas的中心点。

如果此时我们在此Canvas上创建一个Button如下图所示:


Button同理也有四条边、四个角点、一个中心点,此时我们选中Button在Canvas中心点位置会出现一个小雪花图案 ,这就是Button在Canvas上的锚点可用鼠标拖动它,且拖动的过程中会实时显示此锚点距上、下、左、右的百分比如下图所示:



如果我们单击  时,其锚点就会跑到Canvas的右上角如下图所示:


同理单击其他位置时,也就把锚点调整到相應的位置上即可把此锚点调整到画布的中心点上、四个角上、四条边的中点上。

以上是锚点整体移位实际上,我们还可以拖动小雪花Φ的任意一个花瓣使其分散成四个锚点,如下图所示:


当我们单击 这个窗中的最右边或最下边中一些按钮可将锚点分散在两边或上下或㈣个角点上

原来这个雪花状的锚点是由四个锚点组成的复合体。

说了这么多那它到底有什么用途呢?

如图: 当屏幕大小发生改变时,Button的四个角点与对应的4个锚点的距离会保持不变从而保证布局不会随着屏幕大小或者分辨率的改变而改变,可相对有效地保证布局不会混乱以达到屏幕自适应的目的。

但要注意控件的锚点总是相对于自己的上一级来定义的。例如我们再在这个Canmas中创建一个Panel并调小它的夶小,在Panel中创建一个Text我们去调节这个Text的锚点时我们将会发现这个锚点总是相对于Text的上一级Panel来定义与变换位置的。

两个Text控件分别命名为:Tex_UserName与txt_Password,其Text值分别为“用户名称:”与“登录密码:”

这两个输入域控件是前面还没有介绍的新控件在其层级Hierarchy视图将其展开 ,可发现它也為一个复合控件在主控件上还包含两个子控件,一个为Placeholder与Text其Text就是前面所介绍的文本控件,程序运行时用户所输入的内容就保存在这个TextΦ而Placeholder是占位符,它表示程序运行时在用户还没有输入内容时显示给用户的提示信息在这里我们把它设置为“请输入…”,设置方法是茬层级视图中展开这个InputField控件选中其子控件Placeholder,在Inspecter视图中可发现其Text(Sript)组件修改其值为“请输入…”即可,如下图所示:


InputField控件与其他控件一样也有Image(Script)组件,自身组件InputField(script)中也有变换Transition属性其默认值也为颜色变换,除此之外它有一个重要的属性:ContentType(内容类型),有10个选项如下图:


據此,我们把第一个InputField的内容类型设为第5个Alphanumeric:字母数字第二个InputField的内容类型设为第8个Password:密码,这样程序就可启用其自动验证功能例如在用戶名称输入框中如果你输入的不是字母或数字则不能输入进去,第二个密码框中输入密码时它会默认以*号占位输入的密码

    3、创建一个Text,鼡于显示登录是否成功等提示信息用在其Inspector视图中,去掉其默认显示的内容即让其才开始运行时不显示任何内容,并把其Best Fit勾选上让其提示信息自适应文本框的大小:


4、最后创建一个提交按钮,其整个界面如下图所示:


5、创建脚本(红色部分为新增内容):




















脚本创建好了後我们在Hierarchy中创建一个空对象,命名为_LogonSystemEvent对把这个脚本挂在它身上,而且在其Inspector视图中为其3个公共变量赋值(把相应控件拖放到对应变量嘚值框中):


运行程序,如果用户名称或密码错误提示信息框中会显示:用户名称或登录密码错误 请重新输入!,否则显示:登录成功!如下图所示:


十、Toggle控件动态事件

Toggle:开关,当我们创建它后 可发现它也为一个复合型控件 ,它有Background与Label两个子控件而Background控件中还有一个Checkmark子子控件,如果我们将其拖散 可清楚地看见Background 是一个图像控件,而其子控件Checkmark 也是一个图像控件其Label控件 是一个文本框,它们与我们所讲的控件昰一致的我们通过改变它们所拥有的属性值,即可改变Toggle的外观如颜色、字体等等。下面来看看Toggle的一些重要属性

Is On:目前是处于开还是關。

    当我们运行起来用鼠标点击那个Toggle按钮,将发现其中的对勾符号会在出现与不出现之间切换同时与之相对应的,在其Inspector面板中属性In On後面的对勾也在勾选 与不勾选 之间切换。

实际上用鼠标点击那个Toggle按钮,其对勾符号会在出现与不出现之间切换它的原理就是控制那个對勾图像出现与不出现而实现的,这个Graphic就是设置这个属性值的你可点击 最后那个设置按钮 ,在出现的窗体中 选择另外的图像如Background同时将 Φ的Target Graphic的值设为Checkmark,即将它们两者的值互换将发现,当我们点击Toggle按钮时其对勾不会消失与出现,而是背景消失 与出现 这样做虽然没有多夶实用价值,但说明Unity可以方便地控制这个按钮的外观

Group:组(单选框功能)

在Hierarchy面板中,选中我们刚才创建的Toggle然后按键盘Ctrl+D两次,就可复制絀两个Toggle了并在场景视图中拖动它们的位置,使它们都可见运行,我们将发现这个三个都可选中即它们是复选框。

那么怎样做出单选嘚效果呢

前面所创建的按钮是独立的,互不关联当然就可独自地选与不选。如果我们把这三个组成一个组让它们关联,就可做成单選了


我们先在画布上建立一个空对象,并命名为_ToggleGroup在其Inspector中单击 这个按钮,为其添加组件在弹出的菜单中选择UI,在后续弹出菜单中


为了哽完美首先调整空对象_ToggleGroup的位置与大小,让其包含那3个Toggle控件然后在Hierarchy中,把3个Toggle选中并拖到_ToggleGroup中成为子物体 这样在逻辑上与外观上均完备,苴移动父物体时子物体也会跟着移动

 这是Toggle的事件处理,它与Button的事件有所不同下面来看看怎样给Toggle添加事件。

我们把Toggle的标签改成装备名称再在场景中增加一个显示选取的装备名的文本框:

























在Canvas中创建一个空对象,把此脚本挂接到此对象上并把场景中的Text赋给public Text Display这个变量,然后汾别选中那3个Toggle在其检视图中单击事件下的“+”号: ,单击后就为该控件添加了事件如下图:


然而,事件要委托给一对象现在还没有,显示的是 此时把已经挂接上了脚本的那个空对象拖放到此处,便委托事件处理对象了如下图所示:


有了事件处理对象,但还没有指萣方法此时单击 会出现下图所示的菜单:


鼠标指向我们为此对象所挂的脚本名_ToggleEvent时就会继续展开一个菜单,其中就有我们在此脚本中编写嘚方法Toggle1(bool)、Toggle2(bool)、Toggle3(bool)这个菜单与Button的有所不同了,Button的如下图所示:


比较这两个菜单可发现Toggle多了上面的那部分:


下面的 是静态方法上面的 是动态事件,是系统自动生成其bool型参数已被封装在其中了,此时我们不能象Button那样去选择其静态方法了而要选择与之对应的动态事件才可正常运荇了。

Toggle与Button在事件处理上的的区别不只是上面所谈到的那一点还有其他区别,如:

Button事件组件面板的上部显示的是 

Toggle事件组件面板的上部显示嘚是 

Button是当Button被单击时发生Toggle是当Toggle选中与不选中(即其值发生改变)时发生,且还有一个布尔型参数选中时传进给参数的值为真,反之为假所以在前面脚本编写中,其方法里我们要设置对应的布尔型参数来接受这个值:







根据上面的分析可知Toggle选中与取消选中时都会产生事件,那么在一组单选按钮组中当我们点选另一个按钮同时会取消前一个按钮的选择,那么这两个按钮就都会产生事件为了证明这一点,峩们将前面的脚本稍作改变:



















以前的代码是当选中即isclik为真时才显示相关信息而取消选中,虽然事件也产生但因isclik为假,所以不会显示信息所以我们便觉察不出来,而现在加上了一个print语句这样只要事件发生了,就都会在后台里打印出相关信息来如下图所示:


这是首次運行选中“屠龙宝刀”时的情况。


接着我们选中“倚天剑”时“屠龙宝刀”也被取消,“倚天剑”与“屠龙宝刀”都产生了事件所以會打印出各自的信息。


再在这基础上选中“降龙十八掌”“倚天剑”被取消,同时“倚天剑”与“降龙十八掌”均产生了事件所以倚忝剑与降龙十八掌相关信息都会打印出来。

以上就是Toggle的事件处理机制如果我们Toggle不是单选而是复选,那么我们又怎样在那个文本框中显示絀多选信息呢

这个问题看似很难,实际上很简单代码如下:

















把info的赋值符号=变成+=,这样就把info的值累加起来了也就记录下了多选值了。這虽然简单但不完善,如果先选中然后又去掉,但先添加进去的值却不会去掉这需要进一步地处理才行。

在事件组件面板中第一個选项框中的值我们在Button时就是一直使用的是其默认值:Runtime Only,如下图所示:


当我们单击该选项时出现的下拉菜单如下:


Off:关闭事件处理功能;

Editor And Runtime:编辑与运行时,其事件处理功能均起作用;

Runtime Only:仅在运行时其事件处理功能才起作用。

我们假设把Toggle1方法改成如下所示:





然后把第一个Toggle嘚事件处理对象及方法置空并把事件运行模式变为Editor And Runtime,此时再为它添加事件对象及方法我们将发现在添加结束后,其事件便立即发挥作鼡了如下图所示,当然程序运行时也能发挥其功效的这就是“编辑与运行时,其事件处理功能均起作用”的意思


    此功能可以为我们程序员提供预览、事前先知的功能,方便我们编辑

十一、Slider控件(滑动条)

Slider也是一个复合控件 ,Background是背景默认颜色是白色,我们保持不变;Fill Area是填充区域其子控件Fill中只有一个Image(Script)专有组件,假设我们将其颜色改为红色;Handle Slice Area中的子控件Handle(手柄)中也只有一个Image(Script)专有组件假设我们将其顏色改为黄色,那么Slider的外观为: 


上部的Interactable、Transition与前面介绍的控件是差不多的下面谈谈它特有的一些属性:

Direction:Slider的摆放方向,可以从左到右、从祐到左、从上到下、从下到上

Whole Numbers:整数数值假设我们将Min Value设为1,Max Value设为100那么调节手柄时,对应的值在1到100之间而且是一个小数,如55.67有时我們希望它是整数,那么选中该项即可

我们再创建一个Slider控件并命名为Slider2,并把其所有子控件的名字改成在其默认名后加2的名字再把先前的那个Slider改名为Slider1,也把其所有子控件的名字改成在其默认名后加1的名字如下图:



运行程序,当我们调节Slider2的手柄时我们将发现Slider1的填充区域在發生变化,为什么呢因为默认情况下Slider2的Fill Rect是它自己的Fill2,而我们现在把Slider1的Fill1赋给了它作为它现在的Fill Rect对象,所以就会出现此种情况这就是Fill Rect的功效。

在上面的实验中我们把Slider1用来做显示,Slider2用来控制如果能把Slider1中黄色手柄隐藏起来就更好了:


这也是能做到的,我们选中Slider1的子子控件Handle1在其Inspector视图中,将其Image(Script)前面的对勾去掉 这样就不会显示那个手柄了:


假设我们想在拖动手柄的时候,让其值显示在右边的一个文本框中洳下图所示:


 指的是Slider的滑块滑动其值发生改变时而产生的动态事件,它有一个参数Single:单精度实际上这里指的是float,整个事件的机理是当滑动滑块时,其值发生改变事件产生,而且会实时将滑块所对应的值传给此事件保存在这个参数中,供程序使用

根据此原理,我们建立下列脚本SliderDemo:








然后在场景中创建一个空对象把此脚本作为组件挂在这个空对象上,再在场景中创建一个文本框并赋给

最后一步就是紸册事件了,单击 中的“+”按钮为其添加事件 ,把前面创建的并已挂上脚本的那个空对象拖到 中为其委托事件处理对象 再指定事件方法,单击 :


运行程序就可达到要求了

十二、ScrollBar控件(滚动条)


其属性: 与前面的Slider差不多,动态事件也是一样的这里就只谈其特有的属性:

Value:当拖支滑块时,其值是在0到1之间变化的

Size:是滑块的大小如果把它改成0.5,滑块就会大到占滑条的一半大

Number Of Steps:数值的步骤。假设设定为5那么就会把Value分成5个值,调节滑块时其值就在这5个值中变化

十三、一个简单的游戏主界面


右边蓝底色中的“生化危机”为Text;开始、设置、结束为Button,并加上简单的帧动画Highlighted(见前面的动画过渡)

左边淡黄底色区域为面板panel它为父控件,其中所包含的所有控件均为它的子控件遊戏难度下的三个选择钮为单选按钮组,其设置方法请参见前面Group

这个面板,通常情况下是不可见的当单击“设置”按钮时面板从左外側滑入而可见,进行设置后单击面板中的“确定”按钮后面板又滑出到左外侧处于不可见状态。这是一个动画其设置方法与Button动画相似,但它不是利用Button那种自动生成动画的方法而建立的

下面我们先来建立面板的动画过程:


此时单击顶端最左侧红色按钮,它为动画录制按鈕会弹出一个对话框,要求为将要录制的动画选择保存位置与动画的名称如下图:


假设我们将此动画保存在Assets下的_Animation文件夹中,并取名为ShowPanel.anim单击保存后,其界面如下:


录制的动画是面板从不可见到可见的显示动画那么在第0帧时面板是不见的,所以此时把面板水平向左拖动箌画布的左外侧如下图所示:

 动画录制机会记录下此时对象的位置,其Inspector面板中的RectTransform参数会发生改变:

接下来我们把帧数框中的帧数改为60帧即设置第60帧时面板的位置(设为60帧的原因是,面板从第0帧的位置变化到第60帧的位置时其动画时间大约为1秒钟)此时录制面板中的那条紅色竖线将移动到1:00处,如下图:


根据动画设计要求此时面板应该是完全可见的,所以我们把面板水平向右拖到画布中动画录制机同样會记录下此时面板的位置 ,其设置窗口如下图:


我们还可发现在现在位置的红线处会出现象0帧处的关键帧图标: 。

我们在 上单击一下其展开图如下:

 展开的那两项分别表示在此过程中,对象在X轴上位移了131Y轴上为0。

从底部的 处可见现在的视图是Dope Sheet(关键帧清单),当点擊Curves(曲线)时会转换为曲线视图,如下图


如果曲线过大显示不全或过小看不清时可调节鼠标中键滑轮,缩放曲线到适当大小

图中水岼绿色线 所包含的区域即为动画区域,曲线上的红色点为关键帧点可看出此动画只有两个关键帧,用鼠标单击关键帧时Scene视图中的面板僦会移动到所设置的位置上。

设置好后单击红色的录制按钮一下,即可停止录制且保存动画

这是显示面板的动画,下面我们来设计隐藏面板的动画

单击已经显示出刚才录制的动画名为ShowPanel这个框右边的按钮,弹出:


单击[Create New Clip]创建一个新的动画剪辑,此时会同样弹出一个要求伱为新动画取名以及选择保存路径的对话窗假设我们为此动画取名为HidePanel.anim,路径与前一个动画相同其后的动画设计与前边一样,只不过第0幀时面板在画布上,第60帧时面板在画布外。

动画创建结束后即可直接关闭录制窗体,系统会自动保存动画文件回到系统界面下,茬Project视图中的我们事先设定的保存动画的_Animator文件夹下将会新增三个文件: 而且在Hierarchy视图中选中已设置了动画的控件Panel,在其Inspector视图中将发现系统会為其自动增加动画组件Animator

好了,万事具备运行程序,但发现那个面板的显示动画会不断地重复播放其原因是其Loop Time的属性值为True,如果设为False即可去掉其默认的自动播放特性方法为,在Project视图中选中 动画然后在其Inspector视图中,把 后的钩去掉即可(同理其HidePanel动画也做这样的处理),泹程序运行时面板虽不会重复播放显示动画了,但它会播放一次这与我们的设计初衷不符,我们的初衷是程序运行时不显示面板当峩们点击设置按钮后才会显示面板,点击面板中的确定按钮后隐藏面板。要达到这种功能就要设置动画状态机中的一些属性以及配合使用脚本才能完成。

首先让动画不自动播放。

在Hierarchy视图中选中设置了动画的控件Panel可发现其Inspector视图中Animator组件中的第一个属性Controller(控制器,也称动畫状态机)的值为前边录制的 动画:Panel如图: ,单击其后的设置按钮 可更改为其他动画不过这里是不需更改的,我们双击动画框中的已囿的动画Panel会打开Animator窗口:


其中有两个按钮代表的就是按钮文字所指示的动画剪辑:ShowPane、HidePanel,即现在这个Panel动画里有两个动画剪辑我们在面板的涳白地方单击鼠标右键: ,选择第一项Create State中的Empty创建一个空动画,其默认名为New State如图:


在New State上点右键,在弹出的 中选第二项Set As Default即设置这个空动畫为默认播放的动画,既然为空动画自然就不会播放动画,经此设置后的窗口如下图所示:


比较设置前后两图可发现代表默认动画的按钮的颜色为黄红色。即哪个按钮为黄红色那个动画剪辑就是当前动画播放时的状态位置,动画状态机的命名来源也许就是这个原因

經此设置后,再次运行程序就不会有动画播放了。但也许你会发现那个面板仍然显示出来了出现这种情况,不是动画造成的因现在雖然没有动画,但那个面板本来是存在的当然要显示出来,如果想要它一开始就不显示我们只需在场景编辑视图中将其位置拖到画布の外即可达到目的,如下图:


通常情况下一个动画里有许多的动画剪辑,到底播放哪个动画是动画状态机来决定的。 这个界面就是动畫状态机界面它表示现在的动画播放的是它中的哪个动画剪辑。那么我们有什么办法来控制动画状态,或者说让动画在不同的剪辑中茭替转换呢

我们在“New State”上单击鼠标右键,选择第一项Make Transition(设置转换)然后直接移动鼠标,将会出现一个带前头的连线再在”ShowPanel”上单击鼠标左键,即可在这两个动画剪辑上建立转换联接: 这个连线表示,当满足某个条件时就可由播放剪辑New State变成播放剪辑ShowPanel,即使ShowPanel处于播放狀态这个条件又在哪里设置呢?单击 右边的“+”按钮在弹出的 中选Bool,即设置一个布尔型参数并把此参数假设命名为IsDiaplay,如图

设置好參数后,用鼠标单击那根连接线它将变成蓝色,表示选中如图:




这两步设置的结果我们可以这样理解,当IsDiaplay为真true时动画播放状态处于New State戓HidePanel时,都将转到去播放ShowPanel

依此类推,当IsDiaplay为假false时动画播放状态如果处于ShowPanel时,将转到去播放HidePanel这样其动画状态我们就设定完了,如下图:


接丅来我们利用脚本去改变那个变量的值就可实时控制动画的播放了。

脚本内容如下(红色部分为增加的脚本内容):










最后设定“设置”與“确定”两个按钮的委托事件具体设定过程请参见前面的Button事件。

至此这个简单的游戏主界面便创建完工,可运行程序查看效果了

滑动区域控件ScrollRect是在一个较小区域显示较多内部控件的一种机制。在UI系统中这种控件的原型是没有的,它是我们开发者利用UI系统里已有的基本控件组合而成的不过在UI系统里有ScrollRect这个类,即它是一个组件不是控件。控件与组件有什么区别呢简单地说,在一个控件里可以添加组件如在Button上可添加Animator组件。有些控件在创建时它会默认自带一些组件,如Panel会自带Image组件如图: ,其带括号的Script就表示这个Image是组件因在UI系统里有Image这个基本控件的,故加上一个带括号的Script来区别控件与组件说明此处的Image是组件而不是控件。同理当我们创建一个Button控件时,默认凊况下我们可以在其Inspector视图里发现它带有Image与Button两个组件的如下图:


这好像有点混,3D怎么用Button控件里含有Button组件呢

实际上我们可以这样理解,组件是一个脚本是一个类,控件是这个类的实例化对象是一个具体实现,所以Button控件里含有Button组件就好理解了再一个,类之间可以继承所以一个控件可以包含多个不同类型的组件。

根据上面的叙述ScrollRect是待开发者自己去建立的控件,我们姑且把它称作隐形控件下面我们来創建这个控件。

创建一个画布Canvas在画布上创建两个空对象,其中一个命名为ScrollRect另一个命名为Content,再创建一个Scrollbar调整它们的大小与位置,大致洳下:


在Content上创建几个子对象这里我们创建4个Button,并调整它们的位置使它们平铺在Content中,同时设置Button的Image的SourceImage的值(挂上图片普通图像挂不上,應转换成精灵请参见前面的Image)。


Scrollbar其功能简单说是用滑动条的滑动去控制内容区域的移动。根据此原理我们把Hierarchy视图中的Content与Scrollbar分别拖挂到这兩属性值框中即完成了对象的指定工作试运行程序并拖动滑动条,发现Content中4个按钮图片确实能随着滑动条的移动而移动了如图:


    但这还鈈完美,如果能隐藏多余的内容只显示特定区域的内容,就象网页中的滚动条那样就好了如下图所示:


要达到此功能,还要为已添加叻ScrollRect组件的对象增添Image、Mask(遮罩)两个组件其添加方法与上一致。

Scrollbar已完备但当我们运行时,其效果仍然与前面相同不能隐藏多余部分。洳果在Hierarchy视图中我们把Content拖到ScrollRect上使Content成为ScrollRect的子对象,就可达到我们想要的效果了


其原因是,我们所添加的Image与Mask是在ScrollRect上那么用图像去遮罩的对潒是ScrollRect,所以我们要把Content作为ScrollRect的子对象才能达到此效果

十四、高级控件 标签页面TabPage


如图,当我们点击顶部不同的标签时下部的内容区域会显礻对应的内容版面。

1、在画布上创建一个空对象命名为Lable,创建一个Image布局上Lable在上面,Image在下面如下图:




Background是背景,是未被选中时表现出来嘚图景首先在场景视图中将其大小调大,使其与整个按钮形状一样大然后在其Inspector视图中的Image组件里设置Source Image或Color属性值,这里为了简便我们将其Color值设为较暗的灰度色,用于它未被选中时展现出来的颜色


Checkmark是选中时表现出来的图景,默认是一个对钩同理首先在场景视图中将其大尛调大,使其与整个按钮形状一样大这样一来,Checkmark与Background一样大两个重叠起来了,当未选中时表现出来的是Background的景象,选中后表现出来的是Checkmark嘚景象对于Checkmark的调整,然后在其Inspector视图中的Image组件里设置Source Image或Color属性值这里为了简便,将Image组件里的Source Image属性设为空None即去掉那个对钩图像,并将其Color值設为较亮的灰度色用于它被选中时展现出来的颜色。

这三个按钮状的Toggle按设计思路应该为单选所以按以前所学的知识,需设置它们的Group属性值为Lable 同时,对于它们的Is On属性第一个Toggle的保持勾选,另两个去掉勾选即使开始时,第一个处于默认选中状态

3、在Image上创建三个为空的孓控件,分别命名为Page1、Page2、Page3并调整它们的大小,使其与Image一样大位置上与Image重叠。再在Page1、Page2、Page3上各自创建一个Text子控件也调整它们的大小大致與Image相当,且位置上也与Image重叠并分别输入要显示的文本内容。这三个Text是重叠在一起的显示时,其内容也会重叠如果我们只勾选第一个Text嘚父控件Page1的 ,另两个去掉勾选那么显示时会默认显示第一个,另两个处于未激活状态不会显示出来,自然就不会发生显示的重叠了

4、最后一步我们来实现当我们点击顶部不同的标签时,下部的内容区域会显示对应的内容版面

也许你会认为这要用到脚本,实际上有更簡便的方法当然会离不开事件处理机制的。下面以Toggle1为例选中它,在其Inspetctor视图中单击:


中的“+”号,为其添加事件如下图:


委托事件處理对象,这里我们把Page1拖给 如下图:



虽然我们没有编写自己的脚本但Unity有内置的许多方法的,这里我们选择第二项GameObject:


选择上边的动态方法:SetActive设置结果如下图:


这个事件的运行机理是:当Toggle1的选中状态发生改变时(注意是状态发生改变,选中时会产生事件那么由选中到取消選中,也会产生事件)所挂接的对象Page1会被激活或失效。

根据这个原理Toggle2的事件委托对象为Page2,Toggle3的事件委托对象为Page3这样就实现了当我们点擊顶部不同的标签时,下部的内容区域会显示对应的内容版面了如下图:


十五、大型游戏案例UI开发


在Project中建立一些文件夹


我们这里先把一些贴图导进Sprits中,并把它们转化为Sprint其转化方法请参见前面的Image控件中的图像精灵。


Render Mode:渲染模式设为Screen Space – Came这种模式可在画布与摄像机之间放三維物体,做出更绚丽的界面

Render Camera:既然渲染模式为Screen Space – Came,那么在此处就需为此设置渲染所用的摄像机了我们把Hierarchy中的主摄像机更名为UICamera后并拖到此处,为此指定渲染所用的摄像机

Plane Distance:直译过来为“平面距离”,这里表示的是画布距摄像机的距离默认为100个单位,虽然距离越大在畫布与摄像机之间所放的三维物体越多,但一般设成200个单位这里我们设成200。


Reference Resolution:参考分辨率应根据应用情况而定,这里我们设成800×600即畫布的大小宽为800像素,高为600像素

Screen Match Mode:屏幕自适应模式, 选第1项自适应宽或高。

在画布上创建一个Image控件命名为Background,并为其赋值一个Sprits贴图作為背景图:


此图看起来会是朦胧的究其原因是因其默认为半透明状,将其设为不透明即可解决。方法为单击: 会弹出:


其中的R、G、B表示红绿蓝颜色,最后一项A代表的就是透明度将其滑块拖到最右,如上图右即设成了不透明,返回后其效果如下图:


4、创建供滑动用嘚系列面板

再在画布上建立一个Image父控件命名为Sliderpanel,并在其下建立5个Panel其结构与命名如下:


调整这5个panel,使它们向右平铺开来如下图。我们這样做的目的是想创建一个滑动效果就像手机上的滑屏效果。


这5个面板默认是重叠在一起的要像上图那样把它们向右平铺开来,其位置的调整除用鼠标手工拖动外,其实有更精确的方法

第1个面板MainPanel在原位,是不需调整的

我们以下列三个系列图来说明这个问题:

下图Φ的第1个,我们是在画布Canvas上创建一个面板Panel并调整它的大小,使这个Panel的Left、Top、Right、Bottom分别为200、100、220、120从图示就可看出它们分别表示子控件Panel的边与父控件Canvas相对应边之间的距离,这个距离的单位为像素如果画布设置的参考分辨率为800×600,即宽800像素高600像素,那么大家就可从子控件与父控件各边之间的距离(即空白距离)算出子控件的大小了


图2与图3均是在Canvas的子控件Panel上创建的一个子子控件Panel,不过图2中的Canvas上的子控件Panel与Canvas一样夶图3中的Canvas上的子控件Panel比Canvas小,各边留空100它们的子子控件Panel的Left、Top、Right、Bottom都是150像素,然而因父控件的大小不同它们的大小也就不同了。从这个唎子可看出Lest、Top、Right、Bottom指的是本控件的边与父控件相对应的边之间的空白距离。

上例情况应该是好理解的然而,这些值为负值时又该怎樣理解呢?

我们还是先从正值理解起Left为150,表示子控件的左边缘在父控件左边缘的向右方向150像素处同理,Right为150表示子控件的右边缘在父控件右边缘的向左方向150像素处。反之Right为-150,则表示子控件的右边缘在父控件右边缘的向右方向150像素处即负表示反方向。

根据上面所讲原悝继续设置游戏界面,那么Panel2、Panel3、Panel4的Left分别为1600、2400、3200Right分别为-1600、-2400、-3200,这样那5个面板就向右边并排排列开来了(这里展示的是加上贴图后的效果,其贴图大家可自行完成)


根据前面的创建从结构 上可看出有两个图像控件backguound与Sliderpanel,Sliderpanel上有5个Panel控件backguound上有贴图,Sliderpanel作为父控件以便对其中的5个Panel統一移动、旋转等处理其本身是没有贴图的,而那5个Panel中是有贴图的总共有6个贴图存在,那么在其Scene或Game视图中也许我们认为应该看到6个畫面,而实际上在2D的Scene视图中看到的是:

如果我们单击Scene视图上方 中的 即可观察到3D模式下的状态:



此设置的结果是将background沿Z轴正方向即向前推600个潒素,那么在3D视图中为:


    从这点上可看出看不见,并不代表它不存在

这时虽然在3D模式下的Scene视图中能观察到,但因Canvas的渲染模式为Screen Space – Camera在Game視图中又由于MainPanel的遮挡,其background仍不见但如果以后实现了滑动功能,MainPanel被滑开后就可见了这样做的好处至少不会因MainPanel的滑开而露出一个空白底子。

Screen Space – Camera这是我们目前最常用的渲染模式虽然我们可以放置一些3D模型,但显示总是2D的你是不能看到它的侧面的。既然是这样那么摄像机僦用不着再使用透视Perspective模式了,可将其设置为Orthographic(正交) 即选择第2项 ,其Scene视图的表现将由:



即视线为2D正交状更有利于2D表现。

5、设计主界面仩的元素


3个按钮左下角喇叭贴图的按钮用于调节音量;中间水晶球贴图的按钮用于开始游戏;右上角钱币贴图的按钮用于查看金币数量;

2个3D模型,1个美女3D模型1个小汽车模型。

3D模型导入后可能出现两种情况,一个是运行游戏时不可见;二个是其贴图丢失造成白模。

第┅种情况的原因是当我们查看渲染的摄像机的Culling Mask属性时将发现其值为UI,即只有UI层才被渲染故我们应将该模型的Layer设为UI 。那么为什么我们所添加的象Button、Text…等UI控件不需设置此步就可见呢我们单击选中或任意创建一个UI控件,再查看其Layer将发现它们会被自动设置为UI如下图:

 所以就鈈需我们再次去设定了。而3D模型添加到场景后其Layer默认为Default,如果不手工改成UI就不能显示出来了

第二种情况的解决办法,我们可以先将模型所用的材质贴图先复制到该工程项目中的一个文件夹内并在3DMAX中将其对应的材质贴图的路径也改成该工程项目的那个文件夹中对应的材質贴图文件,然后把该模型直接导出为FBX格式到该工程项目中的一个模型文件夹中这样它会自动对应到相应的材质贴图,再在场景中使用這个模型时就不会出白模情况了

另外,当我们单击选中已导入Project中的3D模型时在其Inspector视图中,选中Model选项卡将发现Scale Factor的值为0.01,如下图所示:


3D模型导入Unity时默认是缩小100倍的在3DMAX中,其单位往往默认是英尺英寸而Unity是米,如果我们把MAX的单位设成米并把“系统单位设置”里的系统单位仳例也设成米,如下图:  

这样制作出来的模型导入到Unity中时就可将Scale Factor设成1,即1:1导入就不会出现大小不合适的情况了。

我们先给出滑动用嘚脚本:





IBeginDragHandler与IDragHandler是两个关于拖拽的接口类IBeginDragHandler是处理开始拖拽的事件接口,IDragHandler是处理拖拽中的事件接口实现接口,就必须实现接口中的所有方法而这两个接口中有什么方法呢?如果脚本编辑器我们使用的是Visual Studio的话在接口类名上单击鼠标右键,选择“转到定义”如下图:


就可查看箌该接口中的方法:

我们把其中的方法OnBeginDrag复制到我们的脚本中不过复制过来后一定要在方法前加上Public关键字,因接口中的方法都是Public的且是默认,所以在接口中就没有标示出Public的如果我们不加上Public的话编辑器就会报错。

我们可以先在这两个方法中只加上print语句并运行程序,观察結果将发现OnBeginDrag只运行一次,是在开始拖拽时OnDrag运行多次,发生在拖拽中明白此道理后,我们把print语句注释起来加上控件拖动的语句:

Space.World);此呴就是使面板在世界坐标中沿X轴向上移动PosX/100,为什么要除以100呢因PosX是像素,而Translate的移动量的单位是米除以100就相当于转化一下单位,否则本来昰100像素就是移动100米了会非常的快,快得不符常理了当然这个100是通过试验方法来设定的,不是固定的

把此脚本挂接到Sliderpanel上,因它是父控件移动它就可移动那5个面板了。

虽然我们实现了滑动但有一个问题,如下图状在此基础上继续把面板向右滑动,且滑出主界面时僦不能再把鼠标放置到面板身上去把它滑回来,主界面上就只剩下那个背景图控件了无法完成后续的操作。


下面我们先来观察一下面板嘚移动值我们在脚本的Update中加上一句:print("x="+this.transform.position.x);运行后,当面板向右将要移出(如下图)时



其值为由0到13.4移动的这13.4是像素还是米?好象都不是我們将此句改写成:print("x=" + this.transform.localPosition.x);,再运行移动后发现,在面板向右将要移出时打印出来的值为600多或700多,而我们的画布是800像素宽说明此值是像素值。localPosition是局部坐标是Sliderpanel相对它的父控件Canvas的坐标,是相对值也正是我们想要的值。

下面我们就可利用此值来控制面板不被移出界面

在Update中去掉剛才的Print语句,加入下列语句:

滑动面板中的面板除第一张放在主界面上外其他面板都是放在右边的,所以一开始应从右向左滑后边的媔板就会进入主界面中,如果从左向右滑整个面板就会滑出界面。开始时Sliderpanel的坐标为0,0,0,如果向左滑其坐标值将减小,为负值如果向祐滑,其坐标值将增大为正值。根据我们的设计这个坐标值为正值时,面板就有可能滑出界面所以if (this.transform.localPosition.x > 0)这句就是监测面板的坐标值,当峩们向右滑时其坐标值立马就会大于0,于是条件成立下边的语句就会执行:

以上解释是帮助文档中的内容,在其中还一个例子程序:

//潒弹簧一样跟随目标物体






这个例子是当我们移动目标物体target时,另一个也就是挂接了此脚本的物体会像弹簧一样跟随目标物体为什么会潒弹簧一样呢?因Lerp会根据Time.deltaTime * smooth的值在transform.position到target.position之间插值,并返回一个Vector3赋给挂接了此脚本的物体此物体的坐标值由于有了新的值,而且这个值是在咜们两者之间(插值)看起来这个物体就是向目标物体靠近,如果我们移动得快它们两者之间的距离就越大,那个物体向目标物体靠菦得也就越多看起来就快些,反之就慢些但随着时间的推移,Time.deltaTime * smooth的值最终会等于1那么此时Lerp返回的值就是目标物体的坐标值,那么这个粅体就会靠在目标物体上也就是说那个物体始终不会脱离目标物体,其跟随快慢是随着目标物体移动的快而快慢而慢,最终跟上看起来就像在它们两个身上连接了一个弹簧一样。根据此我们把static function Lerp (from : Vector3, to : Vector3, t : float) : Vector3中的参数t : float称为弹性系数,用此控制跟随的速度在实际运用中,往往用Time.deltaTime来玳替这样物体的移动随着时间的消失,看起来显得更加平滑再给它乘上一个浮点数smooth可更加灵活地控制这个“弹簧的弹性”了。

0)这样┅来,当Sliderpanel向右滑坐标值大于0时,Sliderpanel会向Vector3(0, 0, 0)点返回靠拢最终回到这点上来,保证了此面板不会滑出界外了

以上是控制面板不会向右滑出界外,下面可以根据此原理设计出控制面板不会向左滑出界外其代码如下:

为什么这里是-3200,是因总面板有5个在界外的有4个,每个面板与畫布一样大其宽为800像素,4个800当然就是3200了到此,脚本的全部代码如下:








以上虽然保证了整个面板不会被滑出界外但在滑动过程中,这5張面板交替出现在主界面上时有很不好控制的现象的出现,如想要的面板可能一滑而过即使滑到了想看到的面板,它可能一半在界面仩另一半在界外,如果往回滑一点时可能是原来在界外的那一半在界面上了,而原来在界面上的那一半却又跑到另一侧的界外了如果能让面板自动整板卡位到界面上,就会让人感觉到很舒适了实际上,我们应用上面定义滑动边界的办法也能做到这点

在Update中增加下列玳码:





该代码的工作原理,大家可根据前定义滑动边界的原理去分析它应该是一样的。这里的弹性系数乘了一个5而不是10,是觉得10时太赽了这个值大家可根据具体情况去调节。实际上直接乘以一个值这个编程方法并不好,应该是设定一个变量通过变量可方便调试,請大家自己优化

运行程序将发现,向左滑动时很方便很容易就卡位到我们想要的版面上了,但向右滑回时就感觉不好了,很难卡位箌想要的版面上了分析一下我们的代码就不难发现其中的原因了。


那么我们怎样让程序知道用户滑动的方向呢?程序中正好有一个private float PosX这個量它在OnDrad方法中赋值PosX = eventData.position.x – StartPosx,当它为负时就可表示向左滑为正时就表示向右滑,于是我们在卡位程序中的每个判断语句中嵌套一个判断语呴让程序根据用户的滑动方向来卡位,就会智能化了如第一个判断语句中嵌套判断语句后是:


PosX小于0,就是向左滑卡位到第2张,否则夶于0说明是向右滑,就卡位到第1张余下的判断语句依此改写,那么面板的滑动就完善了至此,整个脚本的内容如下:












实际上以上代碼还可继续优化优化后的代码如下:

//X轴向上移动的距离













下面我们做出小汽车不停旋转的动画。

在Hierarchy视图中选中小汽车模型然后单击系统菜单Window中的Animation,如下图:



单击红色的录制按钮 会弹出:


选择并打开保存将要录制的动画文件的文件夹_Animator,并为此动画命名为car_Rotation保存后,动画录淛界面如下图所示:



其意思为到60帧时,围绕Y轴旋转60度


其意思为,到120帧时围绕Y轴旋转120度。


其意思为到180帧时,围绕Y轴旋转180度


其意思為,到240帧时围绕Y轴旋转240度。


其意思为到300帧时,围绕Y轴旋转300度


其意思为,到360帧时围绕Y轴旋转360度。

设置完后单击红色录制按钮停止錄制,并保存一下场景我们将发现:

在Project中展开_Animator文件夹,其中将出现两个与刚才录制的动画有关的文件如下图: 

在Inspetor视图中,会自动为该模型增加一个Animator组件如下图:

此时我们运行程序,将发现那个小汽车会不停地旋转起来即录制的动画已成功加载,当我们在Project中选中car_Rotation那个動画文件时其Inspetor视图中的Loop Time是勾选的,所以动画会自动播放,如下图:

10、声音设置面板移动动画

象前面第十三节:一个简单的游戏主界面┅样在这里我们建立一个设置声音的面板,当单击主界面上的声音设置按钮后从上往下滑出声音设置面板,设置完后单击声音设置面板里的确定按钮声音设置面板从下往上滑回。

首先建立这个声音面板在Canvas上单击鼠标右键,创建一个UI中的Panel命名为SetAudio,并设置它的Source Image给它┅个图片精灵,如下图:


该面板遮挡了主界面上UI元素却没有遮挡住3D元素,把视图切换到3D形式可看出该面板与Slederpanel重合,美女与车两个3D模型茬它的前边所以不能遮挡它们。


我们将其Z坐标值调小到如-500比美女与车的Z值都还要小,即可遮挡它们了


我们的目的是单击主界面上的聲音设置按钮后,该面板从上往下滑出遮挡所有,它成为主界面设置完后,单击声音设置面板上的确定按钮后滑回所以,该声音面板的初始位置应在该位置处的上边所以继续把面板垂直住上调:


然后再在声音设置面板上创建一个Button,显示文字为确定用于设置完后的返回。

这些准备工作做好后下边着手创建该面板的动画。选中该声音设置面板单击系统菜单Window中的Aniation



单击 中的红色录制按钮,会弹出:


此時要求我们给录制的动画取名与选择保存此动画的路径我们假设为此动画取名为ShowSetAudio,保存在_Animator中:



以前那个红色按钮是这种状态: 现在是: ,有点泛红晕状表示现在处于录制状态。这个 中最后一个为0的数字框即为帧数框现在处于0帧位置处,我们把0改成60即60帧,告诉动画機下边我们录制第60帧处的动画状态,此时录制面板中的那条红色竖线将移动到1:00处(60帧大约为1秒)如下图:


根据动画设计要求,此时面板应该是滑下来所以在Sceene中我们把面板沿Y轴向下拖到,动画录制机会实时记录下面板的相对位置为了准确,我们可手工在处于暗红色的 Top與Bottom框中输入值0即此时声音设置面板的上下边离它父控件的上下边均为0像素,完全滑下来其设置窗口界面如下图:


我们还可发现,在现茬位置的红线处会出现关键帧图标:

从底部的 处可见,现在的视图是Dope Sheet(关键帧清单)当我们点击SetAudio:Anchored Position.y并点击Curves(曲线)时,会转换为曲线视圖如下图


如果曲线过大显示不全或过小看不清时,可调节鼠标中键滑轮缩放曲线到适当大小。

曲线上的绿色点为关键帧点可看出此動画只有两个关键帧,用鼠标单击关键帧时Scene视图中的面板就会移动到所设置的位置上。

此时我们点击SetAudio:Size Delta.y,也可观察此项的曲线只不过該项值没有变化,为一平直的直线:


设置好后单击红色的录制按钮一下,即可停止录制且保存动画

这是显示声音设置面板的动画,下媔我们来设计隐藏声音设置面板的动画

单击已经显示出刚才录制的动画名为ShowSetAudio这个框右边的按钮,弹出:


单击[Create New Clip]创建一个新的动画剪辑,此时会同样弹出一个要求你为新动画取名以及选择保存路径的对话窗假设我们为此动画取名为HideSetAudio.anim,路径与前一个动画相同其后的动画设計与前边一样,只不过第0帧时面板在下,第60帧时面板在上。

动画创建结束后即可直接关闭录制窗体,系统会自动保存动画文件回箌系统界面下,在Project视图中的我们事先设定的保存动画的_Animator文件夹下将会新增三个文件: 而且在Hierarchy视图中选中已设置了动画的控件SetAudio,在其Inspector视图Φ将发现系统会为其自动增加动画组件Animator而且其中的Controller并已自动赋值为已录制了动画的控件SetAudio:

好了,万事具备运行程序,但发现那个面板嘚动画会不断重复播放其原因是其Loop Time的属性值为True,如果设为False即可去掉其默认的自动播放特性方法为,在Project视图中选中 动画然后在其Inspector视图Φ,把 后的钩去掉即可(同理其HideSetAudio动画也做这样的处理),但程序运行时面板虽不会重复播放显示动画了,但它会播放一次这与我们嘚设计初衷不符,我们的初衷是程序运行时不显示面板当我们点击设置按钮后才会显示面板,点击面板中的确定按钮后隐藏面板。要達到这种功能就要设置动画状态机中的一些属性以及配合使用脚本才能完成。

首先让动画不自动播放。

在Hierarchy视图中选中设置了动画的控件SetAudio可发现其Inspector视图中Animator组件中的第一个属性Controller(控制器,也称动画状态机)的值为前边录制的 动画:SetAudio如图: ,单击其后的设置按钮 可更改为其他动画不过这里是不需更改的,我们双击动画框中的已有的动画SetAudio会打开Animator窗口:


其中有两个按钮代表的就是按钮文字所指示的动画剪輯:ShowSetAudio、hideSetAudio,即现在这个SetAudio动画里有两个动画剪辑我们在面板的空白地方单击鼠标右键: ,选择第一项Create State中的Empty创建一个空动画,其默认名为New State洳图:


在New State上点右键,在弹出的 中选第二项Set As Default即设置这个空动画为默认播放的动画,既然为空动画自然就不会播放动画,经此设置后的窗ロ如下图所示:


比较设置前后两图可发现代表默认动画的按钮的颜色为黄红色。即哪个按钮为黄红色那个动画剪辑就是当前动画播放時的状态位置,既然当然动画为空动画自然就不会播放动画,动画状态机的命名来源也许就是这个原因吧

经此设置后,再次运行程序就不会有动画播放了。

通常情况下一个动画里有许多的动画剪辑,到底播放哪个动画是动画状态机来决定的。 这个界面就是动画状態机界面它表示现在播放的动画是它中的那个红黄色所表示的动画剪辑。那么我们有什么办法来控制动画状态,或者说让动画在不同嘚剪辑中交替转换呢

我们在“New State”上单击鼠标右键,选择第一项Make Transition(设置转换)然后直接移动鼠标,将会出现一个带前头的连线再在”ShowSetAutio”上单击鼠标左键,即可在这两个动画剪辑上建立转换联接: 这个连线表示,当满足某个条件时就可由播放剪辑New State变成播放剪辑ShowSetAudio,即使ShowSetAudio處于播放状态这个条件又在哪里设置呢?单击 右边的“+”按钮在弹出的 中选Bool,即设置一个布尔型参数并把此参数假设命名为IsDisplay,如图

设置好参数后,用鼠标单击那根连接线它将变成蓝色,表示选中如图:




依此类推,当IsDiaplay为假false时动画播放状态如果处于ShowSetAudio时,将转到去播放hideSetAudio这样其动画状态我们就设定完了,如下图:


接下来我们利用脚本去改变那个变量的值就可实时控制动画的播放了。

脚本内容如下(红色部分为增加的脚本内容):










最后设定“设置”与“确定”两个按钮的委托事件

在Button组件的下方有一个OnClick()选项,这就是Button控件处理事件的偅要机制

OnClick()意思为当该按钮被点击时所发生的事件:


此时其事件列表为空:List is Empty,我们单击其下的“+”按钮为其添加一个事件:


此时事件虽被添加了但其委托的事件处理对象为空:None(Object),当然连事件处理对象都没有其事件处理方法自然也就为空:No Function。那么怎样委托事件处理对象与選择事件处理方法呢

我们把层级面板中刚才建好的并已挂上了事件处理脚本的那个专门用来处理面板移动的空对象_ MovePanelControl拖放到None(Object)框中即可,此時此框中显示的内容即为委托的此事件处理对象的名称_MovePanelControl (MovePanelControl): 括号中的MovePanelControl表示此对象是挂上了名为MovePanelControl的脚本。有了事件处理对象了然后使用该對象的什么方法来处理事件呢?这还需我们给它指定其方法是单击显示内容为No Function的那个事件方法框,会弹出菜单列表:


当我们的鼠标指向峩们自己编写的脚本MoveSetAudio时会继续展开其中就有我们在脚本中编写的事件处理方法:showSetAudio(),选中它即可设置后: 这样就完成了事件的委托,当峩们运行时单击那个那个声音设置按钮,其声音设置面板就会从上往下滑出

其声音设置面板的隐藏按钮事件的设置方法同上。

以上的設计原理用一个图大致表示如下:

11、UI面板旋转动画


我们在Sliderpanel的子控件Panel4上创建一个像风扇一样的物体,并让它旋转其组织结构如下图:


Panel是┅个父控件,只要我们旋转这个父控件其子控件也就会跟着旋转,也就达到了旋转风扇的视觉效果了该Panel的透明度需调成完全透明,否則会影响子控件所构成的图案如下图:


风扇一样的图案,是由4个有贴图的子控件拼成中间的那一个是一个Button,目的是单击它时将进入游戲其余3个均为同一贴图的Image控件,各自旋转不同的角度而构成扇叶状


按照前面所讲的方法录制旋转动画,只不过前边我们多数是移动現在是旋转,所以不同帧数时要改变Rotation的Z值如下图:


录制完后保存即可,因其动画默认是循环播放运行程序就可看到效果了。

    设计思路洳下当程序运行后,如下图这是起始界面:


我们向左滑动面板,进入第二、三、四等面板分别展示不同的枪支。下在以第二个面板仩的设计为便进行讲解:


该面板展示一支枪标明价格为8888,点击 按钮会从上往下滑出一面板如下图:


该面板会遮挡它后面元素,用于枪支展示此时我们应做出动画来,让枪支从该面板的后面移动到该面板的前边来并且逐渐变大,如下图:


当用户点击 按钮时枪支变小並移回,同时该展示面板向上滑出回到游戏界面:


Pal_Background是一个面板,颜色为绿色做背景用。

Gun是一个3D枪支模型

Btn_DisplayGuns是一个带向下箭头贴图的按鈕 ,点击它时会有一个展示该枪支的面板从上往下滑出

Image是一个Image控件 ,贴有钱币图

Text是一个文件框 ,显示该枪支的售价

展示面板 我们直接在Canvas中创建,并命名为WeaponDisplayPanel其中有一个带向上箭头贴图的按钮,用于滑回此面板用:


该面板的空间位置在左右方向上不动即Left与Right均为0竖直方姠上要往上,使其游戏运行中不可见在单击了那个 按钮后才滑出:


前后方向上即Z轴值要往前,以遮住主界面为准:

以上准备工作完备后下部就是做动画了。



像前边所讲的面板滑动动画一样进一步设置该动画的状态机,去掉自动播放功能:


至于脚本我们前面总是单独建立,实际上在实际开发工作中有些脚本是可归类在一个脚本文件中,这里我们在前面所建立的MovePanelControl面板滑动脚本文件中增加控制这个武器展示面板的脚本,增加后的代码如下(红色部分为增加的代码):










这些设置好后再给显示面板与隐藏面板的那两个按钮分别委托事件處理即可完成该动画的制作:


下面制作枪支前移并放大、后移并缩小的动画。该动画为一系列的动画是一枚举类型,故需Animation不需要带动畫状态机的Animator,而3D模型导进来时里面默认的动画组件为Animator,故我们需先去掉该组件: 然后再给这个3D模型添加Animation组件: 



再接着创建枪支变大动画:


最后接着创建枪支变小动画:


动画创建完之后其Animation组件的属性如下图:


其中枚举长度为4: ,其枚举项 到 中的值就是我们刚才所创建那4个動画

这4个动画播放哪一个,何时播放就需脚本来控件了。我们打开MovePanelControl脚本在其中增加要播放动画的脚本(增加的部分为红色):










至此,枪支动画就算创建完成当然我们自己还可再增加枪支动画,比如加入粒子系统让枪试射等更加绚丽的动画。

在前面第10节处我们建竝了设置声音的面板,在主界面上单击那个小喇叭按钮会上往下滑出声音设置面板,该面板上除了一个确定按钮外还没有音频管理用嘚控件。现在我们利用此面板来控制背景音乐与音效的音量大小添加两个Text与两个Slider,如下图所示:


然后在场景中创建一个空对象(不是在Canvas仩创建)命名为_AudioManger:



一个为声音监听器,一个为声音源一个相当于耳朵,一个相当于嘴把它们同时加在一个对象上,这样我们就总是能听得见声音的(但也不一定如上图中的Position的Z值为192.304,离我们很远,运行游戏时,将听不到声音的,故这里我们要将X、Y、Z的值重置为0,这样就总能听見声音的)

在场景的创建时,系统会为我们的摄像机自动添加一个AudioListener这里我们已经添加了AudioListener到这个空对象上了,就用着再在摄像机上添加AudioListener叻故需去除摄像机的AudioListener。







//音频源集合类的加载处理












//不能与当前正在播放的背景音乐重复














//播放背景音乐  方法重载  根据背景音乐文件的名称来播放


















//播放音效音乐  方法重载  根据音效文件的名称来播放






把此脚本挂到刚才创建的空对象_AudioManger上其Inspector视图如下:



我们让第一个元素代表背景音乐,第二个代表音效把对应的音频剪辑拖放到此处:


再为此对象添加一个AudioSource组件:



为什么要给它两个AudioSource组件呢?请看下列代码:



//初始化函数茬游戏开始时系统自动调用。一般用来创建变量之类的东西  


//初始化函数,在所有Awake函数运行完之后(一般是这样但不一定),在所有Update函數前系统自动条用一般用来给变量赋值。  

同时在Awake中还有一段代码:



下边是列出了变量名、方法名,未列出方法体等简化的代码:








//播放褙景音乐  方法重载  根据背景音乐文件的名称来播放





//播放音效音乐  方法重载  根据音效文件的名称来播放


方法前边的static修饰符说明此方法为静态方法静态方法的好处是不需实例化对象就可调用该方法,但静态方法里调用的变量必须为静态变量因实例变量必须依附于实例对象,洏静态方法是在未实例化对象时就调用了所以不能调用实例变量,这就是那几个变量设为静态变量的原因

音频管理器编写好后,在何處调用里面的方法来播放背景音乐或音效音乐呢实际上这里我们不需再建立对象了,可以在原控制面板滑动的MovingPanel.cs脚本里调用如要播放背景音乐,在Start中增加一句AudioManager.PlayBackground("BloodBag");即可达到目的如想滑动面板时播放我们设置的音效,可在OnDrag中增加一句AudioManager.PlayEffect ("E5017");即可这里不能在Update中增加该句,因每一帧都偠播放一次实际结果就是不能播放。

//X轴向上移动的距离














如果想给按钮也加上音效我们先写一个脚本:




在Canvas中创建一个空对象,命名为_AudioPlanyControl並把此脚本做为它的组件,然后为要添加音效的按钮增加单击事件委托处理机制当单击按钮时调用AudioManager.PlayEffect("E5017");播放指定的音效文件:


AudioManager.cs这个文件中的AudioManager類是一个音频管理基类,在这里加载音频源得到Audiosource,初始化背景音乐与音效音乐集成了播放背景音乐或音效音乐的方法,该类方法由于偅载可根据音频剪辑或音频剪辑的名称来进行播放。这个类是一个音频管理器且其中的方法为静态方法,可供其他类来调用比如,峩们想左右滑动面板时播放音效于是我们在滑动面板的MovingPanel.cs这个类中的OnDrag这个方法中调用AudioManager中的PlayEffect方法即可:AudioManager.PlayEffect("E5017")。又如单击按钮时要播放音效,而對于按钮是委托事件它比滑动面板时播放音效多了一层委托机制,所以正如前面那样先建立AudioPlanyControl这个类,然后增加按钮的OnClick()事件当按钮被單击时,OnClick事件发生调用指定的AudioPlanyControl类中的方法PlayButtonAudioEffect(),该方法又会调用AudioManager中的PlayEffect方法从而完成音效的播放。象这样绕来绕去的好处是可以方便我们管悝分类控制。

根据这个原理下面我们继续来为前面已建立的两个调节音量的Slider增加处理事件:


根据前面的讲解,我们的设计思路是:在基类AudioManager中编写音量大小处理的具体方法供调用类中的某个方法调用,而调用类又做为Slider控件的OnValueChanged(Single)事件的委托方这样就达到了改变Slider滑块从而控淛音量的目的了。

在AudioManager.cs中增加控制音量大小的静态方法(红色字部分即为增加的部分):







//音频源集合类的加载处理












//不能与当前正在播放的背景音乐重复














//播放背景音乐  方法重载  根据背景音乐文件的名称来播放


















//播放音效音乐  方法重载  根据音效文件的名称来播放








GlobalManage为一个静态类里面铨是一些静态变量,是一个全局管理器存储的值可应用于各个关卡,这个类在前面还没有编写这里把它建立起来,其内容如下:


// 全局褙景音量大小




改变音量大小的方法我们已经在基类中建立起来了其调用类我们可以利用原有的AudioPlanyControl类,在其中添加方法:









该脚本是_AudioPlayControl对象的组件把_AudioPlayControl做为那两个控制背景音乐与音效音乐音量的Slider控件的事件委托对象,并选择事件对应的动态方法:


这样一来当我们调节音量滑块时,OnValueChanged事件发生就会调用指定的方法,并把滑块对应的值传进去:

//改变游戏背景音乐音量

这个方法又会去调用AudioManager中的对应方法同时继续把滑塊对应的值传进去,在AudioManager中会把传进来的音量值赋给当前的背景音乐或音效从而改变播放的音量,并存入全局变量里控制整个程序中的喑量:

<}

版权声明:本博客一本正经胡说仈道文章内容不能作参考。本文为博主原创文章未经博主允许不得转载。该博客所用图片资源均作学习分享用途仅供参考,请勿用於商业行为传播者自负。 如果本博客所写文章侵犯到您的权益请主动联系留言,我们将及时删除相关内容


如果是其他 的 坐标,或者昰 面更改 对应的 即可。

}

1、  RootMotion:根运动自己理解:根据动畫的运动,在脚下圆圈内生成一条路径这条路径称为根路径


2、  IK 反向运动学将身体的一部位,如手准确的定位到指定位置,类如伸掱拿东西


身体的哪一部位来准确匹配目标位置.

权限,位置和旋转的权限.


曲线x轴表示标准化的运动时间0~1Y轴表示在指定动画时间视的y值

在曲线上取值,使用Animator.GetFloat(”curve”);curve字符串是自定义的如果想获取此值,还需要在状态机中添加对应的字符串


5、  角色跟随应用。在目标角色運动时另外一角色跟随移动。

.Dot点乘如果他们指向在完全相同的方向,Dot返回1如果他们指向完全相反的方向,返回-1对于其他的情况返囙一个数(例如:如果是垂直的Dot返回0)。

.Cross叉乘两个向量的交叉乘积,使用叉积的正负值来判断向量ab的相对位置,即向量b是处于向量a的順时针方向还是逆时针方向 

因为有了OnAnimatorMove(),根运动的回调函数所以动画的移动不再依靠根动画去运动,而是受脚本控制来移动

}

我要回帖

更多关于 3D 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信