欢迎光临散文网 会员登陆 & 注册

Unity基础学习笔记01界面与动画系统

2021-11-29 20:35 作者:挽秋_z  | 我要投稿

界面布局

密码: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);
           }
       }
   }
}








Unity基础学习笔记01界面与动画系统的评论 (共 条)

分享到微博请遵守国家法律