Unity入门积累(上)

77 阅读14分钟

一、下载安装

image.png 地址:unity.cn/

image.png 注册unity账号-下载Hub-安装稳定版本-Hub中搞定unity许可证 可以在已添加版本中添加模块

注:Hub是一个类似于版本管理器的存在,还可在其中寻找各种资源。

二、新建工程介绍

image.png

三、Scene 和 Hierarchy窗口

Hierarchy窗口

image.png

Hierarchy若不存在点击右上角三点添加进来。

image.png

用于管理游戏窗口中出现的内容。空白区域鼠标右键或点击加号可以创建物品

image.png

Scene窗口:

image.png

image.png

渲染模式:前三个为着色器、网格和着色器网格模式。 英语生词:Shaded:阴影、着色。 Wireframe:线框

image.png

image.png

视角切换:点击任意一轴可以切换到从x轴看z和y。点击中间或下面单词。可以切换透视(一般3D用,远小近大)和 ISO(正交模式,都一样大,一般2D用)。

image.png

image.png

参照对象切换和移动模式:1中可以切换拖对象移动时的参照坐标系,2中切换移动模式到一单位格移动(也能按住Ctrl来拖动)。

image.png

image.png

image.png

层级物体中眼睛为是否看见、手为是否可选中

四、Game 和 Project窗口

Game窗口:用于观看玩家视角

image.png

image.png

Project窗口: 管理资源脚本等

image.png 快捷键与图层一样

image.png

五、Inspector 和 Console窗口

Inspector窗口: 用来查看游戏场景中对象关联C#脚本信息

英语生词:Inspector:检查器 image.png

Console: 主要用于调试。在窗口-常规(General)-控制台(Console)中可以找到或快捷键:Ctrl+Shift+C。

主要功能:

image.png

六、工具栏和父子关系

image.png 注意:需要另开一个工程需要去Hub中进行开启。

image.png

游戏对象:移动到视图以及其下面几个可以切换物体位置或当前视口位置,或物体是否激活。

image.png

组件:可以添加系统自带组件,与层级中对象添加组件功能类似。 窗口中可以加载资源商店

总结目前重点:

image.png

父子关系:

image.png

Scene上方Pivot可以切换成中心模式,会将位移中心调整到组中心。而Global是调整位移方向相对参照物的。如图:

image.png

七、反射机制和游戏场景

反射机制:

unity反射介绍:

image.png

对象和组件之间的关系:

image.png

image.png

游戏场景:

知识点一、新建场景并保存:通过文件-新建场景(也能Ctrl + N或者在Hub),使用保存场景(Ctrl + S)并存到Scene文件夹下。

知识点二、多个场景的重叠:将Scene中的场景拖到层级中,可以进行复制粘贴游戏对象的操作。

image.png

image.png

八、预制体

知识点一、创建预制体:

预制体是预先创建的模版,创建时需要将层级中创建好的对象拖入项目资产中

image.png

知识点二、修改预制体:

image.png

对原有预制体改变后会出现上图所示的全部恢复和应用所有。全部恢复会变回预制体原有模版。应用所有会改变所有预制体创建的对象和预制体。选择是打开当前预制体模版,打开是编辑预制体模版。 想要仅改变当前预制体创建的对象,可以右键然后点击(英文是Unpack Prefabs)

image.png 就可以解绑原有预制体。

知识点三、导出导入包:

导出:在项目-Assets中右键可以找到导出:

image.png

导入:同样右键导入后缀为UnityPackage的文件,也能拖入文件。

九、脚本

创建规则:

image.png

一般会创建一个Scripts文件夹来统一管理脚本。 注意:unity中的文件名和vs中的类名需要相同。

MonoBehaviour:Behaviour(行为) image.png

image.png

image.png

需要修改一些模版时进入hub中点击找到引擎位置:之后的更改路径如上图默认脚本位置所示

image.png

修改脚本执行顺序:

image.png

十、生命周期

关于帧的介绍: image.png

生命周期函数介绍:

image.png

部分生命周期函数:生命周期函数一般是private或者protected。注意:对象指的是脚本

image.png

打印信息: image.png

物理帧更新是固定时间。而FixedUpdate就是专门进行物理帧更新的。(可以在Edit-Project Settings...-Time)中进行设置:

image.png

OnDisable:图片下方解释有误,应为:失活时启动。

image.png

十一、Inspector可变量

Inspector(检查器窗口)中可编辑框是脚本中的成员变量。

