【Unity1】Unity入门笔记

目录

生命周期函数

Inspector窗口可编辑的变量

MonoBehavior中的重要内容

GameObject知识点

成员变量

静态方法

创建对象

查找对象

通过名字查找单个对象

通过Tag来查找单个对象

通过Tag查找多个对象

找到场景中挂载某个脚本

实例化对象(克隆对象)的方法

删除对象的方法

过场景不移除

成员方法

创建空物体

为对象添加脚本

标签比较

设置失活/激活

次要的成员方法

时间相关_Time

时间缩放比

帧间隔时间

受scale影响

不受scale影响

游戏开始到现在的时间

受scale影响

不受scale影响

物理帧时间间隔

受scale影响

不受scale影响

帧数

Transform

Vector3基础和Transform位置

申明变量

基本运算

常用

位置

绝对位置

相对位置

对象当前的朝向

Transform位移

自己计算移动

API移动

Transform角度和旋转

角度相关

旋转相关

Transform缩放和看向

缩放

看向

Transform父子关系

获取和设置父对象

抛妻弃子

获取子对象

子对象操作

Transform坐标转换

世界坐标转本地坐标

本地坐标转世界坐标

Input鼠标键盘输入

鼠标在屏幕的位置

检测鼠标输入

检测键盘输入

检测默认轴输入

Input触摸手柄陀螺仪

检测任意键盘按键

手柄输入相关

触摸、陀螺仪相关

屏幕相关Screen

Camera可编辑参数说明

Clear Flags

Culling Mask

Projection

perspective透视模式(近大远小,一般用于3D游戏)

orthographic 正交摄像机(一般用于2D游戏制作)

Clipping Planes

Depth

Redering path

Occlusion Culling

Viewport Rect

Rendering path

只做了解

Camera代码相关

光源系统基础

光源组件

Type光源类型

Color光源颜色

Mode光源模式

Intensity光源亮度

Shadow Type

Draw Halo

Flare

Culling Mask

Indirect Multiplier

RealtimeShadows

Cookie Size

光面板相关

环境相关设置

其他设置

碰撞检测

刚体

碰撞器

种类:

共同参数:

常用碰撞器:

异形物体使用多种碰撞器组合

不常用的碰撞器

物理材质

创建物理材质

物理材质参数

碰撞检测函数

物理碰撞检测响应函数

触发器检测响应函数

明确何时响应函数

碰撞和触发器函数都可以写成虚函数,在子类中重写逻辑

刚体加力

刚体自带添加力的方法

力的几种模式

力场脚本

刚体的休眠

音效系统

音频文件导入

音频源和音频监听脚本

代码控制音频源

代码控制播放停止

检测音效是否播放完毕

动态控制音效播放

麦克风输入相关

获取设备麦克风信息

开始录制

结束录制

获取音频数据用于存储或传输


生命周期函数

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson1 : MonoBehaviour
{
//当前类对象被创建时才会调用
//类似构造函数 创建时进行一些初始化操作
void Awake()
{
print("Awake");
}
//当对象被激活时调用
void OnEnable()
{
print("Onenable");
}
//用于初始化信息 但比Awake要晚一点
//在对象进行第一次帧更新之前执行
void Start()
{
print("Start");
}
//它主要是用于进行物理更新
//它的时间间隔是可在project setting中的 Time里去设置的
void FixedUpdate()
{
print("FixedUpdate");
}
//处理游戏核心逻辑性更新的函数,每次循环执行一次
void Update()
{
print("Update");
}
//一般用来更新摄像机位置
//update和Lateupdate之间 Unity进了一些处理处理动画相关的更新
void LateUpdate()
{
print("LateUpdate");
}
//对象失活时调用
void OnDisable()
{
print("Ondisable");
}
//对象被删除时调用
void OnDestroy()
{
print("OnDestroy");
}
}

Inspector窗口可编辑的变量

1.私有和保护类无法显示编辑

2.可以使私有和保护类在窗口中显示编辑,要加上强制序列化字段:

    [SerializeField]
    private int i1;

3.公共类可以显示编辑

4.公共类也可以使其不能在窗口中显示编辑,要加上隐藏字段:

    [HideInInspector]
    public string s;

5.大部分类型都能显示编辑:

using System.Collections;
using System.Collections.Generic;
using System.Data.SqlTypes;
using UnityEngine;

public enum E_TestEnum
{
Normal,
Player,
}
public struct MyStruct
{
public int x;
public int y;
}
public class MyClass
{
public int age;
public string name;
}
public class Lesson2 : MonoBehaviour
{

//可以被显示
public int[] array;
public List<int> list;
public E_TestEnum type;
public GameObject gameObj;

//不能被显示
public Dictionary<int, string> dic;//字典
public MyStruct myStruct;//自定义类型
public MyClass myClass;

}

6.使自定义类型能够显示编辑,在类定义之前加上[System.Serializable]:

[System.Serializable]
public struct MyStruct
{
    public int x;
    public int y;
}

7.其它补充:

using System.Collections;
using System.Collections.Generic;
using System.Data.SqlTypes;
using UnityEngine;

