Unity1 - Gamer羽飞

前言

  1. 一定要多练习
  2. 扩展发散
  3. 学完后尝试建立自己的游戏框架

内容

快捷键

场景区

  • 中键: 同Q
  • 右键+wasd: 作为player移动
  • Alt+左键: 转动视角
  • E: 旋转Rotate
  • R: 缩放Scale
  • T: 矩形缩放Rect,只管一个平面矩形的缩放,一般用于2D平面,如UI
  • Y: 全都有

Game Object

  • Sphere平面和Quad矩形的区别
    • Sphere三角面更多, 可以支撑更精确复杂的计算; Quad三角面只有两个
    • Sphere一般没有y, Quad一般没有z
  • 不同GO的本质区别在于不同GO的Mesh Filter组件中Mesh属性的取值不同

坐标系

  • 在C#中通过Transform实例化的对象来访问对象本身的Position,Rotation变量是世界坐标系下的值。
    transform.position; transform.rotation;
  • 若想获取与组件上的本地坐标则应访问transform.localPositiontransform.localRotation
  • 从世界坐标转成相对父对象的局部坐标:
    1
    2
    3
    4
    transform.TransformPoint(transform.localPosition);
    //局部坐标转世界坐标
    transform.parent.InverseTransformPoint(transform.position);
    //世界坐标转局部坐标

游戏资源管理

  • 导入导出包UnityPackageFile: unity自身的一个压缩包
  • fbx: 3D模型文件
  • 默认Material材质不可更改, 更改需要新建一个Material并应用到对应的GO上. 通过GO的MeshRenderer组件中Material组件可以添加各自的Material, 不同的Material通过选定的Shader着色器(默认Standard)渲染到GO上.
  • Window->Package Manager管理在Assets Store下载的资源包

Terrain地形

  1. 添加相邻地形
  • FillHeightmapUsing: 连接地形的方法
    • clamp: 相邻瓦片交叉混合
    • mirror: 镜像
  1. 绘制地形

    Opacity: 不透明度

  • Paint Holes: 镂空画洞
  • Set Height: 设置高度
    • Flatten Tile: 展平当前terrain
    • Flatten All: 展平所有terrain
  • Smooth Height: 平滑高度
    • Blur Direction: 仅向下舍去-1,双向0,仅向上进入1
  • Stamp Terrain: 只能点一下, 不能滑动绘制
  • Paint Texture: 绘制纹理
    • 在Terrain Layer中选择Texture资源

      Tips: 一般不用绘制, 只需要了解

  1. 画树
  • Mass Place Tree: 大量放置树
  1. 绘制细节
  • Add Grass Texture: 给地面添加草
    • 最终强度: 草的密集程度
  1. 地形设置

脚本的生命周期