知识点一、正常情况下private和protected成员变量是无法在Inspector窗口显示的。但在其上面加\[serializeField]这种特性就可以。

英语生词:Serialize:序列化。Field:字段

image.png

知识点二、公共的可直接显示在检查器窗口中。上方加上\[HideInInspector]可使其不显示在检查器窗口中。

英语生词:Hide:隐藏。

image.png

image.png

知识点三、可显示类型和不可显示类型及自定义类型显示:

image.png

上图中1是可在unity中显示,2是不可显示的。

image.png

想让自定义的类或结构体这些可被显示,可以加上System.Serializable特性。

知识点四、辅助内容

标题分组显示:

[Header("基础字段")]
public int x = 1;
public int y = 2;
[Header("其他字段")]
public int z = 3;

image.png

其他显示:

image.png

image.png

添加方法

image.png

image.png

十二、MonoBehavior类重要内容

知识点一:获取挂载对象和其位置信息及控制是否激活

image.png

注意:如果想获取其他游戏对象信息可以将其他对象管理脚本对象变量来获取信息

知识点二:重要方法

1、获取自己挂载的单个脚本:

image.png

2、获取多个脚本:

image.png

3、获取子类脚本(同时也含自己的)

image.png

4、获取父类脚本(同时也含自己的)

父对象方法就没有填true或false因为父对象失活,子对象不可能运行脚本。

image.png

5、获取可能为空脚本

image.png

练习题:

image.png

1、this代表该脚本,this.gameObject代表挂载的游戏对象,this.transform代表该脚本挂载对象的位置信息(也可以用this.gameObject.transform)

2、

void Start()
{
    print("Test1");
    Test2 test2;
    if (this.TryGetComponent<Test2>(out test2))
    {
        print(test2);
        test2.enabled = false;
    }
}

3、