public class Lesson2 : MonoBehaviour
{
//文字标签分组
[Header("基础属性")]
public int age=10;
public string name;
[Header("战斗属性")]
public int atk;
public int def;
//悬停注释
[Tooltip("闪避")]
public int miss;
//间隔
[Space()]
public int crit;
//显示滑条范围
[Range(0,10)]
public float luck;
//多行显示字符串,默认为三行
[Multiline()]
public string s1;
[TextArea(3,4)]
public string s2;
//添加快捷方法,第一个参数为按钮名,第二个为方法名(不能带参数)
[ContextMenuItem("重置","Test")]
public int Money;
private void Test()
{
Money = 1;
}
//为方法添加特性,使其能在Inspector中执行
[ContextMenu("测试")]
private void testFun()
{
print("测试成功");
}

}

注意:

1. Inspector窗口中的变量关联的就是对象的成员变量,运行时改变他们就是在改变成员变量

2.脚本部署完毕后,再改变脚本中变量的默认值,窗口中的值也不会改变,可以先移除脚本在拖拽上去

3.如果需要使用运行中的值可以先copy再paste

MonoBehavior中的重要内容

using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Lesson3 : MonoBehaviour
{

void Start()
{
    //1.获取依附的Gameobject
    print(this.gameObject.name);//this可省略,可直接用gameObject获取
    //2.获取依附的Gameobject的位置信息
    //得到对象位置信息
    print(this.transform.position);//位置
    print(this.transform.eulerAngles);//角度
    print(this.transform.lossyScale);//缩放大小
    //this.gameObject.transform 与 this.transform相同,故使用后者,this也可省
    
    //控制脚本是否激活:
    this.enabled = true;
    this.enabled = false;
    //得到依附对象上挂载的其它脚本
    public Lesson2 Other;
    print(Other.gameObject.name);
    
    //1.得到自己挂载的单个脚本
    //根据脚本名获取,若没有对应脚本则获取失败返回空值
    Lesson3_Test t = this.GetComponent("Lesson3_Test") as Lesson3_Test;//父类装到子类需转换类型
    print(t);
    //根据Type获取
    t = this.GetComponent(typeof(Lesson3_Test)) as Lesson3_Test;
    print(t);
    //根据泛型获取 建议使用泛型获取 因为不用二次转换
    t = this.GetComponent<Lesson3_Test>();
    print(t);
    //2.得到自己挂载的同种类型的多个脚本
    Lesson3[] arr = this.GetComponents<Lesson3>();
    List<Lesson3> l = new List<Lesson3>();
    this.GetComponents<Lesson3>(l);
    //3.得到子对象挂载的脚本,它默认也会找自己身上是否有挂载了该脚本
    t = this.GetComponentInChildren<Lesson3_Test>();//圆弧括号内的参数为true/false,若为true则子对象失活也能查找到该脚本,默认为false

    //得子对象 挂载脚本 多个
    Lesson3_Test[] lts = this.GetComponentsInChildren<Lesson3_Test>(true);
    print(lts.Length);
    List < Lesson3_Test > list2 = new List<Lesson3_Test>(); this.GetComponentsInChildren<Lesson3_Test>(true, list2);
    print(list2.Count);
    //4.得到父对象挂载的脚本(它默认也会找自己身上是否挂载该脚本)
    t = this.GetComponentInParent<Lesson3_Test>();
    print(t);
    lts = this.GetComponentsInParent < Lesson3_Test > (); print(lts.Length);
    //5.尝试获取脚本
    if(this.TryGetComponent<Lesson3_Test>(out t))
    {
        //相关处理
    }
    
}

}

GameObject知识点

成员变量

//名字
print(this.gameObject.name);
this.gameObject.name = "改名";
print(this.gameObject.name);
//是否激活
print(this.gameObject.activeSelf);
//是否为静态
print(this.gameObject.isStatic);
//层级(int类型)
print(this.gameObject.layer);
//标签(string类型)
print(this.gameObject.tag);
//transform
print(this.gameObject.transform);//GameObject中也有transform
//但Mono中也有所以与this.transform效果相同

静态方法

创建对象

可以通过GameObject.CreatePrimitive方法创建已有几何体,并且可对其内容进行修改:

GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
obj.name = "创建的立方体";

查找对象

通过名字查找单个对象

使用GameObject.Find()方法,但是效率低下,会遍历场景中所有对象

GameObject obj2 = GameObject.Find("创建");
if (obj2 != null)
{
    print("未找到对应对象");
}
else
{
    print(obj2.name);
}
通过Tag来查找单个对象

使用GameObject.FindGameObjectsWithTag("Tagname")或者GameObject.FindWithTag("Tagname")来查找,二者相同

GameObject obj3 = GameObject.FindWithTag("Player");
if (obj3 != null)
{
    print("根据tag找到的对象" + obj3.name);
}
else
{
    print("根据tag未找到对象");
}

以上两种查找方式都找不到失活的对象,而且若查找到多个符合条件的对象无法确定返回的是哪一个

通过Tag查找多个对象

使用GameObject.FindGameObjectsWithTag("Tagname"),也找不到失活的对象

GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
print(objs.Length);
找到场景中挂载某个脚本

使用GameObject.FindObjectOfType<>(),效率更加低下,遍历场景中的对象还要遍历对象上的所有脚本。

Lesson4  o  = GameObject.FindObjectOfType<Lesson4>();
print(o.gameObject.name);

实例化对象(克隆对象)的方法

作用是根据已有的GameObject对象,创建出一个与之一样的对象。

一种是克隆场景上已有的对象,另一种是克隆预设体,将对象或者预设体拖拽过去即可。