![Unity官方图解](D:\Program Files\Typora\assets\unity1\f366aa7d27e1514bb579b495f09942bf.png)

  1. Awake:初始化时调用,通常使用为需要提前初始化的逻辑。比如单例赋值private void Awake(){Instance = this;}

  2. OnEnable:在对象启用时调用,处理每次显示时都需要进行初始化的逻辑,通常和OnDisable配合使用。
    比如: 游戏逻辑使用并修改了变量Number,而下次显示时使用是又需要Number = 1,此时就可以写private void Awake(){Number = 1;}

  3. Start:仅当启用脚本实例时,才会在第一帧调用。通常使用为一些变量初始化逻辑。比如:获取指定物体:private void Start(){child1 = transform.GetChild(0);}

  4. Fixed Update:固定时间调用,所有物理计算和更新都在Fixed Update中处理,不受帧率影响。比如:一些物理属性的更新操作Force,Collider,Rigidbody等。

  5. Update:每帧调用一次,根据帧率的快慢影响执行速度。通常的游戏逻辑都写在这里,比如:和玩家交换,当用户按下空格时进行执行什么操作。

  6. LateUpdate:在Update完成后,每帧调用一次。常见用处是相机跟随主角,比如:主角在Update中移动,则可以在LateUpdate执行相机的移动,这将可以保证摄像机跟着的时候之前的逻辑一起完全执行完成。

  7. OnMouseXXX: 通过鼠标的射线检测来判断鼠标当前位置是否碰到了挂载脚本游戏对象的碰撞体。

    • 前提:

      • 只能检测当前脚本挂载的游戏对象。
      • 当前游戏对象需要有碰撞体。
      • 不能有其他物体(UI)遮挡到此游戏对象。
    • 函数:

      • OnMouseEnter: 鼠标进入时调用一次
      • OnMouseOver: 鼠标停留(经过)时一直调用
      • OnMouseExit: 鼠标退出时调用一次
      • OnMouseDown: 鼠标按下时调用一次
      • OnMouseDrag: 鼠标拖拽(按住)时一直调用
      • OnMouseUp: 鼠标抬起时调用一次
    • 应用(一般成对使用):

      • OnMouseEnter,OnMouseOver,OnMouseExit 一组。比如模拟选中状态:鼠标进入时物体变色,鼠标退出时再变回来。
      • OnMouseDown,OnMouseDrag,OnMouseUp 一组。比如射击游戏:鼠标按下拖拽时调整方向,抬起时发射子弹。
      • 当鼠标按下并停留在当前游戏对象上时,OnMouseOver,OnMouseDrag会同时触发。
  8. OnTriggerXX:

    • 函数

      • OnCollisionEnter: 进入碰撞时触发一次。
      • OnCollisionStay: 在碰撞体中停留时每帧触发一次。
      • OnCollisionExit: 离开碰撞体时触发一次。
      • OnTriggerEnter: 进入碰撞体时触发一次。
      • OnTriggerStay: 在碰撞体中停留时每帧触发一次。
      • OnTriggerExit: 离开碰撞体是触发一次。

      还有对应2D碰撞体的六个方法(如:OnCollisionEnter2D) 函数后面添加2D接口,触发条件和使用方式和3D一致。 使用时注意碰撞体和检测函数同步接口,即用2D碰撞体必须用2D函数。

    • 前提同上

  9. OnApplicationXX:

    • 函数:
      • OnApplicationPause: 检测到暂停的帧结束 –> 切换到后台和回来时调用。游戏停止保存数据/游戏继续数据初始化。
      • OnApplicationFocus: 当屏幕 获得/失去 焦点时调用。失去焦点关闭背景音乐/获得焦点继续播放音乐。
      • OnApplicationQuit: 当程序退出时调用。在移动端大退时也会对调用,但不会触发上面两个方法。
  10. 禁用与销毁

    • OnDisable: 当对象被禁用时调用此函数(其父物体被禁用也会触发)。通常和OnEnable配合使用。比如:在OnEnable添加监听,在OnDisable移除监听
    • OnDestroy: 在对象存在的最后一帧的所有帧更新之后调用此函数。当物体销毁或者场景关闭时触发。比如:子弹打到墙壁时,需要销毁子弹并触发一个打击音效。

脚本执行顺序

  • 先执行所有的Awake(), 再执行所有的Start()

  • Execution Order中设置cs脚本执行顺序, 数值越小越先执行

标签和图层

  • 给GO分组的工具
  • 图层可以在Camera组件Culling Mask属性中选择遮罩图层, 实现显隐不同图层的功能

Prefab预制体与变体

  • 以.prefab文件存储的GO, 可以通过GO快速创建别人打包好的GO

  • 在Scene中的GO组件发生改变, 可以通过右键组件应用到Prefab文件的修改

  • 通过预制体创建的GO发生大改变, 将GO独立为新的prefab时, 选择原始预制体将保留对原始预制体的引用, 选择预制体变体将不再保留对原始预制体的引用

  • 通过代码来创建GO就可以考虑使用预制体

    1
    2
    3
    public GameObject sphere; //首先public一个GO变量, 然后在unity面板中拖入特定的预制体
    Instantiate(sphere,transform); //使用Instantiate初始化这个变量, 并将其设置为当前GO的子GO.该函数返回值为go对象
    Destroy(Instantiate(sphere,transform)); //创建并销毁go

