Unity Study

组件

组件生命周期

生命周期

脚本执行顺序

生命周期函数执行顺序,所有脚本的 Awake =》 所有脚本的 OnEnable =》 所有脚本的 Start。。。 脚本执行顺序权重

物体打标记

标记

物体打标记 物体打标机效果

标签

  • 方便查找游戏物体
  • 可以通过标签判断物体类型 物体标签

图层

图层最多 32 个,有序号索引 图层 相机可选择拍摄图层,碰撞也可以根据图层选择 相机可选择拍摄图层

向量

单位化、归一化

把向量转化为单位向量

运算

加法

。。。

减法

x1-x2, y1-y2

点乘

可计算夹角

  • x1x2 + y1y2 = cos& _ |a| _ |b|

模不影响角度,可以用单位向量计算

  • x1x2 + y1y2 = cos& _ |a| _ |b| = n = cos& * 1

预制体

拖拽生产预制体,预制体变体

Vector3

计算夹角

Vector3.Angle(v, v2);

两点间距离

Vector3.Distance(v, v2);

点乘

Vector3.Dot(v, v2);

叉乘

Vector3.Cross(v, v2);

插值,比例计算

Vector3.Lerp(Vector3.zero, Vector3.one, 0.5f);

  • 在两个向量之间进行比例计算,0 向量和 1 向量的 0.5(0.5, 0.5, 0.5);

向量属性

  • v.magnitude

规范化向量

  • v.normalized

旋转

欧拉角(0-360)

  • Vector3 rotate = new Vector3(0, 30, 0);

四元数转欧拉角

  • rotate = quaternion.eulerAngles;

四元数

四维空间的高阶复数,效率更高,而且不会造成万向节死锁

  • Quaternion quaternion = new Quaternion(x, y, z, w);

无旋转的四元数

  • Quaternion quaternion = Quaternion.identity;

欧拉角转换为四元数

  • Quaternion quaternion = Quaternion.Euler(rotate);

看向一个物体

  • Quaternion quaternion = Quaternion.LookRotation(new Vector3(0,0,0));

Debug

log

  • Debug.Log
  • Debug.LogWarning
  • Debug.LogError

绘制直线

绘制直线 只有开发人员能看到

  • Debug.DrawLine(Vector3.zero, Vector3.one, Color.blue);

绘制射线

  • Debug.DrawRay(Vector3.zero, Vector3.up, Color.red);

游戏物体类

当前脚本所挂在的游戏物体

  • this.gameObject / gameObject

常用属性

名称

  • name

标签,如 player

  • tag

图层,会拿到索引

  • layer

激活状态

  • gameObject.SetActive(false);
  • activeInHierarchy (当前真正的激活状态,会被祖先元素影响)
  • activeSelf (当前自己的激活状态,不一定够是实际的)

获取 Transform 组件

  • this.transform / transform

获取其他组件

  • BoxCollider bc = GetComponent< BoxCollider>();

获取当前物体子物体身上的某个组件

  • GetComponentInChildren< >();

获取父物体身上的组件

  • GetComponentInParent< >();

添加组件

  • gameObject.AddComponent< AudioSource>();

通过游戏物体名称获取游戏物体

  • GameObject test = GameObject.Find("Test");
  • GameObject[] test = GameObject.FindObjects("Test");

通过游戏标签获取

  • GameObject test = GameObject.FindWithTag("Player");
  • GameObject[] test = GameObject.FindObjectsWithTag("Player");

通过预设体实例化游戏物体

  • GameObject go = Instantiate(Prefab);
  • Instantiate(Prefab, transform); // 实例化并设为子物体

销毁

  • Destroy(go);

游戏时间 Time

游戏开始到现在的时间

  • Time.time

时间缩放,默认一倍,可用与加速减速

  • Time.timeScale

固定时间间隔

  • Time.fixedDeltaTime

上一帧到这一帧所用的游戏时间

  • Time.deltaTime

文件路径 application

游戏文件路径(Assets 文件),只读,打包后加密压缩

  • Application.dataPath

持久化游戏路径,可写,可用于存储数据

  • Application.persistentDataPath

StreamingAssets 只读,打包后不压缩,需要自己手动创建

  • Application.streamingAssetsPath

临时文件

  • Application.temporaryCachePath

控制是否在后台运行 (生成设置-玩家设置 中也有)

  • Application.runInBackground

打开 url 到浏览器

  • Application.OpenURL("");

退出游戏

  • Application.Quit();

场景

c

场景类

SceneManager.LoadScene(1)通过索引或名称同步加载场景并跳转,需要引入命名空间

using UnityEngine.SceneManagement;
void Start()
{
  SceneManager.LoadScene(1);
}

获取当前场景

  • Scene scene = SceneManager.GetActiveScene();

名称

  • scene.name