使用GameObject.Instantiate()函数,该函数属于Object类中,故如果继承了MonoBehavior类使用时可以不加上GameObject直接使用

GameObject obj5 = GameObject.Instantiate(pre);

删除对象的方法

使用GameObject.Destroy("要删除的对象名称",延迟删除时间)方法,该函数也是在Object类中,如果继承了MonoBehavior类也可以直接使用。

GameObject.Destroy(obj5,5);

Destroy还可以删除指定的脚本对象。

Destroy(this);

注意:这个Destroy方法 不会马上移除对象 只是给这个对象加了一个移除标识

般情况下 它会在下一帧时把这个对象移除并从内存中移除

若想立即删除可以使用GameObject.DestroyImmediate()函数,如果没有特殊需求就不需要使用这个方法,由于Destroy方法是异步的可以减少游戏的卡顿

过场景不移除

默认情况下,切换场景时,场景上的所有对象都会被自动删除,若希望某个对象在过场景时不被删除,使用GameObject.DontDestroyOnLoad();

GameObject.DontDestroyOnLoad(this.gameObject);
//当前脚本所依附的对象过场景不删除

成员方法

创建空物体

new一个GameObject就是在创建一个空物体

GameObject obj6 = new GameObject();
GameObject obj7 = new GameObject("创建的空物体");
GameObject obj8 = new GameObject("创建挂脚本的空物体", typeof(Lesson1), typeof(Lesson2));

为对象添加脚本

继承了MonoBehavior的脚本,是不能够new出来的,若要动态添加继承了MonoBehavior的脚本在某一个对象上则直接使用AddComponent:

Lesson2 l2 =  obj6.AddComponent(typeof(Lesson2)) as Lesson2;
Lesson1 l1 = obj6.AddComponent<Lesson1>();//使用泛型更方便

得到脚本的成员方法和继承MonoBehavior的类得到脚本的方法相同,故不再赘述

标签比较

if (this.gameObject.CompareTag("Player"))//括号内也可以写成this.gameObject.tag == "Player"
{
    print("该对象的标签是Player");
}
else
{
    print("该对象的标签不是Player");
}

设置失活/激活

参数传false失活,true激活

obj6.SetActive(false);
obj7.SetActive(false);
obj8.SetActive(false);

次要的成员方法

了解即可,不建议使用,效率低

this.gameObject.SendMessage("函数名");//自己查找执行该函数
this.gameObject.BroadcastMessage("函数名");//自己和自己的子对象都查找执行该函数
this.gameObject.SendMessageUpwards("函数名");//自己和自己的父对象都查找执行该函数

这些要查找执行的函数都可以带参数,参数写在函数名后面即可

时间相关_Time

时间缩放比

//时间停止
Time.timeScale =0;
//回复正常
Time.timeScale = 1;
//2倍速
Time.timeScale=2;

帧间隔时间

最近的一帧用了多长时间

受scale影响

print("受scale影响的时间"+Time.deltaTime);

不受scale影响

print("不受scale影响的时间" + Time.unscaledDeltaTime);

帧间隔时间,主要用来计算位移,要根据需求选择计算的时间间隔,如果希望游戏暂停时就不动的就用前者,如果希望不受暂停影响就用后者。

游戏开始到现在的时间

受scale影响

print("游戏开始到现在的"+Time.time);

不受scale影响

print("不受scale影响的游戏开始到现在的时间"+Time.unscaledTime);

物理帧时间间隔

受scale影响

print(Time.fixedDeltaTime);

不受scale影响

print(Time.fixedUnscaledDeltaTime);

帧数

从开始到现在游戏跑了多少帧,即多少次循环

print(Time.frameCount);

Transform

游戏对象(Gameobject)位移、旋转、缩放、父子关系、坐标转换等相关操作都由它处理
是Unity提供的极其重要的类

Vector3基础和Transform位置

Vector3主要是用来表示三维坐标系中的一个点或者一个向量

申明变量

Vector3 v = new Vector3();
v.x = 10;
v.y = 10;
v.z = 10;
Vector3 v2 = new Vector3(10,10);//默认z为0
Vector3 v3 = new Vector3(10,10,10);
Vector3 v4;
v4.x = 10;
v4.y = 10;
v4.z = 10;

基本运算

print(v - v3);
print(v + v2);
print(v * 10);
print(v / 10);

常用

print(Vector3.zero);//000
print(Vector3.right);//100
print(Vector3.left);//-100
print(Vector3.forward);//001
print(Vector3.back);//00-1
print(Vector3.up);//010
print(Vector3.down);//0-10

常用的一个方法:计算距离:

print(Vector3.Distance(v2,v*2));

位置

绝对位置

相对于世界坐标

print(this.transform.position);
相对位置

相对于父对象,没有父对象时与position相同

print(this.transform.localPosition);

transform的xyz是不能直接单独修改的,但是可以用vector给他赋值


print(this.transform.position);
print(this.transform.localPosition);

this.transform.position = new Vector3(10, 10, 10);
this.transform.localPosition = Vector3.up * 10;
//如果只想改一个值xy和z要保持原有坐标一致
//1.直接赋值
this.transform.position = new Vector3(19, this.transform.position.y, this.transform.position.z);
//2.先取出来 再赋值
//虽然不能直接改 transform的 xyz 但是 Vector3是可以直接改 xyz的//所以可以先取出来改vector3 再重新赋值
Vector3 vPos = this.transform.localPosition;
vPos.x = 10;
this.transform.localPosition = vPos;

