Unity基础学习笔记01界面与动画系统
密码:WOde3653
Project(工程)模块:包含了游戏开发过程中所有的可能用到的资源
Hierarchy(层级窗口):当前编辑的关卡中所包含的游戏物体
Inspector(属性窗口):对选中的物体的属性进行编辑
Scene(场景视图):对游戏物体进行可视化的编辑,所见即所得,类似于第一人称视角,可以进行控制(按住鼠标右键后才可以)
Game(游戏视图):预览视图,游戏在实际进行游戏时的效果,即玩家看到的界面(即摄像机看到的画面)
地形
导入高程图
如果直接导入高程图来构建地形,高程图的高度和宽度都需要是2的整数次幂,并且是RAW格式才可以。调整好高程图之后,在Unity中新建一个地形,之后在属性窗口中载入高程图(在第五个小标志设置中的Texture Resolutions中),然后调整高程图的参数。
新建一个地形:GameObject-->3DObject-->Terrain(是一个很大的平面)
Terrain->Paint Terrain
1.Raise or Lower Terrain 升高或降低地形。按住shift,再用鼠标左键可以将地形抹平(这个操作要在Raise or Lower Terrain下进行)
2.Set Height可以设置一个高度上限。按住shift + 鼠标左键:在当前鼠标点采集地形的高度信息,之后的高度上限就是这个采集的高度信息(这个操作要在Set Height下进行)
3.Flatten All 将当前的地形整个的设置为Height的高度。
4.Smooth Height 平滑工具,可以平滑一些台阶的边缘。
5.Stamp Terrain 印章工具,如同在邮票上盖戳。
6.Paint Texture 绘制纹理:Edit Terrain Layers..->Create Layers(第一个图层作为基础图层平铺到地形上,之后选择的图层可以进行绘制),在添加了基础纹理之后,还可以对图层添加不同的纹理(在New Layer处,例如选择了泥地基础纹理之后,还可以对泥地添加泥地法线贴图纹理)主要作用是使泥地展现出不同的效果。
Terrain->Paint Trees
为场景添加树木
Terrain->Paint Details
为场景添加细节(或者说一些装饰物)
Edit Details...在此处进行添加,例如为场景添加草丛,选择草丛图层,实际上是将图片竖着插入来构建出草丛的效果。(草丛的疏密程度可以进行调整,以此来构建富有表现力的地形效果)
构建湖泊效果
首先需要构建一个湖的地形效果,使用Set Height 将地形整个抬高以后,再在Raise or Lower Terrain下使用shift+鼠标左键将地形磨平一部分来构建湖泊的地形,之后在Project中找到Water的效果加入湖泊中即可。
游戏对象
游戏对象(Game Object)可以是一个角色,可以是一颗树木,一盏灯来照亮周围的环境,或者是一个声音源等等。
组件
组件(Component):实现游戏对象具体功能的单元。
对于每一个物体来说,都至少有一个Transform组件,用来控制物体的位置变换,大小缩放,旋转等操作。
组件Mesh Filter : 用来控制物体的外观
组件Rigidbody:刚体物理组件,如果给盒子添加该组件,当运行游戏时,盒子会做自由落体运动。
组件Constant Force :对物体添加一个向上的恒力(力的大小可以调整), 当运行游戏时,物体会向上运动。
游戏对象与组件的关系
1.游戏对象类似于容器,不具任何功能。
2.通过添加各种组件从而组成特定的游戏物体。
简单脚本
编写好的脚本会作为组件出现在属性窗口中,并且在脚本中的变量可以暴露在属性窗口中(定义变量时将其定义为public类型),(方便在Unity界面中进行调整)
创建一个新脚本(Unity中支持C#):在Project窗口中右键-> Create -> C# Script,创建后双击打开。
*在Unity里可以更改默认的编译器,当自己的电脑里有多个VS编译器或者需要使用Mono来编译时,可以从
Edit->Preferences->External Tools->External Script Editor 里来选择默认使用的编译器。
动画系统
场景动画
分为场景动画,角色动画等, 动画主要由关键帧组成(类似于多张图片连续播放,修改关键帧参数,中间的数值由计算机自动生成)。动画文件保存的是每一帧的网格信息。
选择物体,创建动画 Windows ->Animation->Animation->crate...(默认会生成两个关键帧,即关键帧动画)
在Project窗口中,Animator Controller (动画状态机) 可以对多个动画进行控制,如顺序等。右键某个动画块 ->Make Transition 控制指向的箭头。
动画的属性窗口中 Loop Time 用来控制动画是否循环播放
骨骼动画
三维的网格动画不便于使用,插入骨骼,使三维网格(皮肤)被动的运动,便于与场景物体的交互。动画文件保存的是每一帧的骨骼姿态信息。骨架模型
在场景中放入模型后,在Project窗口中新建一个Animator Controller并命名,将其拖拽到选中的模型的Inspector的Animator--Controller中。
在Animator下的Parameters中点击小加号选择trigger(触发器类型),动画状态机中连接两个动画的线可以点击,为(在Conditions中)两个动画之间的转换添加触发条件。动画状态的转换一般要在前一个动画播放完成之后才会发生,如果希望交互立即发生,在连接线的属性中将Has Exit Time 勾掉即可。
在Animator Controller中,当动画进行到某一帧的时候,可以添加一些触发事件。先选中动画文件,在属性窗口中的Event中进行添加,Event的意思是当动画进行到某一帧的时候,为其添加一个响应事件,而响应事件对应着脚本里面的某一个函数。调到某一帧后,在Function中添加命名(命名为脚本中的函数名)。
重定向:即可以将其他动画的骨骼运动运用到其他的模型中,还可以实现动画状态之间的自然融化。
Standard assets 中的ThirdPersonUserControl是一个简单的控制角色的脚本(如WASD移动,空格跳跃等)。
动画曲线
作用:在动画片段上增加额外的运动数据,可以基于动画状态来控制其他的物体(如控制角色在冷天的呼气)。
一般要将动画片段与相应的参数进行绑定,然后通过脚本进行控制。在动画的Curves(曲线)属性中进行控制,先设置一个曲线,然后编写需要的脚本,绑定到对应游戏对象,将需要根据动画变换的物体绑定到脚本。
动画层(Animation Layer)
作用:如为不同身体部位使用不同的动画状态机(就比如下半身在跑步,而上半身在进行射击的动作),
在不同层级之间复用动画状态机。(如角色受伤后动作有改变,但是动画逻辑未改变)
还可以嫁接不同身体部位,得到新的动画。
遮罩Mask
为动画层设定受该层动画影响的部位,一般是绿色表示时候影响,红色不受影响。
在动画控制器中新建图层,为不同的图层添加动画,可以通过调整动画的权重来进行不同动画的融化。使游戏对象可以做出更自然的动作。
在project窗口中,新建一个Avatar Mask(遮罩),将不用的部分点掉,添加到图层中,播放该图层的动画时,红色的部分就不会受当前动画的影响,而使用其他层的动画。
还可以添加交互功能(当用户进行操作后,修改动画层的权重),新建脚本,编辑后将其添加给游戏对象。
逆向运动学(IK)
利用骨骼动画,实现角色和游戏场景进行实时交互的技术。
正向运动学:实现骨骼动画最简单的方法,从根节点开始(骨骼的关系一般为树状结构),然后将骨骼的变换逐层传递给子孙节点,当在骨骼上绑定物体的时候使用正向运动学会比较方便(如在游戏中技术射出弓箭,要求弓箭射中敌人后要粘到敌人身上。
但正向运动学无法解决游戏人物和环境实时交互的问题。(一般只能播放事先准备好的骨骼动画)
逆向运动学一般只知道末端骨骼的姿态,然后反向计算其他骨骼的信息。
响应函数:OnAnimatorIK
要使角色能够响应IK,需在图层中将IK处理勾选上。
//使角色看向鼠标移动的方向
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class IK : MonoBehaviour
{
protected Animator animator;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
private void OnAnimatorIK(int layerIndex)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float enter = 0f;
Plane palne = new Plane(Vector3.up, transform.position);
Vector3 target;
if(palne.Raycast(ray,out enter))
{
target = ray.GetPoint(enter);
animator.SetLookAtWeight(0.5f,0.3f,0.8f,1);//修改多部位的权重,使角色的动作看起来更自然
animator.SetLookAtPosition(target);
}
}
}
//使角色的手或脚可以尽量靠近某个物体,如建立一个球,在球上方新建一个空对象Hint,将球和Hint对象拖拽给游戏对象对应的脚本中参数
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class IK2 : MonoBehaviour
{
protected Animator animator;
public Transform target;
public Transform hint;
public bool isHand = true;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
private void OnAnimatorIK(int layerIndex)
{
AvatarIKGoal g = isHand ? AvatarIKGoal.RightHand : AvatarIKGoal.RightFoot;
AvatarIKHint h = isHand ? AvatarIKHint.RightElbow : AvatarIKHint.RightKnee;
animator.SetIKPositionWeight(g, 1f);
animator.SetIKPosition(g, target.position);
animator.SetIKRotationWeight(g, 1f);
animator.SetIKRotation(g, target.rotation);
animator.SetIKHintPositionWeight(h, 1f);
animator.SetIKHintPosition(h, hint.position);
}
}
子状态
把一系列动作组成的复合动作看作一个子状态,再将子状态融入到动画状态机中,便于管理(分而治之),比如游戏中的冲刺攻击,包含了快跑,跳跃和攻击三个动画(即是一个子状态)。
在动画状态机中右键创建子状态机,双击打开编辑子状态机。在子状态机的动画播放完之后,需要转回到Base Layer(基础图层)中(在子状态的动画机中最后转到(up)Base Layer),然后将动画转New StateMachine(即新的子状态动画机中),建立一个触发器(trigger)类型的参数,建立一个脚本来确定触发条件(如当用户按下空格时)。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SubState : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
GetComponent<Animator>().SetTrigger("start");
}
}
}
融合树(Blend Tree)
对两个或者多个相似运动进行融合(最明显的例子就是走路和跑步运动,即随着角色移动速度的提高,来从走路过渡到跑步。或者在运动时,转弯的身体偏向)
<与之类似的>transition(动画过渡):是在一定的时间内平滑的从一个动画状态过渡至另一个状态(如果在短时间内完成可以接受),未产生新的动画,而Blend Tree融合树允许多动画平滑混合成新的动画(多个动作同时对生成的动作产生影响,依靠参数控制不同动作的权重)
在动画状态机中,右键中新建New Blend Tree,双击进入其界面,在右面的属性界面里可以将动画直接拖拽给Blend Tree,运行游戏,在动画状态机中调整Blend的数值,可以看到角色在不同的动画状态中过渡,变化。在Blend tree 的属性界面可以更改动画的混合类型(默认为1D,即一维),可以调整为Direct(直接),然后新建参数,赋给动画(在Blend tree中修改动画的Paramete)。
Blend Tree的动画混合类型2D Freeform Cartesian(二维的混合方式):新建多个运动域后。一般要调整Pos X,PosY的数值,用来调整运动区域,使其比较均匀(基本上可以理解为二维坐标系)。(在最面还有一个镜像,勾选后对于对称来说该状态仍有效),还需要新建参数赋给Parameters(我理解为权重)
//该段代码实现了用户可以通过上下左右来操作角色(通过动画的融合树来实现
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class BT : MonoBehaviour
{
Animator animator = null;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
float h = CrossPlatformInputManager.GetAxis("Horizontal");
float v = CrossPlatformInputManager.GetAxis("Vertical");
Vector3 move = v * Vector3.forward + h * Vector3.right;
if(Input.GetKey(KeyCode.LeftShift))
{
move.z *= 0.5f;
}
float turn = move.x;
float forward = move.z;
animator.SetFloat("speed", forward, 0.1f, Time.deltaTime);
animator.SetFloat("turn", turn, 0.1f, Time.deltaTime);
}
}
目标匹配(Match Target)
用途:如角色在运动时,手或脚在特定时间到达特定位置(比如角色跳过石头的时候脚需要踩在石头上,跳起来够着某个头顶的东西),通常使用目标匹配的功能来影响角色的姿态,调整事先制作的动画,达到特定效果。
//让角色跳到某个指定位置(一般是需要在物体上方放置空对象)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MUBIAOPP : MonoBehaviour
{
Animator animator;
public Transform rightFoot;
AnimatorStateInfo animState;
public float matchStart;//进行目标匹配的开始与结束时间,一般需要在unity中调整开始结束时间(范围0~1),是角色的动作看起来更自然。
public float matchEnd;
// Start is called before the first frame update
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if(animator !=null)
{
animState = animator.GetCurrentAnimatorStateInfo(0);
if (Input.GetButton("Fire1")) animator.SetTrigger("jump");
if(animState.IsName("JUMP00"))//IsName中的参数为需要进行目标匹配的动画
{
animator.SetTrigger("jump");
animator.MatchTarget(rightFoot.position, rightFoot.rotation, AvatarTarget.RightFoot,
new MatchTargetWeightMask(Vector3.one, 1), matchStart, matchEnd);
}
}
}
}