public class Test1 : MonoBehaviour
{
    [SerializeField]
    GameObject car;
    // Start is called before the first frame update
    void Start()
    {
        print("Test1");
        Test2 test2;
        if (car.TryGetComponent<Test2>(out test2))
        {
            print(test2);
            test2.enabled = false;
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

十三、GameObject

知识点一、GameObject成员变量

image.png

知识点二、GameObject静态方法

英语生词:primitive:原来的。

创建对象:

image.png

通过名字找单个对象:

只能找到激活的对象 如果用单个方法寻找结果有多个满足条件,会返回随机的一个。

image.png

查找多个对象

image.png

克隆对象 Instantiate:在计算机中为实例化。类似于克隆和删除的方法,他们是Unity自带的Object中的方法,所以可以直接方法名来使用。

image.png

克隆后物体的位置:

原始预制体(Prefab)的初始位置

  • 当你使用 Instantiate 克隆一个预制体时,新物体的位置会继承该预制体在场景中 原始保存的位置
  • 例如,如果你的预制体在制作时(在场景中)的位置是 (2, 3, 0),那么直接 Instantiate 时,新物体也会出现在 (2, 3, 0)(相对于父物体或世界坐标系)。

父物体的影响

  • 如果 Instantiate 时指定了父物体(通过 parent 参数),新物体会以父物体的位置为基准,叠加预制体的本地位置(localPosition)。
  • 如果没有父物体,则使用世界坐标系(World Space)下的位置。

删除对象

image.png

过场景不移除

image.png

知识点三、GameObject成员方法

image.png

上图中的params是一种变长参数的意思

创建空物体:

image.png

添加脚本

image.png

标签比较

image.png

设置激活、失活

image.png

广播执行脚本

image.png

总结:重要的内容

image.png

练习:

image.png

public class Test2 : MonoBehaviour
{
    [SerializeField]
    GameObject car;
    void Start()
    {
        print("执行实例化预制体");
        GameObject.Instantiate(car);
    }

}
public class Test2 : MonoBehaviour
{
    [SerializeField]
    GameObject car;
    void Start()
    {
        Test1 t1 = car.GetComponent<Test1>();
        //t1.SetActive(false);
        print(t1);
        //GameObject.Destroy(t1);
        t1.enabled = false;
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum E_Destroy
{
    NotDestroy,
    Destroy,
    DestroyImmediate
}

public class Test2 : MonoBehaviour
{
    [SerializeField]
    GameObject car;
    public string name;
    public bool IsActive;
    public E_Destroy _Destroy;
    void Start()
    {
        car.name = name;
        car.SetActive(IsActive);
        if(_Destroy == E_Destroy.NotDestroy)
        {
            print("不删除");
        }
        else if (_Destroy == E_Destroy.Destroy)
        {
            print("延迟删除");
            GameObject.Destroy(car);
        }
        else
        {
            print("立即删除");
            GameObject.DestroyImmediate(car);
        }
    }
}

十四、时间time相关

作用:位移、计时、时间暂停

知识点一、时间缩放比例

image.png

知识点二、帧间隔时间

image.png

知识点三、游戏开始到现在的时间(主要用于单机)

image.png

知识点四、物理帧时间间隔

image.png

知识点五、帧数

image.png

十五、Vector3基础和Transform

知识点一、Vector3基础

vector3声明:

image.png

Vector3基本计算:

image.png

Vector3常用:

image.png

计算距离:

image.png

知识点二、位置

this.transform.position; 得到的是世界坐标系。

this.transform.localPosition; 相对父对象的坐标。

改变位置:不能直接改某一个值,只能全部坐标一起赋值。

image.png

得到朝向:

image.png

知识点三、位移移动

路程 = 方向 * 速度 * 时间

自己计算:

image.png

API计算:

this.transform.Translate(this.transform.forward * 1 * Time.deltaTime, Space.Self);

注意:第二个参数不填的,默认是Space.Self

Translate有两个参数1为路程(带方向),2为参考坐标系。有Space.Self和World。上面函数意思是以自己为坐标系移动,移动的路程是相当于世界坐标系下自己方向的路程。(总结:在自己坐标系下还需要偏转自己朝向那么多度。)

练习题:

image.png

1、

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

public class Test3 : MonoBehaviour
{
    [SerializeField]
    GameObject carPrefab;
    // Start is called before the first frame update
    void Start()
    {
        Instantiate(carPrefab);
    }
}

2、

第二个行;第四个行

3、

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

public class Test3 : MonoBehaviour
{
    [SerializeField]
    GameObject car;
    private void Start()
    {
        car = Instantiate(car);
    }
    private void Update()
    {
        car.transform.Translate(car.transform.forward * 1 * Time.deltaTime, Space.World);
    }
}

知识点四、角度和旋转

角度相关:

image.png

自转:使用API旋转:

Rotate第一种重载:

image.png

Rotate第二种重载:

image.png

围绕某一点旋转:

image.png

练习题:

image.png

1、

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

public class Test_Temp : MonoBehaviour
{
    GameObject cube;
    // Start is called before the first frame update
    void Start()
    {
        //创建自带的立方体,并设置位置和缩放以及名称
        cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.transform.position = new Vector3(2, 0.5f, 2);
        cube.transform.localScale = new Vector3(2, 1, 2);
        cube.name = "1212";
    }

    // Update is called once per frame
    void Update()
    {
        //使其每帧以自己的y方向为轴转动10度
        this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime);
    }
}

2、需要绑定如下:

image.png

tanke:

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

public class Test_Temp : MonoBehaviour
{
    GameObject cube;
    // Start is called before the first frame update
    void Start()
    {
        //创建自带的立方体,并设置位置和缩放以及名称
        cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.transform.position = new Vector3(2, 0.5f, 2);
        cube.transform.localScale = new Vector3(2, 1, 2);
        cube.name = "1212";
    }

    // Update is called once per frame
    void Update()
    {
        //使其每帧以自己的y方向为轴转动10度
        this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime);
    }
}

外层cube:

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

public class Test1 : MonoBehaviour
{
    int count = 50;
    private void Update()
    {
        this.transform.Rotate(new Vector3(0, count, 0) * Time.deltaTime);
        if(Time.frameCount % 1000 == 0)
        {
            print(Time.frameCount);
            count = -count;
        }
    }
}

GameObject:

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

public class Test2 : MonoBehaviour
{
    int count = 20;
    // Update is called once per frame
    void Update()
    {
        this.transform.Rotate(new Vector3(0, 0, count) * Time.deltaTime);
        if (Time.frameCount % 1000 == 0)
        {
            print(Time.frameCount);
            count = -count;
        }
    }
}

3、

o3,o2,o1为从父到子的顺序球体。

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

//地球脚本
public class q2 : MonoBehaviour
{
    public GameObject o3;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        //自转
        this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime);
        //公转
        this.transform.RotateAround(o3.transform.position, Vector3.up, 5 * Time.deltaTime);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//月球脚本
public class q1 : MonoBehaviour
{
    //地球游戏对象
    [SerializeField]
    GameObject o2;
    // Update is called once per frame
    void Update()
    {
        //公转
        this.transform.RotateAround(o2.transform.position, Vector3.up, 10 * Time.deltaTime);
        //自转
        this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime, Space.Self);
    }
}

知识点五、缩放

缩放基本知识:

image.png

手写缩放:

image.png

看向:

image.png

总结:

image.png

练习:

image.png

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

public class Camera : MonoBehaviour
{
    public GameObject go1;
    Vector3 s;
    private void Start()
    {
        s = go1.transform.position - this.transform.position;
    }
     
    // Update is called once per frame
    void Update()
    {
        this.transform.LookAt(go1.transform.position);
        this.transform.position = go1.transform.position - s;
    }
}

十六、父子关系

知识点一:获取和设置父对象

image.png

知识点二:父类舍弃直连子类

需要注意的是:只会断掉和自己直接相连的子类。 image.png

知识点三:获取子对象

按名字查找:

image.png

遍历子对象:

可以得到子对象数量(包含失活对象),还能通过索引去找,顺序是Hierarchy

image.png

知识点四:儿子的操作:

image.png

练习题:

image.png

第一题、 第一种解法:

image.png

第一题、 第二种解法:

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

public static class ExtensionMethod
{
    //拓展方法需要在静态非泛型类中,拓展方法需要时静态方法,第一个参数前面加this
    public static string[] SortByNameLength(this Transform trans)
    {
        int nameLength = trans.childCount;
        string[] nameStr = new string[nameLength];
        string temp;
        //获取子类名数组
        for (int i = 0; i < nameLength; i++)
        {
            nameStr[i] = trans.GetChild(i).name;
        }
        //冒泡排序
        for(int i = 0; i < nameLength - 1; i++)
        {
            for(int j = 0; j < nameLength - i - 1; j++)
            {
                if (nameStr[j].Length > nameStr[j + 1].Length)
                {
                    temp = nameStr[j + 1];
                    nameStr[j + 1] = nameStr[j];
                    nameStr[j] = temp;
                }
            }
        }
        //根据名字查找并设置顺序,顺序为:最长->最短 依次设置为第一个子对象。
        for(int i = nameLength - 1; i >= 0; i--)
        {
            trans.Find(nameStr[i]).SetAsFirstSibling();
        }
        return nameStr;
    }
}

public class P16 : MonoBehaviour
{
    private void Start()
    {
        string[] table = this.transform.SortByNameLength();
        foreach(string item in table)
        {
            print(item);
        }
    }
}

2、

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

//拓展方法类:需要写在静态类中
public static class Temp
{
    private static GameObject son;
    public static void FindByName(this Transform trans, string name)
    {
        son = GameObject.Find(name);
        if (son.transform.IsChildOf(trans))
        {
            MonoBehaviour.print(son);
        }
    }
}
public class P1 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        this.transform.FindByName("Cube (1)");
    }
}