对象当前的朝向

由于对象可以旋转,对象的朝向会与世界坐标朝向不同

print(this.transform.forward);
//对象当前的各朝向
//对象当前的面朝向
print(this.transform.forward);
//对象当前的头顶朝向
print(this.transform.up);
//对象当前的右手边
print(this.transform.right);

Transform位移

自己计算移动

用当前所在位置加上我要移动的位移得到我所在的最终位置

this.transform.position += this.transform.forward*1*Time.deltaTime;//对象面朝向移动
this.transform.position += Vector3.forward*1*Time.deltaTime;//世界坐标系移动

API移动

使用this.transform.Translate()

//参数一:表示位移多少 路程 = 方向 * 速度 * 时间
//参数二:表示相对坐标系默认该参数是相对于自己坐标系的


//相对于世界坐标系的 z轴 动
this.transform.Translate(Vector3.forward * 1 * Time.deltaTime, Space.World);
//相对于世界坐标的自己的面朝向去动
this.transform.Translate(this.transform.forward 1 Time.deltaTime, Space.World);
//相对于自己的坐标系下 ,再加上旋转的方向
this.transform.Translate(this.transform.forward * 1 * Time.deltaTime, Space.Self);
//相对于自己的坐标系下的 z轴正方向移动
this.transform.Translate(Vector3.forward * 1 * Time.deltaTime, Space.Self);

一般用API来位移

Transform角度和旋转

角度相关

//相对世界坐标角度
print(this.transform.eulerAngles);
//相对父对象角度
print(this.transform.localEulerAngles);
//注意:设置角度和设置位置一样 不能单独设置xyz 要一起设置
//若要改变面板角度则要设置相对角度
this.transform.localEulerAngles = new Vector3(10,10,10);
this.transform.eulerAngles = new Vector3(10, 10, 10);
print(this.transform.localEulerAngles);

旋转相关

//API计算
//自转
//参数一 每一帧旋转的角度  每个轴具体转多少度
//参数二 默认相对于自己坐标系进行的旋转,Space.World为相对世界坐标系旋转
this.transform.Rotate(new Vector3(0,10,0)* Time.deltaTime);
this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime, Space.World);

//相对于某个轴 转多少度
//参数一:是相对哪个轴进行转动
//参数二:转动的角度
//参数三:默认相对于自己的坐标系 Space.World为相对世界坐标系旋转
this.transform.Rotate(Vector3.right,10* Time.deltaTime);
this.transform.Rotate(Vector3.right, 10 * Time.deltaTime,Space.World);

//相对于某一个点转
//参数一:相当于哪一个点转
//参数二:相对于该点哪一个轴转
//参数三:转的度数旋转速度*时间
this.transform.RotateAround(Vector3.zero, Vector3.right, 10 * Time.deltaTime);

Transform缩放和看向

缩放

缩放不能单独改xyz 只能一起改(并且相对于世界坐标系的缩放大小不能修改)

故更改缩放大小都是相对父对象进行修改

//相对世界坐标系
print(this.transform.lossyScale);
//相对本地坐标系(父对象)
print(this.transform.localScale);                                                
this.transform.localScale=new Vector3(3,3,3);

Unity没有提供关于缩放的API,只能自己算

this.transform.localScale += Vector3.one * Time.deltaTime;

看向

让一个对象一直面向某一个点或者某一个对象

//看向一个点 相对于世界坐标系的
this.transform.LookAt(Vector3.zero);
//看向一个对象 就传入一个对象的 Transform信息
this.transform.LookAt(lookAtObj);

Transform父子关系

获取和设置父对象

//获取父对象
print(this.transform.parent.name);
this.transform.parent = null;//取消父对象
//设置父对象
this.transform.parent = GameObject.Find("Father2").transform;

//通过API来进行父子关系的设置

this.transform.SetParent(null);//取消父对象
this.transform.SetParent(GameObject.Find("Father2").transform);//设置父对象
//参数一: 父对象
//参数二: 是否保留世界坐标的 位置 角度 缩放 信息
//true 会保留 世界坐标下的状态和父对象进行计算得到本地坐标系的信息,实际位置(世界坐标中)不变
//false不会保留 使变成字对象后界面显示的内容和之前相同(在世界坐标中会变化)
this.transform.SetParent(GameObject.Find("Father3").transform, false);
this.transform.SetParent(GameObject.Find("Father3").transform, true);

抛妻弃子

删除不了儿子与孙子之间的父子关系

this.transform.DetachChildren();

获取子对象

可以找到失活的子对象,找不到子对象的子对象

print(this.transform.Find("cube(1)").name);
print(this.transform.childCount);//输出子对象的个数,失活的也算
this.transform.GetChild(0);//通过索引得到子对象,超出个数会报错

子对象操作

public Transform son;
...
if(son.IsChildOf(this.transform))
print("是我的儿子");
//得到自己作为儿子的编号
print(son.GetSiblingIndex());
//把自己设置为第一个儿子
son.SetAsFirstSibling();
//把自己设置为最后一个儿子
son.SetAsLastSibling();
//把自己设置为指定个儿子,超出范围就直接设置成最后一个索引
son.SetSiblingIndex(15);

Transform坐标转换