Vector3

  • 常用常量

    • Vector3.zero: (0,0,0)

    • Vector3.one: (1,1,1)

  • 函数

    • Vector3.Angle(new Vector3(0,0,0),new Vector3(1,1,1)): 两个向量之间的夹角

    • Vector3.Distance(new Vector3(0,0,0),new Vector3(1,1,1)): 两个坐标之间的距离

    • Vector3.Dot(new Vector3(0,0,0),new Vector3(1,1,1)): 两个向量的乘积(返回==标量==)

      1
      2
      3
      4
      5
      //Dot源码
      public static float Dot(Vector3 lhs, Vector3 rhs)
      {
      return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
      }

      ab=(x1,y1,z1)⋅(x2,y2,z2)=x1×x2+y1×y2+z1×z2=|a|×|bcosθ

      通过取值正负可以判断两向量方向是否相同; 通过取值是否为0可以判断是否垂直

    • Vector3.Cross(new Vector3(0,0,0),new Vector3(1,1,1)): 两个向量的叉乘(返回==Vector3对象==)

      //Cross源码

      1
      2
      3
      4
      public static Vector3 Cross(Vector3 lhs, Vector3 rhs)
      {
      return new Vector3(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x);
      }

      a×b=(a1,a2,a3)×(b1,b2,b3)=(a2×b3−a3×b3,a3×b1−a1×b3,a1×b2−a2×b1))

      |a×b|=|a|×|b|×sinβ

      叉乘的几何意义表示为求得以ab为平面的法线向量c, cab组成的平面, c的模|c|=|a|×|b|×sinβ, 或以ab组成的平行四边形的面积

      若两者叉乘之模为0, 则ab相互平行; 若两者叉乘之模等于两者各自的模的乘积, 则ab相互垂直

    • Vector3.Lerp(new Vector3(0,0,0),new Vector3(1,1,1),0.5f): 两个Vector3之间插值

  • 对象常量(Vector3 v = new Vector3(1,1,1);)

    • v.magnitude: Vector3的模

Euler欧拉角与Quaternion四元数

  • Euler的实例化: 同Vector3

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

  • Quaternion的实例化:

    • 常量(0,0,0,0): Quaternion.identity
    • 欧拉角to四元数: Quaternion quaternion = Quaternion.Euler(new Vector3(0,30,0));
    • 四元数to欧拉角: Vector3 vector3 = quaternion.eulerAngles;

Debug

  • 输出文本Text:
    • 调试输出: Debug.log("Text");
    • 调试输出警告: Debug.logWarning("Text");
    • 调试输出错误: Debug.logError("Text");
  • 画线
    • 画直线: Debug.DrawLine(Vector3.zero,Vector3.one,[Color.Green]); //两个必需参数为两个点坐标
    • 画射线: Debug.DrawRay(Vector3.zero,Vector3.one,[Color.Green]); //第一个参数是起始点坐标, 第二个参数为射线向量

