组件介绍
| 组件概念
可替换性、可直接使用
| 游戏组件
系统 - 如UI系统,有按钮、图片、下拉框,这些功能都是不同的组件,在一起就组成了 UI系统
Unity内置简易模型和材质
| 模型介绍
层级面板 -> 右键 -> 3Dobject -> 各种模型
| 材质介绍
顶点组成的网格数据
Scene 界面游戏物体操作
| 工具栏
手型工具:Q & 鼠标中键,用于拖动场景
移动工具:W ,用于移动模型的位置
旋转工具:E ,用于旋转模型
缩放工具:R ,用于放大缩小模型
移动&缩放工具:Y ,可以同时移动、旋转模型
| 约束与吸附
变化拘束:移动、缩放、选择时按住 Ctrl (拘束程度在 Edit -》 Grid And Snap 中可以设置)
模型吸附:选择模型后按 V,选择吸附位置在拖拽到需要吸附的位置上
复制模型:Ctrl + C
粘贴模型:Ctrl + V
快速复制:Ctrl + D
快速定位:F
自定义组件
| 为什么要自定义组件
我们写的组件大多和游戏逻辑有关,比如玩家控制脚本。
| 如何自定义组件
项目面板右键 -> 创建 -> C#脚本 ->拖拽
| 注意事项
继承 MonoBehaviour 的类都是组件
只有组件可以挂载到游戏物体身上
Inspector面板 和 C# 一同使用
演示:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class L2_4Demo : MonoBehaviour
{
public string Name;
public int ID;
void Start()
{
Debug.Log(666);
}
}
Transform组件
| 组件介绍
三个主要数值:
Position:位置
Rotation:旋转
Scale:缩放
| 组件常用属性和方法
属性:
childCount
:子物体的数量
parent
:父物体的 Transform 组件
root
:最高级别父物体
postion
、eulerAngles
、localScale
方法:
Find(string)
:查找子物体
Translate(Vector3)
:朝着一个坐标移动
Rotate(Vector3)
:旋转一个角度
LookAt(Transform)
:看向目标
| 组件的特殊性
可以直接访问 Transform 组件
演示:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class L2_5TransformDemo : MonoBehaviour
{
private float num = 0;
void Start()
{
#region 属性
//print(transform.childCount);
//print(transform.parent);
//print(transform.root);
//print(transform.eulerAngles); // 旋转
//print("当前坐标:"+transform.position);
//print("当前旋转:" + transform.rotation);
//print("当前缩放:" + transform.localScale);
//transform.position = new Vector3(num, 10, 10);
//transform.rotation = new
//num += 0.01f;
#endregion
#region 方法
//print(transform.Find("C"));
//transform.Translate(new Vector3(-0.01f, 0, 0));
//transform.Rotate(new Vector3(3, 0, 0));
//transform.LookAt(transform.parent);
#endregion
}
}
GameObject
| GameObject 是什么
在 层级面板 中的都是游戏对象或者说游戏物体。
| 组件中的 gameobject
组件中可以使用来自基类继承 gameObject 属性 直接访问脚本所在的游戏物体,类似 transform。
gameObject:组件所在游戏物体
transform:组件所在游戏物体的transform组件
| GameObject 常用属性和方法
属性:
name
:游戏物体名称,和层级面板中等同
tag
:游戏物体的标签
activeInHierarchy
:显示状态
transform
:这个游戏物体的变换组件
方法:
static GameObject Find(string path)
:一个静态方法,查找游戏物体
GetComponent<T>()
:获取游戏物体身上的组件,T代表要查找的类型,类似方法有很多
SetActive(bool)
:修改显示状态
演示:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class L2_6Demo : MonoBehaviour
{
private GameObject gO;
public Transform ts;
void Start()
{
// 获取当前组件所在的游戏物体
//print(gameObject);
//print(gameObject.transform.position);
//print(gO.transform.position);
//print(ts);
//print(ts.position);
//print(ts.gameObject);
//print(gameObject.name);
//print(gameObject.tag);
//print(gameObject.activeInHierarchy);
//print(gO.activeInHierarchy);
//gO = GameObject.Find("C/D");
//print(gO.transform.localPosition);
//GameObject go = gameObject.GetComponent<GameObject>(); //error
//print(go.name);
Transform temptransform = gameObject.GetComponent<Transform>();
BoxCollider boxCollider = gameObject.GetComponent<BoxCollider>();
print(temptransform.position);
print(boxCollider.isTrigger);
gameObject.SetActive(false);
}
}
预制体
| 概念
预先制作好的游戏物体。
如:lol小兵,远程近战,什么时候放,固定ai逻辑。
| 创建
将游戏物体放在Assets面板。
| 使用
将预制体从项目面板拖拽到层级面板来达到复用效果。
接近“引用关系”
预制体被删除,不影响游戏物体(但会变成红色)。右键里可以选择取消引用关系
双击资源文件夹里的预制体或点击预制体小箭头,进入“异世界”进行编辑
| 修改
预制体可以套娃,也就是预制体套预制体。
变体:
如果游戏物体已经是预制体,Unity会弹窗提醒我们选择创建模式
原始预制体:一个完全独立的预制体
预制体变体:旧的预制体变化,变体也会发生变化,但是变体保留和旧预制体不同的部分
Unity生命周期函数
| 概念
指一个组件从激活到销毁的整个过程。
| 常用生命周期函数
Awake()
:唤醒事件,一开始就执行,只执行一次。
OnEnable()
:启用事件,每次启用都执行一次。当脚本组件被启用的时候执行一次
Start()
:开始事件,执行一次
FixedUpdate()
:固定更新事件,执行N次,每0.02s 执行一次。所有物理相关的更新都在这个事件中处理
Update()
:更新事件,执行N次,每帧执行一次
LateUpdate()
:稍后更新事件,执行 N 次,在 Update()
事件执行完毕后再执行
OnDisable()
:禁用事件,每次禁用都执行一次。在 OnDestroy()
事件也会执行
OnDestroy()
:销毁事件,执行一次。当组件被销毁时执行
演示:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class L2_8Demo : MonoBehaviour
{
private void Awake()
{
// 初始化一次
print("Awake");
}
private void OnEnable()
{
// 如 背包
print("OnEnable");
}
void Start()
{
print("Start");
}
void Update()
{
// 每帧执行一次
print("Update");
// 我渲染上一帧的时间
//print(Time.deltaTime);
}
private void LateUpdate()
{
print("LateUpdate");
}
private void FixedUpdate()
{
print("FixedUpdate");
}
private void OnDisable()
{
print("OnDisable");
}
private void OnDestroy()
{
print("OnDestroy");
}
}
Invoke
| 函数使用
Invoke
是调用、执行的意思Invoke(string methodName, float time)
:输入一个方法名称,过个几秒 来执行一次methodName:方法名称
time:几秒后执行
InvokeRepeating(string methodName, float time, float repeatRate)
:重复调用methodName:方法名称
time:几秒后执行
repeatRate:重复间隔时间
CancelInvoke(string methodName)
:取消调用,使用无参重载就是取消全部
演示:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class L2_9Demo : MonoBehaviour
{
void Start()
{
// 3s 后执行一个方法/行为
//Invoke("Demo", 3);
// 2s 后,每间隔1s执行一次
InvokeRepeating("Demo", 2, 1);
// 5s 后执行取消Demo
Invoke("CancelDemo", 5);
}
private void CancelDemo()
{
CancelInvoke("Demo");
}
public void Demo()
{
print("Demo");
}
}
协程
| 概念
协同程序,并不是多线程。
要有一个主程序,这个主程序就是生命周期函数。
为什么需要?主程序已经在执行某个任务,希望 “同时运行” 其他逻辑,这里的同时并不是多线程意义的,只是感官上同时。
| 函数的定义
协程特定返回值: IEnumerator
返回: yield return
协程不会因为前面返回则不执行后面的代码
小演示:
// 常规函数
public int GetNum()
{
return 0;
}
// 协程函数
public IEnumerator Demo()
{
print("先执行的");
// 等待 1s
yield return new WaitForSeconds(1.0f);
print("后执行的");
// 下一帧继续执行
yield return null;
print("最后执行的");
}
| 函数的使用
Coroutine StartCoroutine(Demo("这是参数"))
:执行一个协程,参数直接调用协程方法即可。可以用一个变量接受返回值用于后续停止该协程。我们在生命周期函数中调用协程,但是协程的运行顺序和主程序无关,可以理解成开了一个分支专门运行这个协程,如果我们打开了多个协程,这些协程之间也无关。
| 函数的停止
StopAllCoroutines()
:结束全部协程StopCoroutine(demo())
:结束某个协程程序StopCoroutine(IEnumerator routine)
和调用协程一样使用,但是如果协程有参数不要使用这个StopCoroutine(Coroutine routine)
:参数填写协程变量StopCoroutine(string methodName)
:参数填写协程方法的名
演示:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class L2_10Demo : MonoBehaviour
{
void Start()
{
//StartCoroutine("Demo");
//Coroutine cor = StartCoroutine(Demo(10));
//StopCoroutine(cor);
//StartCoroutine(Demo2());
StartCoroutine(Demo3());
StartCoroutine(Demo4());
}
// 常规函数
public int GetNum()
{
return 0;
}
// 协程函数
public IEnumerator Demo(int num)
{
print(num);
print("先执行的");
// 等待 1s
yield return new WaitForSeconds(3f);
print("后执行的");
// 下一帧继续执行
yield return null;
print("最后执行的");
}
// 协程函数
public IEnumerator Demo2()
{
while (true)
{
// 暂停 0.1s
yield return new WaitForSeconds(0.01f);
transform.Rotate(new Vector3(5, 0, 0));
}
}
// 协程函数
public IEnumerator Demo3()
{
transform.position = new Vector3(10, 10, 10);
yield return Demo2();
}
// 协程函数
public IEnumerator Demo4()
{
// 5s 之后取消协程
yield return new WaitForSeconds(5);
// 取消全部
StopAllCoroutines();
}
}
常用工具类
| 数学工具类
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)
:返回随机值(1)如果是int 重载:返回0-4的随机值,包含0;不包含5
(2)如果是float重载:返回0-5的随机值,包含0并且包含5
| 时间工具类
只读:
Time.time
:表示从游戏运行到现在的时间,会随着游戏的暂停而停止计算Time.deltaTime
:表示从上一帧到当前帧的时间,以 秒 为单位Time.realtimeSinceStartup
:表示自游戏开始后的总时间,即使暂停也会增加,也就是现实时间
读写:
Time.timeScale
:时间缩放,默认值为 1,若设置 <1,表示时间减慢,若设置 >1,表示时间加快,0 意味着游戏暂停
演示:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class L2_11Demo : MonoBehaviour
{
void Start()
{
#region math
//int num1 = Mathf.Abs(-6);
//int num2 = Mathf.Max(3,4,5,10,20);
//int num3 = Mathf.Min(3,4,5,10,20);
//float num4 = Mathf.Round(2.5f);
//float num5 = Mathf.Ceil(2.4f);
//float num6 = Mathf.Floor(2.4f);
//print(num1);
//print(num2);
//print(num3);
//print(num4);
//print(num5);
//print(num6);
// 0~4 因为包含左边,不包含右边
//int num1 = Random.Range(0, 5);
//print(num1);
//float num2 = Random.Range(0, 5.0f);
//print(num2);
#endregion
#region time
Time.timeScale = 3;
#endregion
}
private void Update()
{
#region time
//print(Time.time);
// 每帧上升 1m
//transform.Translate(new Vector3(0, 1f, 0));
// 每 秒 上升 1m ; 方向 * 速度 * 一帧花费的时间
//transform.Translate(new Vector3(0, 1f, 0) * 1 * Time.deltaTime);
//print(Time.deltaTime);
print("游戏时间:"+Time.time);
print("帧时间:"+Time.deltaTime);
print("现实时间:"+Time.realtimeSinceStartup);
#endregion
}
}