世界坐标转本地坐标

print(Vector3.forward);
//世界坐标系的点转换为相对本地坐标系的点
//受到缩放影响
print("转换后的点" + this.transform.InverseTransformPoint(Vector3.forward));

//世界坐标系的方向 转换 为相对本地坐标系的方向
//不受缩放影响
print("转换后的方向" + this.transform.InverseTransformDirection(Vector3.forward));
//受缩放影响
print("转换后的方向(受缩放影响)" + this.transform.InverseTransformVector(Vector3.forward));

本地坐标转世界坐标

//本地坐标系的点转换为相对世界坐标系的点 受到缩放影响
print("本地 转 世界 点"+ this.transform.TransformPoint(Vector3.forward));
//本地坐标系的方向 转换 为相对世界坐标系的方向
//不受缩放影响
print("本地 转 世界 方向"+ this.transform.TransformDirection(Vector3.forward));
//受缩放影响
print("本地 转 世界 方向"+ this.transform.TransformVector(Vector3.forward));

Input鼠标键盘输入

鼠标在屏幕的位置

//屏幕左下角为坐标原点 往右是x轴正方向 往上时v轴正方向
//返回值时vector3 但是只有 x和y有值 z一直是0 是因为屏幕本来就是2D的 不存在z轴
print(Input.mousePosition);

检测鼠标输入

可以发射子弹

可以控制摄像机转动

//鼠标按下一瞬间 进入
//只要按下的这一瞬间 进入一次
//0左键 1右键 2中键
if (Input.GetMouseButtonDown(1))
{
    print("鼠标某一个键按下了");
}

//鼠标抬起一瞬间 进入
if (Input.GetMouseButtonUp(0))
{
print("鼠标某一个键抬起了");
}

//鼠标长按按下抬起都会进入
//就是 当按住按键不放时 会一直进入 这个判断

if(Input.GetMouseButton(1))
{
print("右键按下");
}

//中键滚动
//返回值的y -1下 0不动 1上
//返回值为Vector2的值 鼠标滚轮滚动会改变其中的y值
print(Input.mouseScrollDelta);

检测键盘输入

//键盘按下
if (Input.GetKeyDown(KeyCode.W))
{
    print("w键按下");
}

KeyCode是枚举类型

//传入字符串的重载
//传入的字符串不能是大写的不然会报错
//但是键盘的大小写都能识别
if(Input.GetKeyDown("q"))
{
    print("键按下");
}

检测默认轴输入

unity提供了 更方便的方法 来帮助我们控制对象的位移和旋转

//参数名可以看 project setting 中的 input manager
//键盘AD按下时 返回 -1到1之间的变换
//该值就是左右方向-1到0代表左,0到1代表右 我们可以通过它来控制 对象左右移动 或者左右旋转
print(Input.GetAxis("Horizontal"));
//键盘SW按下时 返回 -1到1之间的变换
//该值就是前后方向-1到0代表后,0到1代表前 我们可以通过它来控制 对象上下移动 或者上下旋转
print(Input.GetAxis("Vertical"));

//鼠标横向移动时 -1 到 1 左 右
print(Input .GetAxis("Mouse X"));
//鼠标竖向移动时-1到1下上
print(Input.GetAxis("Mouse Y"));
//GetAxisRaw方法和 GetAxis使用方式相同
//只不过 它的返回值 只会是-101不会有中间值 而GetAxis方法返回的值是-1到0到1的渐变值

Input触摸手柄陀螺仪

检测任意键盘按键

//是否有任意键或鼠标长按
if (Input.anyKey)
    print("有一个键长按");
//是否有任意键或鼠标按下
if (Input.anyKeyDown)
    print("有一个键 按下");
print(Input.inputString);

手柄输入相关

//得到连接的手柄的所有按钮名字
string[]strs = Input.GetJoystickNames();
//某一个手柄键按下
if(Input.GetButtonDown("Jump"))
{

}
//某一个手柄键抬起
if (Input.GetButtonUp("Jump"))
{

}
//某一个手柄键长按
if (Input.GetButton("Jump"))
{

}

触摸、陀螺仪相关

//移动设备触摸相关
if (Input.touchCount > 0)
{
    Touch t1 = Input.touches[0];//位置
    print(t1.position);//相对上次位置的变化
    print(t1.deltaPosition);
}
//是否启用多点触控
Input.multiTouchEnabled =false;
//陀螺仪(重力感应)
//是否开启陀螺仪 必须开启 才能正常使用
Input.gyro.enabled = true;//电脑上无法得到该值,手机上才能得到
//重力加速度向量
print(Input.gyro.gravity);

//旋转速度
print(Input.gyro.rotationRate);
//陀螺仪 当前的旋转四元数
//比如 用这个角度信息 来控制 场景上的一个3D物体受到重力影响
//手机怎么动 它怎么动
print(Input.gyro.attitude);

屏幕相关Screen

//当前屏幕分辨率
Resolution r = Screen.currentResolution; print("当前屏幕分辨率的宽" + r.width +"高"+r.height);
//屏幕窗口当前宽高
//需要用窗口宽高做计算时使用
print(Screen.width);
print(Screen.height);
//屏幕休眠模式
Screen.sleepTimeout = SleepTimeout.NeverSleep;