是否加载完成

  • scene.isLoaded

场景所在路径

  • scene.path

场景索引

  • scene.buildIndex

获取场景的所有游戏物体

  • GameObject[] gos = scene.GetRootGameObjects();

场景管理类

using UnityEngine.SceneManagement;

已经加载的场景数量

  • SceneManager.sceneCount

创建新场景

  • Scene newScene = SceneManager.CreateScene("newScene");

卸载场景, 异步

  • SceneManager.UnloadSceneAsync(newScene);

加载场景

  • SceneManager.LoadScene("MyScene", LoadSceneModal.Single); 加载后替换
  • SceneManager.LoadScene("MyScene", LoadSceneModal.Additive); 以叠加的方式加载场景

异步加载场景并获取进度

  • SceneManager.Load("MyScene", LoadSceneModal.Additive); 以叠加的方式加载场景

以协程方法来异步加载场景

AsyncOperation operation;
IEnumerator LoadScene(){
  operation = SceneManager.LoadSceneAsync(1);
  yield return operation;
}

获取进度,进度最大为 0.9

  • operation.progress

加载完场景后不自动跳转

  • operation.allowSceneActivation = false;

Transform

相对于世界、相对于父物体

  • position/localPosition
  • rotation/localRotation
  • eulerAngles/localEulerAngles
  • localScale

向量(轴方向)

  • forward
  • right
  • up

操作

看向

  • LookAt(Vector3)

旋转

  • transform.Rotate(Vector3.up, 1);

绕某个物体旋转, 绕(0,0,0)点的 up 轴,以速度 5 旋转

  • transform.RotateAround(Vector3.zero, Vector3.up, 5);

移动

  • transform.Translate(Vector3.forward * 0.1f);

父子关系

获取父物体

  • transform.parent.gameObject;

子物体个数

  • transform.childCount;

解除父子关系

  • transform.DetachChildren();

获取子物体

  • Transform trans = transform.Find("child");
  • trans = transform.GetChild(0);

判断是否为子物体

  • bool res = trans.isChildOf(transform);

设置为父物体

  • trans.SetParent(transform);

键盘鼠标操作

鼠标

鼠标点击

按下鼠标 0 左键 1 右键 2 滚轮

  • if (Input.GetMouseButtonDown(0))

持续按下鼠标

  • if (Input.GetMouseDown(0))

抬起鼠标

  • if (Input.GetMouseButtonUp(0))

键盘

按下键盘按键

  • if (Input.GetKeyDown(KeyCode.A))
  • if (Input.GetKeyDown("a"))

持续按下键盘

  • if (Input.GetKey(KeyCode.A))

键盘抬起

  • if (Input.GetKeyUp(KeyCode.A))

虚拟轴、虚拟按键

虚拟轴介绍 虚拟轴 虚拟轴设置 虚拟轴设置

使用

获取水平轴

  • float horizontal = Input.GetAxis("Horizontal");

获取竖直轴

  • float vertical = Input.GetAxis("Vertical");

虚拟按键,相当于允许游戏自定义按键,如跨平台

  • if (Input.GetButtonDown("Jump"))

触摸操作

开启多点触摸

  • Input.multiTouchEnabled = true;

判断单点触摸

if (Input.touchCount == 1)

触摸对象

  • Touch touch = Input.touches[0];

触摸位置

  • touch.position

触摸阶段

switch(touch.phase){
  case TouchPhase.Began:
    break;
  case TouchPhase.Moved:
    break;
  // 静止
  case TouchPhase.Stationary:
    break;
  // 结束
  case TouchPhase.Ended:
    break;
  // 因为其他事件打断被取消了
  case TouchPhase.Canceled:
    break;
}

多点触摸

if (Input.touchCount == 2)

Touch touch2 = Input.touches[1];

角色控制

为物体添加 CharacterController 组件,再创建一个控制组件

    private CharacterController player;
    // Start is called before the first frame update
    void Start()
    {
        player = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector3 dir = new Vector3(horizontal, 0, vertical);

        //Debug.DrawLine(Vector3.zero, dir, Color.blue);
        player.SimpleMove(dir * 10);
    }

物理系统

重力

碰撞检测 collider

监听发生碰撞

  • private void OnCollisionEnter(Collision collision)

持续发生碰撞

  • private void OnCollisionStay(Collision collision)

结束碰撞

  • private void OnCollisionExit(Collision collision)

Collision collision -碰撞到的物体信息

  • collision.gameObject.name

触发

监听发生碰撞

  • private void OnTriggerEnter(Collider other)

持续发生碰撞

  • private void OnTriggerStay(Collider other)

结束碰撞

  • private void OnTriggerExit(Collider other)

铰链 弹簧

Higne Joint

Spring Joint

Fixed Joint

物理材质

创建物理材质,添加到 Collider 上

射线检测