十七、坐标转换

知识点一:世界坐标转换为本地坐标

英语生词:Inverse:逆向。Direction:方向。

image.png

知识点二:本地坐标转换为世界坐标

image.png

练习题:

image.png

1、

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

public class P16 : MonoBehaviour
{
    private void Start()
    {
        //先通过本地坐标得到世界坐标,在该世界坐标处生成一个空物体。
        GameObject go = new GameObject("newEmpty");
        go.transform.position = this.transform.TransformPoint(new Vector3(-1, 0, 1));
    }
}

2、

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

public class P16 : MonoBehaviour
{
    private void Start()
    {
        //循环创建物体随后改变世界坐标。
        for(int i = 1; i < 4; i++)
        {
            GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            go.transform.position = this.transform.TransformPoint(new Vector3(0, 0, i));
        }
    }
}

第一二题第二种方法:使用特性在检查窗口可以找到:

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

public class P16 : MonoBehaviour
{
    [ContextMenu("左前上创建物体")]
    void ComFun()
    {
        //先通过本地坐标得到世界坐标,在该世界坐标处生成一个空物体。
        GameObject go = new GameObject("newEmpty");
        go.transform.position = this.transform.TransformPoint(new Vector3(-1, 0, 1));
    }
    [ContextMenu("前方创建三个球")]
    void ComFun2()
    {
        //循环创建物体随后改变世界坐标。
        for (int i = 1; i < 4; i++)
        {
            GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            go.transform.position = this.transform.TransformPoint(new Vector3(0, 0, i));
        }
    }
}