Screen.fullScreen = true;
//窗口模式
//独占全屏Fu11screenMode.ExclusiveFullscreen
//全屏窗口FullScreenMode.FullscreenWindow
//最大化窗口FullscreenMode.MaximizedWindow
//窗口模式Fu1lscreenMode.Windowed
Screen.fullScreenMode = FullScreenMode.Windowed;

//移动设备屏幕转向相关
//允许自动旋转为左横向 Home键在左
Screen.autorotateToLandscapeLeft =true;
//允许自动旋转为右横向 Home键在右
Screen.autorotateToLandscapeRight =true;
//允许自动旋转到纵问 Home键在下
Screen.autorotateToPortrait =true;
//允许自动旋转到纵向倒着看 Home键在上
Screen.autorotateToPortraitUpsideDown=true;

//指定屏幕显示方向
Screen.orientation = ScreenOrientation.AutoRotation;

//设置分辨率 一般移动设备不使用
Screen.SetResolution(1920,1080,false);

Camera可编辑参数说明

Clear Flags

skybox天空盒:模拟天空背景,用于3D

Solid Color颜色填充:填充背景颜色,一般用于2D

Depth only只画该层,背景透明:多个摄像机叠加渲染与Depth叠加使用

Don't Clear不移除,覆盖渲染:一般不用

Culling Mask

选择渲染层级,可以指定渲染或不渲染某一层级的对象

Projection

perspective透视模式(近大远小,一般用于3D游戏)

Fov Axis:决定光学仪器的视野范围

Field of view:视口大小

Physical Camera(物理摄像机):摄影相关参数,如Focal Length(焦距)、Sensor Type(传感器类型)、Sensor Size(传感器尺寸)等

orthographic 正交摄像机(一般用于2D游戏制作)

size为大小

Clipping Planes

裁剪平面距离,最近能看多近,最远能看多远

Depth

渲染顺序上的深度,深度大的Camera后被渲染,小的先被渲染,后渲染的会把前渲染的挡住

Redering path

渲染纹理,可以把摄像机画面渲染到一张图上,在Project右键创建Render Texture,主要用于制作小地图

Occlusion Culling

是否启用剔除遮挡,被挡住的模型不被渲染

Viewport Rect

视口范围,屏幕上将绘制该摄像机的视图位置,用于双摄像机游戏,0-1相当于宽高百分比

Rendering path

渲染路径

只做了解

Allow HDR 是否允许高动态范围渲染

Allow MSAA 是否允许抗锯齿

Allow DYnamic Resolution 是否允许动态分辨路呈现

Target Display 用于那个显示器,主要用来开发有多个屏幕的平台游戏

Camera代码相关

重要静态成员

//获取摄像机
//如果用之前的知识 public一个对象然后将camera拖进去 来获取摄像机
//主摄像机的获取
//如果想通过这种方式 快速获取摄像机 那么场景上必须有一个 tag为Maincamera的摄像机
print(Camera.main.name);
//获取摄像机的数量
print(Camera.allCamerasCount);
//得到所有摄像机
Camera[] AllCamera = Camera.allCameras; 
print(AllCamera.Length);

//渲染相关委托
//摄像机剔除前处理的委托函数
Camera.onPreCull += (c) =>
{

};
//摄像机 渲染前处理的委托
Camera.onPreRender += (c) =>
{

};
//摄像机 渲染后 处理的委托
Camera.onPostRender += (c) =>
{

};

重要成员

public class Lesson14 : MonoBehaviour
{
    public Transform obj;
    // Start is called before the first frame update
    void Start()
    {
        //世界坐标转屏幕坐标
        //转换过后x和y对应的就是屏幕坐标 z对应的是该物体离摄像机有多远,两者的z之差
        //我们会用这个来做的功能 最多的 就是头顶血条相关的功能
        
    Vector3 v &#61; Camera.main.WorldToScreenPoint(this.transform.position);
    print(v);
}

// Update is called once per frame
void Update()
{
    //屏幕坐标转世界坐标
    Vector3 v1 &#61; Input.mousePosition;
    //只所以改变z轴 是因为 如果不改 z默认为0
    //转换过去的世界坐标系的点 永远都是一个点 可以理解为 视口 相交的焦点
    //改变z才能在视野中显示出来
    v1.z &#61; 10;
    obj.position &#61; Camera.main.ScreenToWorldPoint(v1);
   // print(Camera.main.ScreenToWorldPoint(v1));
}

}

光源系统基础

光源组件

Type光源类型

Point:点光源,参数:Range(照射范围)

Spot:聚光灯,方向光(环境光),参数:Range(照射范围)Spot Angle(光锥角度)

Area:面光源(仅在烘焙状态下有用,节约性能,提前将光源效果计算好再将算好的图贴上去,并非实施计算,但是有物体移动到该光源下时,光影效果不受该光源影响)

Color光源颜色

Mode光源模式

Realtime:实时光源,实时渲染,效果好,性能消耗大

Baked:烘焙光源,提前计算好,无法动态变化

Mixed:混合光源,预先计算+实时运算

Intensity光源亮度

Shadow Type

Noshadows:关闭阴影

HardShadows:生硬阴影,性能消耗较低

SoftShadows:柔和阴影,性能消耗较高

投影遮罩

Draw Halo

球形光环开关,光源周围产生光晕

Flare

耀斑,若希望摄像机能看到耀斑效果,需要在摄像机上加上Flare Layer脚本,不加脚本摄像机中看不到

Culling Mask