组件属性的修改

  • 获取GO和transform:

    • 获取本GO: GameObject go = this.gameObject; 也可直接使用gameObject代替this.gameObject

      GO的父子关系控制在transform组件中, 上面的this表示的是本GOtransform, 所以上面的this.gameObject也可以写为transform.gameObject

    • 获取其他无关GO:

      • public GameObject go; 然后通过unity面板选择

      • GameObject.Find("name"); 使用GameObject类方法根据name寻找

      • GameObject.FindWithTag("tag"); 使用GameObject类方法根据tag寻找

    • 获取父物体GO:

      1
      2
      3
      Transform parent = transform.parent; // 获取物体的直接父物体
      Transform root = transform.root; // 获取物体的根物体
      int hierarchy = transform.GetSiblingIndex(); // 获取物体在父物体中的层级索引.根物体的层级索引为0,其直接子物体的层级索引依次递增
    • 获取子物体GO:

      • 获取所有层级所有子物体, 包括本物体: GetComponentsInChildren()
      1
      2
      Transform[] myTransforms = GetComponentsInChildren<Transform>();
      foreach (var child in myTransforms){Debug.Log(child.name);}
      • 通过name获取一级子物体: transform.Find("Child0")

        获取二级子物体需要全路径: transform.Find("Child0/Child00")

        ==注意: 对象gameObject没有此方法, transform有此方法, transform对象的方法只能寻找本身及子物体, GameObject类方法是从所有层级所有物体中寻找==

      • 通过index获取一级子物体: transform.GetChild(1)

        获取二级子物体需要连续两次调用: transform.GetChild(1).GetChild(0)

    • GameObject类的实例化需要到unity面板中选择, 在代码中的gameObjecttransform对象的一个属性, 获得的所有父子GO物体均为相应的transform对象

  • GO/transform的属性和函数:

    1
    2
    3
    4
    5
    6
    7
    8
    go.name
    go.tag
    go.layer
    go.activeInHierarchy //是否激活状态在层级中
    go.activeSelf //本身是否激活状态
    //两个同时为真才是激活状态, 只要有一个为假就不是激活状态
    go.AddComponent<BoxCollider>(); //添加组件
    go.SetActive(true); //设置是否激活, 这是go的函数, transform无法管控GO是否激活
  • 获取其他组件: BoxCollider bc = GetComponent<BoxCollider>();或直接使用匿名函数接想用的属性GetComponent<BoxCollider>().xxx

  • 获取父物体的特定组件: GetComponentInParent<BoxCollider>()

  • 获取子物体的特定组件: BoxCollider[] bc = GetComponentInChidren<BoxCollider>(), 会遍历包含本身在内的所有层级所有子物体

Time类

  1. Time类属性

    总时间
    Time.time 帧时间
    Time.unscaledTime 不受Scale约束的帧时间
    Time.fixedTime 频率时间/不受帧约束的时间
    Time.unscaledFixedTime 不受Scale约束的频率时间
    Time.realtimeSinceStartup 不受Scale影响的实际时间
    Time.timeSinceLevelLoad 自最后一个非添加场景(non-additive scene)完成加载以来的Scaled时间
    增量时间
    Time.deltaTime 帧间隔时间/Δ帧时间
    Time.unscaledDeltaTime 不受Scale约束的帧间隔时间
    Time.fixedDeltaTime 频率间隔时间/不受帧约束的时间间隔
    Time.fixedUnscaledDeltaTime 不受Scale约束的频率间隔时间
    其他
    Time.frameCount 总帧数
    Time.timeScale 时间缩放尺度, 默认为1, 为0停止, 为2二倍速
    Time.maximumDeltaTime 最大帧增量时间
    Time.maximumParticleDeltaTime 粒子更新的最大帧增量时间
    • 过于卡顿时, Time.deltaTime会增大, 但不会无限增大, 受Time.maximumDeltaTime限制, 而Time.unscaledDeltaTime不受此限制, 因此Time.time会比Time.unscaledTime慢一些.

Application类

静态变量
Application.persistentDataPath 不同平台持久化的Assets文件夹(读写)
Application.streamingAssetsPath 游戏安装目录Assets目录中streamingAssets文件夹, 无加密(只读)
Application.temporaryCachePath 临时文件夹
Application.runInBackground 是否在后台运行
Application.platform 返回游戏运行平台(只读)
Application.systemLanguage 返回系统语言(只读)
Application.unityVersion 返回unity版本
静态函数
Application.OpenURL("http") 打开URL
Application.Quit 退出游戏

Scene类与SceneManagement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using UnityEngine.SceneManagement //引入namespace使用SceneManager类
SceneManager.LoadScene(1); //在File-BildSettings中引入不同scene获得index, 通过index加载scene
SceneManager.LoadScene("MyScene",[defalt:LoadSceneMode.Single]LoadSceneMode.Addictive); //通过name加载scene
SceneManager.UnloadSceneAsync(s); //卸载scene

