文章目录
进阶组件
生命周期函数
生命周期函数是指:一个游戏物体冲产生、游戏过程中、结束等函数
- Awake():唤醒事件、游戏一开始就执行,执行一次
OnEnable():启用事件,只执行一次,当脚本组件被启用的时候执行一次 - Start():开始事件,只执行一次
- Update():更新事件,执行N次,每帧执行一次
FixedUpdate():固定更新,执行N次,每0.02s执行一次,所有物理组件相关的更新都在这个事件中处理
LateUpdate():稍后更新时间,执行N次,在Update()执行完毕后再执行 - OnDestory():销毁事件,执行一次,当脚本所挂载的游戏物体被销毁时执行
OnGUI():GUI渲染事件,执行N次,次数是Update()的两倍
OnDisable():禁用事件,执行一次,在OnDestory()前执行;当该脚本被“禁用”后也会触发该事件
常用API
Invoke函数
用于调用、执行
- Invoke(string methodName, float time):输入一个方法名称,过个几秒来执行
methodName:方法名称
time:几秒后执行 - InvokeRepeating(string methodName, float time, float repeatRate):
repeatRate:重复时间间隔 - CancelInvoke(string methodName):取消调用,使用无参重载就是取消全部
public class NewBehaviourScript : MonoBehaviour
{
void Start()
{
//延迟执行,只执行一次
Invoke("print",1.2f);
//延迟执行,可重复执行
InvokeRepeating("print", 1.2f, 2.0f);
}
void Update()
{
if(Input.GetKeyDown((KeyCode.Space)))
{
Debug.Log("Input Space");
//取消print
CancelInvoke("print");
//没有参数将取消全部
//CancelInvoke();
}
}
private void print()
{
Debug.Log("12345");
}
}
协同程序
协同程序一般称为协程,还有一个主程序也就是各种生命周期函数
使用协程的情况:例如使用WASD正常走路,中途按了一次F键,希望这个物件一直处于一个旋转的状态,可以定义一个bool变量,按F设置其为true,在Update中判断并旋转物件
private bool isRotate = false;
void Start()
{
}
void Update()
{
InputMove();
if (Input.GetKeyDown(KeyCode.Space))
{
isRotate = !isRotate;
if (isRotate)
{
InvokeRepeating("Rotato", 0, 0.02f);
}
else
CancelInvoke("Rotato");
}
}
private void Rotato()
{
transform.Rotate(new Vector3(0, 1, 0));
}
定义协程的方法:
协程必须包装在一个函数中
//协程
private IEnumerator DoRotate()
{
Debug.Log("做事前");
//等待0.02s
yield return new WaitForSeconds(0.02f);
Debug.Log("做事后");
}
使用协程
Coroutine StartCoroutine(Demo("参数"));
Coroutine StartCoroutine():执行一个协程,参数直接调用协程方法。可以使用一个变量接受返回值用于后续停止该协程
协程的运行顺序与主程序无关,可以理解成开了一个分支专门运行这个协程;若有多个协程打开,这些协程之间也无关
停止协程
协程如果运行到最后一行,意味着停止,但是我们也可以选择主动停止
StopAllCoroutine():结束全部协程
StopCoroutine():停止某个协程
- StopCoroutine(IEnumerator routine):和调用协程一样,但是如果协程有参数则不适用
- StopCoroutine(Coroutine routine):参数填写协程变量
- StopCoroutine(string methodName):参数填写协程方法名
工具类
数学
- Mathf.Abs(int num):返回绝对值
- Mathf.Max(int a, int b):返回最大值
- Mathf.Min(int a, int b):返回最小值
- Mathf.Round(2.5f):返回四舍五入后的值
- Mathf.Ceil(2.5f):返回向上取整的值
- Mathf.Floor(2.5f):返回向下取整的值
- Random.Range(0, 5):返回随机值
- 如果是int重载:返回[0, 5)的随机int值
- 如果是float重载:返回[0.0, 5.0]的随机float值
时间
只读:
- Time.time:表示游戏运行到现在的时间,会随着游戏的暂停而停止计算
- Time.deltaTime:表示从上一帧到当前帧的时间,以秒为单位
- Time.realtimeSinceStartup:表示自游戏开始后的总时间,即是暂停也会增加,也就是现实经历的时间
读写:
- Time.timeScale:时间流速,默认值为1,若设置<1,则表示时间减慢;若设置>1,则表示时间加快;0意味着游戏暂停
线条与射线
拖尾
拖尾也是现实中的现象,比如飞机划过天空留下的尾迹,火箭后方的火焰等等;主要特点是一般附属在物体的尾部,随着物体的移动而产生效果
创建拖尾游戏物体:右键层级面板->Create->Effects->Trail
拖尾渲染器
拖尾游戏物体的本质就是挂载了Trail Renderer这个组件,所有的效果都是由这个组件完成的
常用参数:
- Width:拖尾宽度
- Time:拖尾销毁时间
- Min Vertex Distance:定点距离,理解成平滑程度
- Emitting:是否发射开关
- Color:颜色设置
- Corner Vertices:角定点数量0~90,影响平滑程度⬆️
- End Cap Vertices:端部定点数量0~90,影响平滑程度⬆️
效果图:
物理射线
从一个点往一个方向发射一根无限长的射线,当这根射线与场景中其余的游戏物体的碰撞体组件相碰撞时射线结束;犹豫射线可以与物理组件Collider相交互,所以也称之为物理射线(射击游戏中,可以利用射线检测玩家按下鼠标的书剑判断是否可以击中敌人)
//定义射线,第一个参数为发射源,第二个参数为发射方向
Ray ray = new Ray(Vector3.zero, new Vector3(0, 1, 0));
//定义射线检测
RaycastHit hit;
//射线检测-发射射线,如果碰到碰撞体会返回true
if(Physics.Raycast(ray,out hit))
{
Debug.Log(hit.collider.gameObject.name);
}
RaycastHit:射线接触碰撞体后得到的碰撞信息都保存在这种类型的变量中
常用属性:
- hit.point:接触坐标
- hit.collider:接触到的碰撞体组件
- hit.distance:接触点到起点的距离
通过摄像机生成射线:
从相机或者理解成屏幕中心发射一个射线,方向为鼠标的位置
//从屏幕中心发射射线至鼠标位置
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
加载预制体
加载游戏物体:
- 游戏中的敌人、特效等等一般都是在需要使用的时候动态的加载出来
- 加载的过程叫做实例化游戏物体
加载预制体: - 预制体也是一个GameObject,获取这个游戏物体可以通过面板赋值的方式
- 使用资源加载,需要使用动态加载的预制体必需放在Resources文件夹(如果没有需要自己创建)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Manager : MonoBehaviour
{
private GameObject cube;
public GameObject prefab;
// Start is called before the first frame update
void Start()
{
cube = GameObject.Find("Cube1");
prefab = Resources.Load<GameObject>("Objects/Mode");
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.Q))
{
//实例化游戏物体,参数从左往右依次为 需要实例化的游戏物体、实例化的位置、不旋转、父物体
GameObject.Instantiate<GameObject>(prefab, new Vector3(Random.Range(0.0f, 5.0f), Random.Range(0.0f, 5.0f), Random.Range(0.0f, 5.0f)), Quaternion.identity, null);
}
}
}
UI系统
UI就是用户界面,比如游戏中的按钮、背包、头像、等级等等
在层级面板中右键:
创建文本、图像等等的同时也会一起创建Canvas和EventSystem:
- Canvas:UI画布,用于存放各种UI元素,UI元素只有在Canvas下才可以正确显示
- EventSystem:事件系统,用来支撑UI元素的点击拖拽等事件,当使用UI时需要保证场景中有这个游戏物体,但是不需要去内部的组件内容,存在即可
Text文本
Text游戏物体本质就是包含一个Text文本组件,但是UI游戏物体具备的是Rect Transform而不是Transform组件
- Rect Transform:矩阵变换方阵,UI游戏物体的特有组件,是一个继承了Transform的组件,因为UI游戏物体具备各种布局方式,和普通的游戏物体差异性很大
基于Rect Transform使用快捷键T来设置UI游戏物体的大小
Text组件用于显示玩家ID、等级、技能以及其他属性的文本类型
Text常用属性
- Text:显示的文本内容
- Font:字体
- Font Style:字体样式,如加粗、下划线等
- Font Size:字体大小
- Line Spacing:行间距
- RichText:富文本
- Color:字体颜色
- Raycast Target:是否作为射线检测的目标以及点击等等
Unity脚本做任何与UI相关的工作都要先引用using UnityEngine.UI
,也就是UI命名空间
组件获取则是:GetComponent<Text>()
组件的属性获取与修改和面板中的单词基本一致,可以直接修改
Image图片
(依旧是必须放在Canvas下才能生效)
主要属性:
- SourceImage:源图片,在脚本中叫sprite
- Color:图片颜色
- RaycastTarget:是否作为射线检测的目标以及点击、拖拽等等
- ImageType:显示模式
- Simple:普通模式
- Sliced:切片,需要图片九空格,要在资源层面处理
- Tiled:平铺
- Filled:填充
主要功能:
- Set Native Size:设置为图片的原始尺寸
Unity中的图片资源:
在项目管理器中点击一个图片资源,然后在检查器面板中可以看到资源的相关属性
- TextureType:Unity中大多数情况都需要选择为Sprite
- Sprite Model:精灵模式,精灵是Image组件持有的实际图片
- Pixels Per Unit:像素单位,会影响实际在游戏中图片的尺寸,数值越大游戏中越小
- Pivot:图片的中心
- Sprite Editor按钮:编辑精灵
SpriteEditor:
- PackageManager
- 插件/功能管理器
- 可以在插件管理器选择自己需要的功能来安装,SpriteEditor需要2D Sprite插件:
- 精灵编辑
- 设置Pivot轴心
- Revert:恢复设置
- Apply:应用操作
- 蓝色外框是精灵的九宫格
SpriteEditor-Slice图片切片
图片切片:实际开发中不会一个按钮一个图片,而是选择打包在一起,所以需要在Unity中进行分割
- Automatic:自动分割,实际是根据不同游戏物体之间的透明通道进行
- Gird By Cell Size:根据网格像素分割,根据一个宽高(像素)自动分割
- Grid By Cell Count:根据网格数量分割,就是将一个图片等分拆成几行几列
- Pivot:分割时每一个精灵的轴心
- 拖拽鼠标:手动分割
- 编辑过程中白色的框是一个精灵,点击后可以设置这个精灵的细节
切片完成后即可分别添加切好的素材:
可以通过手动调整绿色九宫格来达到一个按钮延长得效果(绿色九宫格内的效果拉伸,外不变):
拉伸后的效果:
Button按钮以及点击事件
Button按钮
按钮的目的是用于交互,也就是玩家点击后响应玩家的操作,比如完成登录游戏、装备武器等等
在Unity中,按钮是一个复合游戏物体,由两个游戏物体组成:
- Button
-
- Image组件:按钮的背景图片
-
- Button组件:按钮的相关参数、设置、事件(Raycast Target未勾选则按钮生效,无法响应正常操作;区别于Interactable,未勾选则无法点击)
- ext
-
- Text组件:用于显示按钮上的文本
Button属性
Interactable:可交互的,也就是可以点击的
Transition:过渡方式,按钮一般分为几种状态,比如鼠标悬浮、点击、不可用
- None:没有效果
- Color Tint:颜色变化,也就是不同状态时候Image图片的颜色不一样
-
- Target Graphic:用于交互的图片
-
- Normal Color:默认颜色
-
- Highlighted Color:突出显示的颜色
-
- Pressed Color:按下时的颜色
-
- Selected Color:选择时的颜色,当多个Button存在时,最后一个按钮的颜色为此
-
- Disabled Color:禁用时的颜色
-
- Color Multiplier:颜色倍增
-
- Fade Duration:颜色过渡时间
- Sprite Swap:修改精灵,不同状态Image中Sprite不同
Button代码设置点击事件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ButtonC : MonoBehaviour
{
private Button myButton;
void Start()
{
//获取组件
myButton = GetComponent<Button>();
//绑定点击事件
myButton.onClick.AddListener(ButtonClick);
myButton.onClick.AddListener(() => ButtonClick2("按钮被点击了!"));
}
private void ButtonClick()
{
Debug.Log("Clicked!");
}
//传参
private void ButtonClick2(string str)
{
Debug.Log(str);
}
}
表格布局组件
类似背包这种想要排列整齐的时候一般就会使用Gird Layout Group表格布局组件,会自动管理其下方所在其他UI原色的大小、位置等信息,在层级面板中右键并没有表格布局组件,首先要创建一个空的游戏物体->手动添加Grid Layout Group组件
Grid Layout Group属性
- Padding:整个表格的边距(分上下左右留出)
- Cell Size:单元格的大小
- Spacing:单元格的间距
- Start Corner:行/列,第一个成员从什么位置开始
- Child Alignment:子对象对齐,如果布局元素未填满所有可用空间,则应用这个对齐方式
- Constraint:将表格限制为固定数量的行或列
Canvas画布
UI的根结点就是Canvas,意味着UI游戏物体都要放在Canvas下,才能得到正确的显示
一个场景中Canvas时可以存在多个的,并且可以同时生效
Canvas游戏物体由三个组件组成:
- Canvas:画布
- Canvas Scaler:画布比例
- Graphic Racaster:射线检测
Canvas组件
Render Mode:渲染模式
- Screen Space-Overlay模式:Canvas将置于屏幕最上层,自动填充屏幕,不会被其他模式的Canvas或2D/3D物体遮挡
- Screen Space-Camera模式:Canvas将置于相机前方,此时在Canvas和相机中间的2D/3D物体将显示在UI上面,利用这一点,可以实现UI界面展示3D模型
-
- Render Camera:对应的渲染相机,也就是该Canvas显示在哪个Camera前面
-
- Plane Distance:Canvas与Camera的距离
- World Space模式:Canvas将作为一个游戏对象显示在3D场景内
-
- Event Camera:接受UI事件的Camera
Pixel Perfect:完美像素,边缘更清晰
Sort Order:画布排序次序,场景中具备多个Canvas时才有意义
Canvas Scaler组件
Canvas Scaler也是屏幕适配的主要方式,一般通过该组件就可以完成适配
UI Scale Mode缩放模式:
- Constant Pixel Size模式:固定像素大小,不论屏幕分辨率尺寸大小如何变化,像素保持原有大小不变
- Scale With Screen Size模式:屏幕自适应常用方式
-
- Reference Resolution:参考分辨率,进行屏幕适配,自动缩放UI大小时,将以此作为参考
-
- ScaleFactor:缩放背书
Canvas定位
当我们设置好Canvas游戏物体后,画布下的UI游戏物体存在很多定位的问题
Rect Transform主要设置:
- Pos:UI游戏物体的X、Y、Z坐标,但是Z轴很少使用
- Width Height:UI游戏物体的宽高
- Anchors:锚点,可以让游戏物体相对于父物体来定位
- Pivot:中心点,取值[0, 1]
- Rotation:旋转
- Scale:缩放
Anchors预设
- 相对于父物体什么位置进行定位
- 相对于父物体进行怎样的弹性拉升
事件
在Button中的按钮点击就是事件,但在实际项目中,UI并不是只有点击这一种事件,比如鼠标悬浮、鼠标按下、鼠标弹起、鼠标拖拽等等;而且UI本身可能也并不是一个按钮,这些事情可以通过给游戏物体创建脚本实现
脚本中添加using UnityEngine.EventSystems事件相关命名空间
脚本需要继承事件接口,并实现对应方法即可
- IPointerClickHandler:鼠标点击
- IPointerDownHandler:鼠标按下
- IPointerUpHandler:鼠标弹起
- IPointerEnterHandler:鼠标进入
- IPointerExitHandler:鼠标退出
- IBeginDragHandler:开始拖拽
- IDragHandler:拖拽中
- IEndDragHandler:停止拖拽
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class IPoniter : MonoBehaviour,IPointerClickHandler,IPointerDownHandler,IPointerUpHandler,IPointerEnterHandler,IPointerExitHandler,IBeginDragHandler,IDragHandler,IEndDragHandler
{
//鼠标点击
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("鼠标点击了!" + gameObject.name);
//throw new System.NotImplementedException();
}
//鼠标按下
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("鼠标按下了!" + gameObject.name);
//throw new System.NotImplementedException();
}
//鼠标弹起
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log("鼠标弹起了!" + gameObject.name);
//throw new System.NotImplementedException();
}
//鼠标进入
public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("鼠标进入了!" + gameObject.name);
//throw new System.NotImplementedException();
}
//鼠标退出
public void OnPointerExit(PointerEventData eventData)
{
Debug.Log("鼠标退出了!" + gameObject.name);
//throw new System.NotImplementedException();
}
//开始拖拽
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("开始拖拽!" + gameObject.name);
//throw new System.NotImplementedException();
}
//拖拽中
public void OnDrag(PointerEventData eventData)
{
Debug.Log("拖拽中!" + gameObject.name);
//throw new System.NotImplementedException();
transform.position = Input.mousePosition;
//事件发生时鼠标的位置
//transform.position = eventData.position;
}
//停止拖拽
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log("停止拖拽!" + gameObject.name);
//throw new System.NotImplementedException();
}
void Start()
{
}
void Update()
{
}
}
动画系统
游戏动画
游戏中的动画,一般指的是模型动作,而模型动作主要是服务视觉;在数据计算上一般并不依赖动作,实际的攻击计算等使用的一般还是碰撞体
动画系统介绍
Unity动画系统
模型和动作
- 非人形角色,比如一个章鱼怪,它的动作基本上是为了这一个模型来设计的,无法复用到其他模型
- 人形角色,符合标准都可以复用,基于Avatar
角色动作组成
- 游戏物体上挂咋爱Animator动画组件
- Animator组件上持有Controller(动画控制器),Controller上配置好动作以及动作切换逻辑
- 利用Animator组件来播放动画以及切换动画
Unity内制作动画
Unity制作动画准备
动画窗口:Window->Animation->Animation,用来制作、预览动画
动画控制器窗口:Window->Animation->Animator,用来配置动作以及切换逻辑
选中一个游戏物体,在动画窗口点击Create会自动进行以下配置,这也意味着一个游戏物体需要动画的必要条件
- 添加Animator组件,游戏物体进行动画的必要条件
- 创建Animator Controller(动画控制器),并在Animator组件中引用该文件,用于配置动画片段、动画切换
- Animator Controller中添加一个Animation Cilp(动画片段,也就是一个具体的动作),Animator Controller和Animation Cilp都是可以在项目面板中使用右键->Create来创建的
导入动画
资源商店中下载的动画一般都附带了演示模型,可以无视模型直接拖拽到对应的动画控制器,然后选择Animation面板预览即可
动画控制
动画片段文件设置
点击动画文件后,检查面板中可以设置该动画片段的参数
Loop Time:动画是否循环播放
Loop Pose:是否循环姿势,让头尾链接更平滑
Animator面板
Unity动画是基于状态机来实现的,每一个动作都是一个状态,状态之间是可以进行切换的(右键创建过渡),但是需要进行条件判断(比如走路状态切换到跳跃,之后再正常走路)
状态面板
当我们选择一个状态后,检查面板中会出现这个状态的一些参数
- Motion:这个状态具体要播放的动画文件
- Speed:动画的播放速度,float类型
- Mirror:镜像动画,动画左右相反
- Transitions:该状态参与的状态转换
-
- Solo:当两个状态之间有多条条件时,仅生效一条
-
- Mute:禁用
- Mute:禁用
状态切换
连线决定了某个状态是否可以切换到其他状态,并且箭头意味着切换方向,箭头数量意味着过渡数量,红色箭头意味着禁用某条过渡
状态切换参数
状态之间的连线,点击某根连线后,检查面板中可以设置具体切换的参数
Has Exit Time:是否播放完毕才能切换(可称之为强制动作——取消后摇)
Conditions:条件参数,这条线什么时候起效果
Settings:可以调整两个状态切换的细节
参数面板
Parameters中可以设置整个动画控制器中有条件参数
- Float:同C#
- Int:同C#
- Bool:同C#
- Trigger:只执行一次
设置好条件参数后,可以点击一条线设置它的Conditions来选择当什么参数成立时切换动画
数值类条件:
- Greater:>
- Less:<
- Equal:==
- NotEqual:!=
代码控制
游戏运行后,动画会自行从入口处开始执行,但是我们可以获取Animator组件后修改参数,从而控制动画切换
- SetInteger(“Run”, 1):修改参数的值,对应的还有SetBool、SetTrigger、SetFloat
- GetInteger(“Run”):获取参数的值,对应的还有GetBool、GetFolat
- speed:整体的播放速度
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimationScript : MonoBehaviour
{
private Animator animator;
void Start()
{
animator = GetComponent<Animator>();
}
void Update()
{
Move();
}
private void Move()
{
//行走的同时播放行走动画
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 dir = new Vector3(h, 0, v);
transform.Translate(dir * Time.deltaTime * 15);
float temp = (Mathf.Abs(h) + Mathf.Abs(v)) / 2;
animator.SetFloat("Run", temp);
}
}
动作事件
UI是鼠标点击作为事件的触发点
动作中运行到这一帧作为事件的触发点,比如行走动画落脚的时候才播放走路的声音、攻击动画攻击到某一帧后允许取消后摇
动作事件添加
首先,代码中添加事件处理函数,也就是该事件发生、要运行的方法,这个函数所在的脚本必须在该动画所在的游戏物体上,支持传递参数
其次,我们需要在动画中做好事件标记
在Animation面板中选一个动作,在某一帧点击AddEvent,然后点击事件标记,检查面板中可以设置该事件触发的函数
动画资源中添加
外部导入的动画很多角色都通用,这样操作不方便,因此需要从动画所在的模型身上来设置
- 选择动画所在的模型
- 检查面板中选择Animation
- 拉到下方选择Events
- 选择合适的位置添加事件
下拉至:
如果该动画所应用的游戏物体上挂载的脚本并不能找到这个函数,Console面板就会报错
有限状态机
状态机概念
Animator就是基于有限状态机,并且在动画控制器中可视化的配置了动画的状态以及状态切换,在很多游戏开发时我们都可以使用有限状态机的思路来解决问题
将事物的不同行为抽象成状态,比如游戏中有一个敌人正在巡逻,那么他的状态可以分为这样:
- 休息:在一个位置停留一段时间
- 巡逻:根据预先设定好的路线来回走动,并且时不时地休息一段时间
- 追赶:巡逻期间如果遇到玩家,则会追赶玩家
-
- 如果追到则攻击玩家
-
- 追赶一段时间无法追上则回去巡逻
- 攻击:攻击玩家,如果玩家逃跑则切换为追赶
- 回去休息/巡逻
有限
有限状态机的有限是指状态的数量有限,这也意味着我们在开发阶段可以预估到全部行为,否则会出现不可预估的问题;比如UI中的按钮点击,我们可以估计到的有:鼠标进入、鼠标移出、点击(左右键)、拖拽、禁用等等
角色控制
角色控制器组件
除了基于Transform以及Rigidbody而外,还有第三种Character Controller也是最容易上手的角色移动方式;Transform不具备物理特性,而Rigidbody和容易被弹开、传模
角色控制器面板参数
- Slope Limit:控制角色最大的爬坡斜率
- Step Offset:控制角色可以迈上最大的台阶高度
- Skin Width:在角色的外围包裹一层“皮肤”,这层皮肤的厚度相当于角色身上透明的衣服,如果Skin Width设置为1m,那么角色就会浮空1m,一般保持默认
- Min Move Distance:最小移动距离,默认1mm,如果该数值过大但代码中单位移动速度很慢,角色就不会移动
- Center/Radius/Height:角色控制器组件在Scene面板中体现为一个胶囊碰撞器的形状,这也导致其他的碰撞体并不需要,Center为胶囊中心位置,Radius为半径,Height为高度
角色控制器移动
角色控制器组件所在的游戏物体身上不需要挂载碰撞和刚体组件
- 常用属性
-
- isGrounded:是否在地面上
- 常用方法
-
- Move(Vector3 dir):和Transform.Translate雷同,没有中立,需要传递的是一个方向,数值的大小影响移动速度,所以需要乘上Time.deltaTime
-
- SimpleMove(Vector3 speed):会应用重力,需要传递的是一个速度,并且本身就是按照时间来计算的,数值大小虽然也会影响移动速度,但是不会被帧率影响,所以不需要乘Time.deltaTime
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Character_Controller : MonoBehaviour
{
private CharacterController controller;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
//Move();
//是否在地面,会返回一个布尔值
Debug.Log(controller.isGrounded);
}
//SimpleMove放在FixedUpdate固定0.02s更新更好,与物理组件相关的都放在这
private void FixedUpdate()
{
SimpleMove();
}
//不会应用重力,但是可以手写
private void Move()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 dir = new Vector3(h, 0, v);
//controller.Move(dir * 1.2f);
//Move函数需要加上Time.deltaTime(上一帧速度,平滑)才有重力
if(controller.isGrounded)
{
controller.Move(dir * Time.deltaTime * 20.0f);
}
else
{
dir.y -= Time.deltaTime * 10.0f;
controller.Move(dir * Time.deltaTime * 20.0f);
}
}
//会应用重力
private void SimpleMove()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 speed = new Vector3(h, 0, v);
//SimpleMove自带重力
controller.SimpleMove(speed * 10.0f);
}
}
角色模型资源分析
常规角色组成
- 白模:模型的顶点信息
- 材质球:颜色细节
- 动作文件:模型的动作
- Avatar映射文件:人形动作中才使用,映射人体的位置对应什么游戏物体,这样动作文件才能正确工作,基于此可以让动作复用