剔除遮罩层 ,决定哪些层的光源对象收到该光源的影响,和Camera中的效果类似

以下了解即可

Indirect Multiplier

调整间接光的强度,大于1每次反射会使光更亮,小于1每次反射会使光更暗

RealtimeShadows

strength:阴影暗度 0-1之间,越大阴影越暗

Resolution:阴影贴图渲染分辨率,越高越逼真、消耗越高

Bias:阴影推理光源的距离

Normal Bias:阴影投射面延法线收缩距离

Near Panel:渲染阴影的近裁剪面

Cookie Size

方向光源(Spot)才有,但一般不设置,用来调整遮罩大小

Render Mode

渲染优先级

auto:运行时确定

Important:以像素质量为单位进行渲染,效果逼真,消耗大

Not important:以快速模式进行渲染

光面板相关

环境相关设置

Skybox Meterial:改变天空和材质

Sun Source:太阳来源,不设置会默认使用场景中最亮的方向光为太阳

Environment Lighting:环境光设置{

Source:环境光光源颜色,Skybox(以天空和材质作为环境光颜色),Gradient(可以为天空、地面、地平线单独选择颜色,得到混合的效果)

Intensity Multiplier:环境光亮度

Ambient Mode:全局光照模式,只有启用了实时全局和全局烘焙时才有用,Realtime(已弃用),Baked(烘焙)

}

其他设置

碰撞检测

碰撞产生的必要条件:两个物体都有碰撞器且至少其中一个是刚体

刚体

Mass:质量(默认为千克),质量越大惯性越大

Drag:空气阻力,0表示没有空气阻力

Angular Drag:扭矩阻力,影响旋转,0表示没有空气阻力

Use Gravity:是否受重力影响

Is Kinematic:若启用则不会被物理引擎影响,只能通过transform对其进行移动

Interpolate:插值运算,让刚体运动更平滑(None(不应用插值运算),Interpolate(根据前一帧的改变平滑变换),Extrapolate(差值运算,根据下一帧的变换来平滑变换))

Collision Detection(碰撞检测模式,用于防止快速移动的物体穿过其他物体而不检测碰撞,一帧移动距离过大直接穿过碰撞对象)

Constraint:约束对刚体运动的限制(Freeze Position:有选择地停止刚体沿着世界xyz轴移动;Freeze Rotation:有选择地停止刚体沿着世界xyz轴旋转)

碰撞器

种类:

盒状、球状、胶囊、网格、轮胎、地形(前三种性能高,后三者性能低)

共同参数:

Is Trigger:是否为触发器,启用该属性则该物体将用于触发事件、并被物理引擎忽略,主要用于没有物理效果的碰撞检测

Material:物理材质,可以确定碰撞体和其他碰撞对象的交互方式

Center:碰撞体在局部控件对象中的中心点位置

常用碰撞器:

BoxCollider(盒状)

Size参数:碰撞体在XYZ轴上的大小

Sphere Collider(球状)

Radius参数:碰撞体的半径大小

Capsule Collider(胶囊)

Radius参数:胶囊体的半径

Height参数:胶囊体的高度

Direction参数:胶囊体在对象局部空间中的轴向

异形物体使用多种碰撞器组合

刚体对象的子对象碰撞器信息参与碰撞检测,给父对象加上刚体脚本,子对象也会参与碰撞

不常用的碰撞器

Mesh Collider(网格碰撞器)、Wheel Collider(环状碰撞器)、Terrain Collider(地形碰撞器)

网格碰撞器:

轮胎:

和刚体父对象一起使用,父对象质量要足够大,不然会被轮胎弹飞

地形碰撞器:

物理材质

创建物理材质

右键create Physic Material后拖拽给碰撞体脚本中的Material栏

物理材质参数

碰撞检测函数

物理碰撞检测响应函数

只要得到了碰撞到的对象的任意信息就可以得到他的所有信息

Collision中包含的碰撞到自己的对象的相关信息
相关参数
碰撞自己的对象的碰撞器的信息

collision.collider

碰撞对象(GameObject)

collision.gameObject

碰撞对象的位置信息

collision.transform

触碰点数相关

collision.contactCount

接触点的具体坐标

ContactPoint[] pos= collision.contacts

函数:

private void OnCollisionEnter(Collision collision)
{
    print(this.name + "被"+collision.gameObject.name+"撞了");
}
//碰撞结束时会自动执行该函数
private void OnCollisionExit(Collision collision)
{
    print(this.name + "被" + collision.gameObject.name + "结束碰撞了");
}
//两个物体相互接触/摩擦时会自动执行该函数,但不是一直接触一直执行
private void OnCollisionStay(Collision collision)
{
    print(this.name + "一直在和" + collision.gameObject.name + "接触");
}

触发器检测响应函数

//第一次接触时会调用
private void OnTriggerEnter(Collider other)
{
    print(this.name + "被" + other.gameObject.name + "触发了");
}
//二者接触时会调用
private void OnTriggerExit(Collider other)
{
    print(this.name + "被" + other.gameObject.name + "结束触发了");
}
//二者结束接触时会调用
private void OnTriggerStay(Collider other)
{
    print(this.name + "一直在和" + other.gameObject.name + "触发");
}

明确何时响应函数

只要挂载对象和其他物体能产生碰撞或者触发,就能执行对应的碰撞/触发函数