Debug.log(SceneManager.sceneCount); //数量

Scene s = SceneManager.GetActiveScene(); //当前活动scene
Scene s = SceneManager.CreateScene("MyScene"); //创建scene

Debug.log(s.name); //名字
Debug.log(s.isLoaded); //是否已加载
Debug.log(s.path); //文件路径
Debug.log(s.buildIndex); //获取index
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//异步加载场景需要用IEnumerator协程:
public class AsyncTest:Monobehavior
{
AsyncOperation o; //实例化一个AsyncOperation对象用以记录加载过程信息

void Start()
{
StartCoroutine(loading()); //使用StartCoroutin()启动协程, 参数为协程函数名
}

IEnumerator loading() //定义协程事件
{
o = SceneManager.LoadSceneAsync("MyScene"/1); //在协程中使用异步加载场景函数, 函数返回值为AsyncOperation类对象
yield return o; //将加载过程的信息写入o中
}

void Update()
{
Debug.log(o.progress); //0-0.9
}
}

Transform类

实例变量
transform.position 世界位置
transform.localPosition 相对位置
transform.rotation 世界旋转四元数
transform.localRotation 相对旋转四元数
transform.eulerAngles 世界旋转欧拉角
transform.localEulerAngles 相对旋转欧拉角
transform.localScale 缩放
transform.forward GO的前后左右上下
实例函数
transform.LookAt(Vector3.zero) 一直看向某一个点(点坐标)
transform.Rotate(Vector3.up) 旋转(方向向量)
transform.Translate(Vector3.forward * 50 * Time.deltaTime) 向(0,0,1)移动(方向向量)

Input类

  1. 按键Key

    静态属性
    Input.anyKey 如果用户按下任何键(包含任意设备任意输入),在按住不放的过程中一直返回true(只读)
    Input.anyKeyDown 按下任何键(包含任意设备任意输入),按下的那一帧返回true(只读),之后的帧即使仍然被按住也返回false
    Input.inputString 按下的键的值(配合anyKey实现自定义按键)
    静态方法
    Input.GetKey(KeyCode) 检测是否按下了任何指定键,一直按住则一直返回 true
    Input.GetKeyDown(KeyCode) 检测是否按下了任何指定键,只有那一帧时true
    Input.GetKeyUp(KeyCode) 释放的那一帧返回true
  2. 按钮Button

    静态方法
    Input.GetButton(string buttonName) 检测是否按下了任何按钮,一直按住则一直返回 true
    Input.GetButtonDown() 检测是否按下了任何button,只有那一帧时true
    Input.GetButtonUp() 释放的那一帧返回true
  3. 鼠标

    静态属性
    Input.mousePresent 是否有mouse设备连接(只读)
    Input.mousePosition 当前鼠标位置(只读), z=0, 左下角是(0,0,0), 右上角是分辨率
    Input.mouseScrollDelta 鼠标滚轮滚动量(只读), 返回Vector2, y逆时针(0,1), 顺时针(0,-1)
    静态方法
    Input.GetMouseButton(int button) 检测是否按下了按钮,一直按住则一直返回 true, 0左键 1右键 2中键
    Input.GetMouseButtonDown() 检测是否按下,只有那一帧时true
    Input.GetMouseButtonUp() 释放的那一帧返回true
  4. 虚拟轴

    • 设置内容在编辑-ProjectSettings
    1
    2
    3
    float h = Input.GetAxis("Horizontal"); //获取水平轴(-1,1)
    float v = Input.GetAxis("Vertical");
    float x = Input.GetAxis("Mouse X"); //获取鼠标横向从移动, 左-1

    Input.GetAxisRaw只返回-1,0,1三个值,没有过渡态, 一般用于2D游戏中

  5. 触摸

    静态属性
    Input.touchCount 返回整数,代表在当前帧所有触摸点数量(只读)
    Input.touches 返回一个 Touch[] 数组(只读),包含了当前帧所有触摸点
    静态方法
    Input.GetTouch(int index) 返回特定Touch
    对象属性
    touch.position
    touch.phase 包含Began, Moved, Stationary, Ended, Canceled五个阶段的属性, 用switch判断
  6. 陀螺仪/重力感应

    • 前提: Input.gyro.enabled = true;
    默认成员属性
    Input.gyro.gravity 重力加速度向量
    Input.gyro.rotateRate 旋转速度
    Input.gyro.attitude 当前的旋转方向的四元数
  7. 设备按钮

    Input.backButtonLeavesApp: 这个值为true时,按下返回按钮会导致应用程序退出,否则,操作系统将处理返回按钮(Android、Windows Phone或Windows平板电脑)