十八、Input鼠标键盘输入输出

知识点一、鼠标位置和屏幕坐标原点

image.png

知识点二、检查鼠标输入

鼠标按下和抬起进入:

image.png

鼠标长按一直返回true:

image.png

中间滚动状态:

image.png

知识点三、检测键盘输入

键盘按下:

image.png

键盘抬起:

image.png

键盘长按:

image.png

知识点四、检测默认轴输入

键盘上下左右:

英语生词:Horizontal:水平的。Vertical:垂直的。

image.png

鼠标上下左右:

image.png

知识点五、其他输入方式

任意键长按触发:

image.png

任意键按下触发 和 记录这一帧输入:

image.png

手柄输入:

image.png

触摸:

image.png

陀螺仪:

image.png

练习题:

image.png

两题合一:

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

public class CarDriction : MonoBehaviour
{
    public int removeSpeed;
    public int rotateSpeed;
    public int selfRotateSpeed;
    public GameObject go;
    // Update is called once per frame
    void Update()
    {
        //W、S控制前进后退采用 公式为:正方向 * 速度 * 时间 * 输入:向哪边运动 传入的是一个方向向量,默认坐标系是Space.Self
        this.transform.Translate(Vector3.forward * removeSpeed * Time.deltaTime * Input.GetAxis("Vertical"));
        //A、D控制左右旋转车体 公式为:旋转轴 * 速度 * 时间 * 输入
        this.transform.Rotate(Vector3.up * rotateSpeed * Time.deltaTime * Input.GetAxis("Horizontal"));
        //鼠标左右移动控制炮台旋转 公式为:旋转轴 * 速度 * 时间 * 输入
        this.transform.Rotate(Vector3.up * selfRotateSpeed * Time.deltaTime * Input.GetAxis("Mouse X"));
    }
}

十九、屏幕相关

知识点一、静态成员变量

英语生词:current:当前。resolution:分辨率。

分辨率、窗口大小、休眠模式:

image.png

游戏是否全屏:

image.png

屏幕转向:

image.png

指定屏幕固定方向:

image.png

知识点二、静态方法

设置分辨率:

image.png

练习题:

image.png

合二为一:

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

public class CarDriction : MonoBehaviour
{
    public int removeSpeed;//前后移动速度
    public int rotateSpeed;//车体左右旋转速度
    public int selfRotateSpeed;//炮塔旋转速度
    public int gunUpDownSpeed;//炮管上下速度
    public GameObject go;
    public Transform EmptyTransform;
    public GameObject gun;
    public GameObject camera1;
    // Update is called once per frame
    private void Start()
    {
        camera1.transform.LookAt(this.transform.position);
    }
    void Update()
    {
        //W、S控制前进后退采用 公式为:正方向 * 速度 * 时间 * 输入:向哪边运动 传入的是一个方向向量,默认坐标系是Space.Self
        this.transform.Translate(Vector3.forward * removeSpeed * Time.deltaTime * Input.GetAxis("Vertical"));
        //A、D控制左右旋转车体 公式为:旋转轴 * 速度 * 时间 * 输入
        this.transform.Rotate(Vector3.up * rotateSpeed * Time.deltaTime * Input.GetAxis("Horizontal"));
        //鼠标左右移动控制炮台旋转 公式为:旋转轴 * 速度 * 时间 * 输入
        this.transform.Rotate(Vector3.up * selfRotateSpeed * Time.deltaTime * Input.GetAxis("Mouse X"));
        //鼠标滑轮控制炮管上下 参数:哪一个点:Vector3 point, 哪个轴:Vector3 axis, 多少度:float angle
        gun.transform.RotateAround(EmptyTransform.position, Vector3.left, gunUpDownSpeed * Time.deltaTime * Input.mouseScrollDelta.y);
        //鼠标右键进入->鼠标移动控制摄像机绕车旋转,并看向车
        if (Input.GetMouseButton(1))
        {
            print("右键进入");
            print(Input.GetAxis("Mouse X"));
            camera1.transform.RotateAround(this.transform.position, Vector3.up, 200 * Time.deltaTime * Input.GetAxis("Mouse X"));
            camera1.transform.RotateAround(this.transform.position, Vector3.left, 200 * Time.deltaTime * Input.GetAxis("Mouse Y"));
        }
    }
}