只在子对象上挂载该脚本检测碰撞,如果该子对象没有刚体组件不能执行,需要挂载到他的具有刚体组件的父对象上,挂载到父对象上若只有子对象碰撞到了也会触发

根据需求来写这6个函数

要明确物理碰撞和触发器响应的区别

碰撞和触发器函数都可以写成虚函数,在子类中重写逻辑

一般会把想要重写的碰撞和触发函数写成保护类型的没有必要写成public,因为我们不会手动调用该函数,都是unity通过反射帮助我们调用的

刚体加力

首先要获取刚体

Rigidbody body;
void Start()
{
    body = this.GetComponent<Rigidbody>();
}

刚体自带添加力的方法

//添加力
//相对世界坐标系
body.AddForce(Vector3.forward * 10);
        

//相对本地坐标系
body.AddRelativeForce(Vector3.forward * 10);//body.AddForce(this.transform.forward * 10);效果相同

//添加扭矩力
//相对世界坐标系
body.AddTorque(Vector3.up * 10);
//相对本地坐标系
body.AddRelativeTorque(Vector3.up * 10);

//直接改变速度
//该改动的速度方向是相对于世界坐标系的
body.velocity = Vector3.forward*10;

//模拟爆炸的效果,该爆炸效果只对挂载了该脚本的对象生效
body.AddExplosionForce(10, Vector3.zero, 10);

力的几种模式

//计算方式不同,故最终移动的速度不同
//第二个参数 力的模式 主要的作用 就是 计算方式不同
//由于4种计算方式不同 最终移动速度不同
body.AddForce(Vector3.forward * 10,ForceMode.Force);
//1.Acceleration
//给物体增加一个持续的速度, 忽略其质量
//v = Ft/m
//F:(0,0,10)
//t:0.02s  物体帧时间
//m:默认为1
//v = 10 * 0.02 / 1 = 0.2m/s
//每物理帧移动 0.2m/s * 0.02s = 0.004m

//2.Force
//给物体添加一个持续的力, 与物体的质量有关
//m:2kg
//v = 10 * 0.02 / 2 = 0.1m/s
//每物理帧移动 0.1m/s * 0.02s = 0.002m

//3.Impulse
//给物体添加一个瞬间的力 ,与物体质量有关 忽略时间 默认为1
//t:1s
//v = 10 * 1 / 2 = 5m/s
//每物理帧移动 5m/s * 0.02s = 0.1m

//4.VelocityChange
//给物体添加一个瞬时速度 忽略质量 忽略时间 默认质量1kg时间1s
//v = 10 * 1 / 1 = 10m/s
//每物理帧移动 10m/s * 0.02s = 0.2m

力场脚本

unity提供了一个常量力的组件:Constant Force 脚本

刚体的休眠

Unity为了节约性能,会在某些情况刚体休眠

//获取刚体是否处于休眠状态
if(rigidBody.IsSleeping())
{
    //若是 则唤醒
    rigidBody.WakeUp();
}

音效系统

音频文件导入

常用格式

wav、mp3、ogg、aiff

音频文件属性设置

音频源和音频监听脚本

音频源

音频监听脚本

AudioListener只能有一个,一般放在主摄像机上,有该脚本才能听到声音

代码控制音频源

代码控制播放停止

if(Input.GetKeyDown(KeyCode.P)) 
{
    //播放音效
    audioSource.Play();
}
if (Input.GetKeyUp(KeyCode.S))
{
    //停止音效
    audioSource.Stop();
}
if(Input.GetKeyDown(KeyCode.Space))
{
    //暂停播放
    audioSource.Pause();
}

检测音效是否播放完毕

if(audioSource.isPlaying)
{
    print("播放中");
}
else
{
    print("播放结束");
}

动态控制音效播放

直接在要播放音效的对象上挂载脚本 控制播放

如同上文的控制音效播放暂停等


实例化挂载了音效源脚本的对象

new一个GameObject,将自动播放音效的的预设体拖到里面,在相应条件下实例化该预设体 ,实际使用较少。
用一个Audiosource来控制播放不同的音效

将对应的音效拖入clip中

public AudioClip clip;
...
AudioSource aud = this.gameObject.AddComponent<AudioSource>();
aud.clip = clip;
aud.Play();

一个Gameobiect可以挂载多个音效源脚本Audiosource
使用时要注意 管理多个音效 控制他们的播放 停止

麦克风输入相关

获取设备麦克风信息

string[] str = Microphone.devices;
for(int i = 0; i < str.Length; i++)
{
    print(str[i]);
}

开始录制

//参数一:设备名 传空使用默认设备
//参数二:i超过录制长度后 是否重头录制
//参数三:录制时长
//参数四:采样率
if (Input.GetKeyDown(KeyCode.Space))
{
    clip = Microphone.Start(null, false, 10, 44100);
}

结束录制

if (Input.GetKeyUp(KeyCode.Space))
{
    Microphone.End(null);
    AudioSource s = this.gameObject.GetComponent<AudioSource>();
    if (s != null)
    {
        s = this.gameObject.AddComponent<AudioSource>();
    }
    s.clip = clip;
    s.Play();
}

获取音频数据用于存储或传输

//用于存储的数组长度为声道数*剪辑长度
float[] f =new float[clip.channels*clip.samples];
clip.GetData(f, 0);
print(f.Length);

场景转换

SceneManager.LoadScene("场景名字");

完结