Light组件: 光照

  1. Directional定向光: 图穷远光源, 平行光线
    • Intensity强度: 光照亮度
    • Shadow Type: 无阴影, 有锯齿阴影, 模糊边缘阴影
    • Realtime Shadows: 实时阴影
      • Strength: 阴影强度
      • Resolution: 阴影质量
    • Draw Halo: 在GO处显示光晕
    • Flare: 炫光
    • Culling Mask: 光照遮罩, 剔除不需要灯光的GO(如UI)
  2. Spot聚光: 手电筒
  3. Point点光源: 灯泡球体光
  4. Area面光源(性能消耗过高, 仅支持烘焙模式)

Camera

  • Projection投影:

    • Perspective透视: 近大远小
    • Orthographic正交: 完全平面, 一般用于2D
  • Depth: 相机显示顺序, 数值大的优先显示

  • Clear Flags清除标志:

    • SkyBox天空盒: 可以添加SkyBox组件更改天空

    • Solid Color

    • Don’t Clear

    • Depth Only: 仅显示有深度GO, 拍不到的空间不显示

      如果有多个相机, 将深度高的相机设置为DepthOnly, 可以显示高深相机的内容和低深相机的内容&背景

  • FOV Axis: 用于设置Field of View视野的大小

  • Clipping Planes剪裁平面: 只有在近面和远面之间的空间才能被捕捉到

  • Viewpoint Rect显示矩形: 拍摄到的内容在屏幕中的位置(x,y)和宽高(w,h), 位置默认左下角(0,0), 宽高是百分比小数

音频: AudioSource组件

  • 前提: 有且只有一个GO添加了AudioListener组件用以监听
  • 需要播放声音的GO中添加AudioSource组件
  • 音频文件一般分为两类: 音乐和音效
  • AudioSource组件:
    • AudioClip: 引入音频资源文件
    • Mute: 静音
    • Pitch: 音调
    • 3D Sound Settings - Volume Rolloff: 音量衰减
  • 对象属性和函数:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    AudioSource a = GetComponent<AudioSource>();

    //属性:
    Debug.log(a.isPlaying);
    a.loop = true;
    a.volume = 0.5f;

    //音乐函数:
    a.Play();
    a.Pause();
    a.UnPause();
    a.stop();

    //音效函数:
    a.PlayOneShot(AudioClip audioclip); //一个AudioSource只能播放一个音乐,但可以播放多个音效

视频: VideoPlayer组件

  • 使用VideoClip作为资源文件变量
  • VideoPlayer组件:
    • Renderer Mode渲染模式: 选择挂载体
    • 属性和函数参考AudioSource

角色控制: CharacterController组件

  • SimpleMove: 自带重力效果, y轴速度为0, 角色接触地面返回true
  • Move: 绝对控制, 没有重力效果, 影响位移的只有xyz的速度和**Rigidbody的碰撞**, 返回CollisionFlags对象