创建射线

  • Ray ray = new Ray(Vector3.zero, Vector3.up);

从摄像机获取射线

  • Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

声明一个碰撞信息类

  • RaycastHit hit;

碰撞检测

  • bool res = Physics.Raycast(ray, out hit);
  • if res == true

碰撞到的位置

  • Debug.Log(hit.Point)

多检测

  • RaycastHit[] hits = Physics.RaycastAll(ray, 100);
  • RaycastHit[] hits = Physics.RaycastAll(ray, 100, 1 < < 10);

粒子系统

创建粒子系统,使用贴图,调整参数

画线、拖尾

Line Renderer

线的位置不在 transform 里,在 LineRenderer 里

设置线段位置

LineRenderer lineRenderer = GetComponent<LineRenderer>();
lineRenderer.position = 3;
lineRenderer.SetPosition(0, Vector3.zero);

lineRenderer.SetPositions(...);

还可以修改:颜色、宽度

Trail Renderer

拖尾效果 拖尾效果

Animation(46)

老版 Animation

GetComponent< Animation>.play("name");

新版 Animator

创建动画器控制器,并拖拽到 Animator 组件里

触发

触发触发器,如果想立刻触发,有退出时间取消勾选

  • GetComponent< Animator>().SetTrigger("pickup");

角色移动动画控制

    private Animator animator;
    // Start is called before the first frame update
    void Start()
    {
        animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector3 dir = new Vector3(horizontal, 0, vertical);

        if (dir != Vector3.zero)
        {
            transform.rotation = Quaternion.LookRotation(dir);
            animator.SetBool("isWalk", true);
            transform.Translate(Vector3.forward * Time.deltaTime);

        } else
        {
            animator.SetBool("isWalk",false);
        }
    }

动画 检查器

Rig - 动画类型
Animation - 剪辑
  • 循环时间
  • 循环匹配
  • 旋转/位置烘培(是否不转/移动)
Animation - 曲线

随动画进度获取一个曲线的值,可用于根据动画进度设置火焰大小等

Animation - 事件

在关键帧设置事件,在组件中实现事件函数,可达成如左右脚落地触发音效等

混合动画 动画混合树

可实现动画的混合,如按比例混合 walk 和 run

动画图层

在一个图层里

  • Any State
  • Entry
  • 子状态机
  • 上一层状态机
  • Exit

多图层

  • 权重 0-1
  • 遮罩
    • 创建一个 Avatar 遮罩,将操控的设为绿色,将遮罩拖如动画器图层的遮罩

反向动力学

动画器中对应层的 IK 要勾上

private void OnAnimatorIk(int layerIndex) {
  // 设置头部IK
  animator.SetLookAtWeight(1);
  animator.SetLookAtPosition(target.position);

  // 设置右手IK权重
  animator.SetIkPositionWeight(AvatarIkGoal.LeftHand, 1);
  // 旋转
  animator.SetIkRotationWeight(AvatarIkGoal.LeftHand, 1);
  // 设置右手IK
  animator.SetIKPosition(AvatarIKGoal.LeftHand, target.position);
  animator.SetIKRotation(AvatarIKGoal.LeftHand, target.rotation);
}

导航组件 寻路

生成导航地形网格

地形设为静态导航

窗口-AI-导航

  • 烘培

为 player 导航

为 player 添加导航代理组件(Nav Mesh Agent)

using UnityEngine.AI;

private NavMeshAgent agent;

agent = GetComponent<NavMeshAgent>();

// 鼠标点击获取位置并寻路
if (Input.GetMouseButtonDown(0)){
  Ray ray = Camera.main.ScreenPointToRay(Input.mouseposition);
  RaycastHit hit;
  if (Physics.Raycast(ray, out hit){
    Vector3 point = hit.point;
    // 设置该点为导航目标点
    agent.SetDestination(point);
  }
}

网格链接与动态障碍物

导航网格障碍物组件(Nav Mesh Obstacle),可动态切割导航网格

导航-烘培-生成分离网格链接,导航-对象 里要勾上

链接两个点,可以来回传送

随便选中两个点中的一个,添加Off Mesh Link组件, 添加起始和结束物体

区域遮罩

Nav Mesh Agent 区域遮罩部分,该 player 不能访问

区域类型、区域花费

UI

必须要先创建 canvas 画布,所有的 ui 内容都是绘制在 canvas 画布上的,所有的 ui 都需要是 canvas 的子物体

渲染模式

  • 屏幕空间 - 覆盖 : 永远在场景上面
  • 屏幕空间 - 摄像机 : 永远在摄像机里
  • 世界空间

事件系统 EventSystem

图片

锚点

面板

遮罩

文本

适配 content size fitter

按钮

布局

Vertical Layout Group

Horizontal Layout Group

Grid Layout Group

右侧菜单栏