重力: Rigidbody组件

  • automatic tensor: 自动张量, 计算张量旋转行为
  • automatic center of mass: 自动重心计算
  • interpolate: 物体运动插帧, 一般在物理帧率低于app帧率时使用, 默认关闭

    Interpolate:使用前两次物理更新计算当前帧, 会稍滞后于它应该在的位置, 适用于刚体速度变化较大的情况或有其他影响刚体运动的物理元素

    Extrapolate:使用上一次物理更新并预测下一次物理更新以计算当前帧, 会稍超前于它应该在的位置。外推通常不太准确,并且可能在可见的范围内超出碰撞边界(然后在下一帧中进行修正)。外推通常只适用于精度不重要的情况,例如刚体以恒定速度移动,并且没有其他影响刚体运动的物理元素

    启用时Unity会忽略任何不是来自物理系统的变换更改, 对transform进行任何直接(非物理)更改后使用Physics.SyncTransforms调用

  • Collision Detection: 碰撞检测频率
    • Discrete: 离散检测(默认,多数情况够用)
    • Continues: 连续
    • Continues Dynamic: 连续动态检测, 性能消耗最高
    • Continues Speculative: 处于Continues和Discrete之间
  • Constraints: 冻结某一方面的transform

碰撞: Collider组件

  • 碰撞的条件: 两者都有Collider组件 & 至少一个GO有Rigidbody组件
  • 碰撞方法:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    private void OnCollisionEnter(Collision collision){
    //collision.colider: 与之碰撞的物体的collider
    //collision.gameObject: 与之碰撞的GO对象
    }
    private void OnCollisionStay(Collision collision){}
    private void OnCollisionExit(Collision collision){}

    private void OnTriggerEnter(Collider other){
    //other就是触发的collider
    }
    private void OnTriggerStay(Collider other){}
    private void OnTriggerExit(Collider other){}
  • Material: 使用Physical Material文件, 创建Friction摩擦力
    • Bounciness: 弹力, 1没有能量损失
    • Xx Combine: 两个摩擦GO时如何计算

铰链关节,弹簧关节和固定关节: Hinge Joint,Spring JonitFixed Joint组件

  • Anchor: 轴原点
  • Axis: 轴向量

射线检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Update(){
if(Input.GetMouseButtonDown(0)){
//从Camera发射一个射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// 声明一个RaycastHit对象接受hit结果
RaycastHit hit;
//使用Physics.Raycast函数发射ray, 并将发射结果保存到引用参数hit中
if(Physics.Raycast(ray,out hit)){
//打印在3Dunity中与射线相撞的第一个rigidbody的撞击坐标
Debug.log(hit.point);
}

//如果检测多个rigidbody相撞目标,需要实例化RaycastHit[]数组接收, 使用Physics.RaycastAll(Ray ray)多次检测
RaycastHit[] hit = Physics.RaycastAll(ray,[int 检测距离],[int 检测图层],[...]);
}
}

粒子系统: Partical System组件

  • Prewarm: 从stop开始时, 是否从0逐渐展开
  • Start Lifetime: 粒子在空中的存在时间
  • 3D Start Size/Rotation: 开启后转换为3D粒子;默认为面向Camera的平面粒子
  • Flip Rotation: 水平翻转旋转
  • Gravity Modifier: 粒子重力效果
    • Constant: 固定值,[-1上重力,1下重力]
    • Curve: 受力曲线
  • Simulation Space: 生成的粒子是否随GO移动而移动;Local随,World不随,Custom绑定其他GO

线段和拖尾: LineRendererTrailRenderer组件

旧动画: Animation组件

  • Culling Typ: 是否一直播放动画
  • 动画窗体: ctrl+6
  • 使用类似AudioSource: Play(),animation clip

新动画: Animator组件

  • Controller: 由AnimatorController.controller资源文件控制
  • Culling Mode: Cull Update Transforms表示不在镜头时暂停渲染, Cull Completely表示不在镜头时完全停止
  • 在Window-Animation中创建不同的动画资源.anim文件, 在Window-Animator中作为不同的动画状态State进行管理
  • .controller文件包含了三方面内容:
    • .anim文件的引用
    • .anim文件的设置
    • .anim文件之间的相互连接关系

动画的构成: anim文件

  • Rig - Animation Type: 动画类型
    • 无: 不包含动画
    • Legacy旧版: 只能用Animation旧版动画组件
    • Generic泛型: 新版动画, 各种非人动画
    • Humanoid人型: 新版动画, 用于人
  • Rig - Avatar骨骼: 从模型或从其他地方
  • Animation: 对动画Clip进行细操
    • Loop Match: 首位帧是否相似
    • Bake Into Pose: 烘焙特定方向的位移, 避免在动画过程中发生位移
    • Curves曲线: 随动画播放时间的函数曲线, 其值同步在animator的同名parameters
    • Events事件: 在动画的某一帧调用函数(如脚步踏地时发出脚步声)
  • Blend Tree in AnimatorWindowContext: 混合动画(如走和跑的混合)
    • Blend Type混合模式: 由几个变量控制混合动画的计算, 变量在animator的同名parameters
    • Motion: 选择混合的动画
    • Automate Thresholds: 是否默认各个Motion的取值范围
  • Sub-State Machine in AnimatorWindowContext子状态机: 不同的动画状态的分组归类
    • 如拿枪到一个子状态中, 换刀到另一个子状态中
  • Base Layer: 动画状态图层
    • Weight:权重; Mask: Avatar骨骼遮罩; IK: 反向动力学效果;
    • 不使用Mask可以通过控制 Weight获得同Blend Tree一样的效果, 使用Mask可以精确实现不同部位动画的混合

导航系统(需要在PackageManagement中安装AI Navigation组件)

1.静态障碍物

  • 首先将道路GO勾选为Navigation Static, 然后在选择Window - AI - Navigation设置烘焙; 接着将PlayerGO添加NavMeshAgent组件
  • Bake: 烘焙Agent的半径, 高度, 可上最大坡度Slope, 台阶每一阶步高, 可掉落的高度, 可跳跃的距离. (可以添加多个Agent, 作为高矮胖瘦不同的人)
  • 掉落高度跳跃距离是通过生成OffMeshLinks实现, 需要勾选需要生成links的障碍物GO的Object - Generate OffMeshLinks
  • Area: 不同区域的成本消耗设置, 在Object - Navigation Area中更改
  • Nav Mesh Agent组件:
    • Steering: 位移相关
      • Acceleration: 加速度
    • Obstacle Avoidance - Priority: 一个路口多个Agent待通过时的优先级
    • Area Mask区域遮罩: 特定区域永远不可通过, 用于针对不同Agent设定不同的禁止区域
  • 代码实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //前面获取代理组件
    using UnityEngine.AI;
    NavMeshAgent agent = GetComponent<NavMeshAgent>();

    //在Update方法中逐帧更新:
    if(GetMouseButtonDown(0)){
    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    RaycastHit hit;
    if(Physics.Raycast(ray, out hit)) //从屏幕点击到3D位置坐标
    {
    agent.SetDestination(new Vector3(hit.point)); //将坐标设为destination
    }
    }

2.动态障碍物

  • 将特定的某些GO取消勾选Navigation Static, 并添加NavMeshObstacle组件
    • Carve切割: 勾选后会根据该GO的位移重新烘焙原有的静态障碍道路
      • Move Threshold移动阈值: 最小移动多远时开始rebake
      • Time to Stationary静止时间: 移动阈值后经过多少秒开始rebake
      • Carve Only Stationary仅在静止时切割: 取消后会随着位移即时rebake, 性能消耗较大

3.点对点定点传送: Off Mesh Link组件

  • Auto Update Position: 当GO位置改变时, 即时更新Link; 如果位置不会改变就取消,以降低能耗

UI

  • UICanvasEventSystem两个GO组成, Canvas为所有UI控件GO的父物体
  • Canvas组件:
    • Render Mode:
      • OverLay: 永远在最上层
      • Camera: 可被其他GO覆盖
      • World Space: 在3D世界中的一层平面, 可旋转
    • Sort Order: 多个Canvas时的渲染优先级
  • Image组件:
    Raycast Target: 是否接收射线投射
    Anchors: 缩放参照锚点
    Pivot: 图片的轴心, 图片的旋转缩放坐标都是由轴心控制
  • 字体: 新版更清晰, 富文本更多
    • Color Gradient: 颜色渐变