国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Unity 游戲開發(fā)、01 基礎篇 | 知識大全、簡單功能腳本實現(xiàn)

這篇具有很好參考價值的文章主要介紹了Unity 游戲開發(fā)、01 基礎篇 | 知識大全、簡單功能腳本實現(xiàn)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

2.3 窗口布局

  • Unity默認窗口布局

    • Hierarchy 層級窗口
    • Scene 場景窗口,3D視圖窗口
    • Game 游戲播放窗口
    • Inspector 檢查器窗口,屬性窗口
    • Project 項目窗口
    • Console 控制臺窗口
  • 恢復默認布局 Window | Layouts | Default

  • 調大頁面字體 Preference | UI Scaling


3.1 場景

新項目默認創(chuàng)建了 SampleScene 場景 {攝像機,平行光}


3.2 游戲物體

SampleScene 里 {攝像機,平行光} 就是兩個游戲物體

添加物體

  • GameObject 下拉菜單
  • Hierarchy 窗口 右鍵菜單

選中物體(橙色輪廓)(Inspector顯示該物體組件屬性)

  • Scene 窗口選中
  • Hierarchy 窗口選中 (物體重疊時

重命名、刪除物體

  • Hierarchy 窗口選中右鍵菜單 Rename | Delete

移動物體

  • Move Tool

3.3 ?3D視圖

視圖內容

  • Gizmo 導航器 :表示世界坐標方向
  • Grid 柵格 : 表示 XZ 坐標平面(可隱藏、配置)
    • 柵格1格長度代表1個單位,尺寸單位約定為1米
  • Skybox 天空盒(可隱藏)

視圖操作

  • 旋轉 ALT + LMB
  • 縮放 鼠標滾輪、ALT + RMB(精細)
  • 平移 MMB

導航器操作 Gizmo

  • 恢復y軸方向:SHIFT+點擊小方塊
  • 頂視圖:點擊任意軸 (小方塊右鍵菜單)

3.4 世界坐標系

左手坐標系,當x軸向右,y軸向上,z軸向里


3.5 ?視圖中心

視圖旋轉默認按視圖中心點旋轉

  • 繞一個物體旋轉,需要選中物體后按 F 鍵(層級窗口雙擊物體),視圖中心設置為該物體坐標原點,然后 ALT + LMB 旋轉
  • 添加一個新物體,物體位于視圖中心,而不是 {0,0,0}

3.6 透視與正交

  • Perspective 透視視圖
    • 物體近大遠小
    • 透視畸(ji)變:圓球在角落看起來像橢圓
      • 調小Field of view(廣角設定)減少畸變
  • Orthographic 正交視圖(Isometric 等距視圖)
    • 物體大小與距離無關
    • 常用于物體的布局、對齊操作

4.2 ?物體操作

可以在 Inspector 窗口拖動 X Y Z

  • Move tool 移動工具(W):沿著坐標軸、坐標平面移動
  • Rotate tool 旋轉工具(E)
    • 朝XYZ軸方向旋轉,逆時針為正,順時針為負。反之相反
    • 按住 CTRL 旋轉,按 15 度增量旋轉(可修改)
  • Scale tool 縮放工具(R):沿著軸向、整體縮放

操作模式

  • Pivot 軸心 | Center 中心點
  • Global 世界坐標系 | Local 局部坐標系

更多操作

  • 多選(層級窗口,視圖窗口鼠標拉框)、復制(CTRL + D)
  • 激活 Active :檢查器里第一個勾選項

嘗試小插件

主要涉及單c#文件插件(切換視圖快捷功能)的安裝與使用

  • 拖拽進入資源窗口后自動編譯
  • AF插件:G 鍵的視圖中心與F鍵不同,不會放大框顯

5.1 ?網(wǎng)格

Mesh,存儲了模型的形狀數(shù)據(jù)

  • 模型形狀由若干個小面圍合而成,內部都是中空的
  • Mesh 中包含了 面、頂點坐標、面的法向 等數(shù)據(jù)

Unity中觀察模型網(wǎng)格(場景窗口右側欄,2D按鈕左邊)

  • shaded 著色模式,顯示表面材質
  • wireframe 線框
  • shaded wireframe 線框著色(兩個都顯示)

高模:面數(shù)越多,物體表面越精細,GPU負擔也就越重

mesh filter 組件定義網(wǎng)格數(shù)據(jù)


5.2 ?材質

Material 定義物體的表面細節(jié)(顏色,金屬,透明,凹陷,突起)

創(chuàng)建、使用材質

  1. 在資源目錄下創(chuàng)建 Material
  2. 修改阿貝多albedo為藍色(反射率)
  3. 選中物體,把材質拖到物體上

mesh renderer 組件負責渲染,使用材質相當于修改該組件的 Materials 字段,可直接拖動材質到該字段或打開材質瀏覽器。 (檢查器窗口右上角可鎖定)


5.3 ?紋理(貼圖)

用一張圖定義物體的表面顏色。模型每個面有不同顏色,與貼圖映射,在建模軟件里完成

將貼圖拖動至 albedo,可以看到疊加的效果(反射率改為白色),按 BackSpace 清掉貼圖

建模師提供的模型,本身已經(jīng)帶了網(wǎng)格、表面材質、材質貼圖


5.5 ?更多細節(jié)

  • Unity 平面(plane)是沒有厚度的;正面可見,背面透明;從正方體從內部觀察,六個面都是透明的
  • 添加物體默認都是有材質的 Default-Material (引擎內部自帶),呈現(xiàn)紫紅色說明沒材質

5.6 ?FBX

模型資源

FBX模型一般包含 mesh(定義形狀),material(定義光學特性),texture(定義表面像素顏色),有的模型可能定義多個材質。將FBX模型拖動至窗口中生成對象(FBX本身也是一種預制體

貼圖文件的路徑是約定好的,與fbx相同目錄,或者同級 Textures 目錄


材質替換(重映射)

  • 在檢查器窗口找到材質屬性 | Use Embeded Materials | On Demand Remap
  • 使用外部材質:材質屬性 | Location | Use External Materials | 修改解壓的材質

分解重組

  • FBX里的Mesh單獨拖出生成對象,然后給定材質(也可從FBX單獨拖出)

6.1 ?資源文件

復制資源 CTRL + D

  • 模型文件 .fbx
  • 圖片文件 .jpg、.png、.psd、.tif
  • 音頻文件 .mp3、.wav、.aiff
  • 腳本文件 .cs
  • 材質文件 .mat
  • 場景文件 .unity (記錄物體檢查器數(shù)據(jù))(1個場景等于1個關卡)
  • 描述文件 .meta (每個文件都有)

除此之外,可將選擇的文件導出成資源包 .unitypackage ,導出時可把依賴文件一并導出。再通過 .unitypackage 導入 (整個Assets目錄也可以導出)


7.1 軸心、幾何中心

Pivot 物體操縱基準點,可以在任意位置,軸心點是在建模軟件中指定的,可以用空物體當父節(jié)點修改原軸心

Center 幾何中心點,一個物體繞中心點旋轉(炮塔例子)。多個物體則是物體合體之后的中心點


7.2 ?父子關系

在 Hierarchy 窗口呈現(xiàn)兩個物體之間的關系(拖物體B到物體A下)

  • 子物體會隨著父物體移動旋轉(子物體相對坐標不會變化)
  • 刪除父物體,子物體一并刪除

相對坐標:子物體坐標相對于父物體(子物體坐標等于相對坐標+父節(jié)點坐標)


7.3 空物體

  • Create Empty
  • 場景內不可見(無網(wǎng)格信息),但有transform組件
  • 用于節(jié)點的組織、管理(武器站 + 炮塔)(修改軸心);標記位置

7.4 ?Global、Local

  • Global,世界坐標系:上下、東西、南北
  • Local,本地坐標系:上下、前后、左右 (物體自身為軸)(小車沿車頭前進)
  • y 軸 up、z 軸 forward (模型正臉方向與z軸方向一般一致)、x軸 right

8.1 ?組件

物體節(jié)點可綁定多個組件(component ),一個組件代表一個功能

如 Mesh Filter 網(wǎng)格過濾器(加載Mesh);Mesh Renderer 網(wǎng)格渲染器(渲染Mesh)


Transform 所有物體都有、不能被刪除(基礎組件)

  • 位置(相對位置);旋轉(歐拉角);縮放

8.5 ?攝像機

  • Z軸為拍攝方向
  • 擺放攝像機:選中節(jié)點 | GameObject | Align with View 對齊視角(CTRL+SHIFT+F),將攝像機視角變?yōu)楫斍皥鼍按翱谝暯?/strong>

9.1 ?腳本

腳本組件

腳本組件,游戲驅動邏輯,類名和文件名需要一致。編譯過程是自動的

只有掛載腳本才能被調用:物體節(jié)點添加組件、拖動到檢查器窗口下面

腳本類繼承自 MonoBehaviour


獲取物體

  • this 當前腳本組件對象
  • this.gameObject 當前物體
  • this.gameObject.name 當前物體名字(利用獲取到的物體對象獲取其他屬性)
  • this.gameObject.transform 獲取 transform 組件(簡化為this.transform
GameObject obj = this.gameObject;
string objName = obj.name;
Debug.Log(objName);

Transform tr = this.transform; // this.gameObject.transform
Vector3 pos = tr.position;
Debug.Log(pos);

物體坐標

一般常使用 localPosition ,與檢查器中的值一致

  • 世界坐標值 this.transform.position
  • 本地坐標值 this.transform.localPosition

修改本地坐標

this.transform.localPosition = new Vector3(0f, 0f, 3.5f);

移動物體

建議先看 10.1 幀更新

不使用 Time.deltaTime 來移動物體是不勻速的(因為時間增量不同)

正確移動方法是 速度 * 時間(每秒走固定米數(shù),每幀移動距離不同)

  void Update()
  {
    Vector3 pos = this.transform.localPosition;
    pos.z += Time.deltaTime * 10f;
    this.transform.localPosition = pos;
  }

9.4 播放模式

  • 編輯模式
  • 播放(運行)模式:更改不保存,相當于實時調試,實時修改參數(shù)并生效
    • 把修改好參數(shù)的組件 | Copy Component | 退出播放 | Paste Component Values

10.1?幀更新

  • Frame 游戲幀
  • FrameRate 幀率/刷新率
  • FPS(Frames Per Second) 每秒更新多少幀

Update(幀更新):每幀調用一次

  • Time.time 游戲時間(游戲啟動后開始計時)
  • Time.deltaTime 距上次幀更新的時間差(時間增量)

Unity 不支持固定幀率,但可以設置一個近似幀率 Application.targetFrameRate = 60;


11.1?物體運動

物體移動

使用 transform.Translate(dx,dy,dz) 實現(xiàn)相對運動(參數(shù)是坐標增量)

可以添加第四個參數(shù)即 transform.Translate(dx,dy,dz,space)

  • Space.World 世界坐標系
  • Space.Self 本地坐標系(默認)(更常用)

物體方向

GameObject.Find("Sphere") 根據(jù)名字、路徑查找物體

this.transform.LookAt(flag.transform) 將物體 Z 軸轉向某一位置,然后每幀沿著 forward 方向按 2m/s 速度前進

  void Start()
  {
    GameObject flag = GameObject.Find("Sphere");
    this.transform.LookAt(flag.transform);
  }
  void Update()
  {
    float speed = 2f;
    float distance = speed * Time.deltaTime;
    this.transform.Translate(0,0,distance,Space.Self);
  }

兩物體間距

Vector3 的 magnitude 屬性表示向量長度

    Vector3 p1 = this.transform.position;
    Vector3 p2 = flag.transform.position;
    Vector3 p = p2 - p1;
    float distance = p.magnitude;

物體移動到另一物體停止移動

 private GameObject flag;
  void Start()
  {
    flag = GameObject.Find("Sphere");
    this.transform.LookAt(flag.transform);
  }
  void Update()
  {
    Vector3 p1 = this.transform.position;
    Vector3 p2 = flag.transform.position;
    Vector3 p = p2 - p1;
    float distance = p.magnitude;
    if (distance > 0.3f)
    {
      float speed = 2f;
      float dis = speed * Time.deltaTime;
      this.transform.Translate(0,0,dis,Space.Self);
    }
  }

攝像機跟隨物體

選擇物體,Edit | Lock View to Selected (SHIFT + F)


12.1?物體旋轉

Quaternion 四元組

transform.rotation 不便操作,不建議使用

Euler Angle 歐拉角

  • transform.eulerAngles
  • transform.LocalEulerAngles
this.transform.localEulerAngles = new Vector3(0, 30, 0);

Vector3 angles = this.transform.localEulerAngles;
angles.y += 30 * Time.deltaTime;
this.transform.localEulerAngles = angles;

? transform.Rotate(dx,dy,dz,space)Translate 使用方式類似

? 實現(xiàn)公轉:父物體帶動子物體旋轉


13.1 腳本運行

場景加載過程(框架自動完成)

  1. 創(chuàng)建節(jié)點(游戲物體)
  2. 實例化各個節(jié)點的組件(包括腳本組件)| 等同 new 類()
  3. 調用各個組件事件函數(shù)

13.2 消息函數(shù)

屬于 MonoBehaviour (統(tǒng)一行為特性類)的消息函數(shù)(事件函數(shù)、回調函數(shù))

已被禁用的物體 Start / Update 不會被調用,Awake / Start 方法只會被執(zhí)行一次

  • Awake 第一階段初始化(總是會被調用)
  • Start 第二階段初始化(組件被禁用不調用)
  • Update 幀更新
  • OnEnable 當組件啟用時調用
  • OnDisable 當組件禁用時調用

?? Awake 總被調用是根據(jù)當前腳本組件的啟用、禁用狀態(tài)來說的,而不是根據(jù)整個物體節(jié)點的生效、不生效狀態(tài),物體節(jié)點如果不生效 Awake 不會被調用

另外,如果腳本組件只有一個 Awake 方法,那么腳本組件的啟用、禁用也就沒有意義,Unity不為它添加勾選框


13.3 腳本執(zhí)行順序

  1. 第一階段初始化(所有腳本)
  2. 第二階段初始化(所有腳本)
  3. 幀更新(所有腳本)

腳本執(zhí)行順序與層級擺放順序無關系,默認所有腳本的執(zhí)行優(yōu)先級為 0

  • 選中腳本,打開 Execution Order 對話框
  • 添加腳本,值越小,優(yōu)先級越高

13.4 主控腳本

一個空節(jié)點掛載游戲全局設置的腳本(高優(yōu)先級)


14.1?參數(shù)與特性

公有類成員變量:讓開發(fā)者自定義參數(shù)從而控制腳本組件功能

添加特性,為參數(shù)添加編輯器提示

[Tooltip("這個是Y軸的角速度")]

14.2 初始化順序

檢查器參數(shù)、Awake、Start 都對某一參數(shù)初始化時的調用順序

  1. 腳本組件實例化(檢查器參數(shù))(默認值
  2. Awake 修改了參數(shù)
  3. Start 修改了參數(shù)(最終的值

個人認為可以在 Awake、Start 對參數(shù)進行驗證操作


14.3 值類型

基類類型、Vector3、Color 都是結構體值類型

值類型特點

  • 直接賦值
  • 沒值,則默認 0
  • 可空值類型可為 null(個人測試,該類型不顯示在檢查器上)

14.4 引用類型

節(jié)點、組件、資源、數(shù)組類型

public GameObject flag;

15.1?輸入

鼠標輸入

在幀更新方法添加,前兩方法針對一次鼠標事件只會True一次(成對關系),第三個方法多次True

兩個鼠標事件是全局的,腳本之間互不影響

  • Input.GetMouseButtonDown(int) 按下事件
    • 0 左鍵、1 右鍵、2 中鍵
  • Input.GetMounseButtonUp(int) 抬起事件
  • Input.GetMouseButton(int) 鼠標狀態(tài),表示當前鍵否正在被按下

屏幕坐標

獲取屏幕長寬

private void Start()
{
    int width = Screen.width;
    int height = Screen.height;
    Debug.Log($"{width} , {height}");
}

獲取屏幕坐標

Input.mousePosition 僅X、Y有值,屏幕左下角為原點,單位為像素

if (Input.GetMouseButtonDown(0))
{
    Vector3 mousePos = Input.mousePosition;
    Debug.Log(mousePos);
}

物體世界坐標轉屏幕坐標

用于判斷物體是否超出屏幕范圍(出界是物體軸心點出界,是能看到物體剩余部分的

Camera.main.WorldToScreenPoint(pos)

X,Y是物體在屏幕的哪個位置,Z是物體距離攝像機的距離

Vector3 pos = this.transform.position;
Vector3 screenPos = Camera.main.WorldToScreenPoint(pos);
if (screenPos.x < 0 || screenPos.x > Screen.width) // 左右邊
{
    Debug.Log("出界了");
}

鍵盤輸入

與鼠標輸入類似

  • Input.GetKeyDown(keycode) 按下事件
  • Input.GetKeyUp(keycode) 抬起事件
  • Input.GetKey(keycode) 按鍵狀態(tài)
    • KeyCode.A 常量看官方文檔

16.1?組件調用

代碼操控組件

將代碼組件與音樂組件放至同節(jié)點(順序無影響) ;this.GetComponent<AudioSource>() 獲取AudioSource組件

void Update()
{
    if (Input.GetMouseButtonDown(0))
        PlayMusic();
}

void PlayMusic()
{
    AudioSource audio = this.GetComponent<AudioSource>();
    if (audio.isPlaying)
        audio.Stop();
    else audio.Play(); 
}

組件引用

情景:用主控腳本控制背景音樂空節(jié)點音樂組件的播放

不常用方法:在檢查器設置節(jié)點引用,腳本通過物體節(jié)點獲得組件

public GameObject bgmNode;
void Update()
{
    if (Input.GetMouseButtonDown(0))
        PlayMusic();
}
void PlayMusic()
{
    AudioSource audio = bgmNode.GetComponent<AudioSource>();
    if (audio.isPlaying)
        audio.Stop();
    else audio.Play();
}

常用方法:在檢查器里設置組件引用,腳本直接訪問該組件

public AudioSource bgmComponent;
void Update()
{
    if (Input.GetMouseButtonDown(0))
        PlayMusic();
}
void PlayMusic()
{
    AudioSource audio = bgmComponent;
    if (audio.isPlaying)
        audio.Stop();
    else audio.Play();
}

  • **this.GetComponent<T>() **獲取當前物體下的組件
  • xxx.GetComponent<T>() 獲取其他物體下的組件

個人理解每個組件類都有 GetComponent<T> 泛型實例方法,用于獲取當前綁定的節(jié)點的各個組件


代碼組件引用

情景:用一個腳本組件控制另一個腳本組件公開字段,如修改轉速

可以是API獲取,通過物體節(jié)點再獲取腳本組件類型,也可以直接引用,下面是直接引用做法(Unity框架自動完成組件查找過程)

public class InputLogic : MonoBehaviour
{
    public FanLogic fan;
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            fan.rotateY = 90f;
        }
    }
}

public class FanLogic : MonoBehaviour
{
    public float rotateY;
    void Update()
    {
        this.transform.Rotate(0,rotateY * Time.deltaTime,0,Space.Self);
    }
}

消息調用

該方法利用反射機制,效率低,不常用,用于調用其他物體中組件的方法

  • 找到目標節(jié)點
  • 向目標節(jié)點發(fā)送“消息"(字符串,函數(shù)名字)

執(zhí)行過程

  1. 找到節(jié)點綁定的所有組件
  2. 在所有組件下尋找方法名對應的方法,找到就執(zhí)行,找不到就報錯
public class FanLogic : MonoBehaviour
{
    public float rotateY;
    void Update()
    {
        this.transform.Rotate(0,rotateY * Time.deltaTime,0,Space.Self);
    }

    void DoRotate()
    {
        rotateY = 90f;
    }
}

public class InputLogic : MonoBehaviour
{
    public GameObject fanNode;
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            fanNode.SendMessage("DoRotate");
        }
    }
}

練習、無人機

邏輯很簡單,主控節(jié)點引用兩個腳本組件,然后根據(jù)輸入修改這兩個腳本組件的狀態(tài);代碼中通過調用各個組件的公開實例方法來修改字段成員

public class RotateLogic : MonoBehaviour
{
    float m_rotateSpeed;
    void Update() =>
        this.transform.Rotate(0, m_rotateSpeed * Time.deltaTime, 0, Space.Self);
    public void DoRotate() => m_rotateSpeed = 360*3;
    public void DoStop() => m_rotateSpeed = 0;
}

public class FlyLogic : MonoBehaviour
{
    float m_speed = 0;
    void Update()
    {
        float height = this.transform.position.y;
        float dy = m_speed * Time.deltaTime;

        if( dy > 0 && height < 4 )
            this.transform.Translate(0, dy, 0, Space.Self);
        else if ( dy < 0 && height > 0)
            this.transform.Translate(0, dy, 0, Space.Self);
    }

    public void Fly ()=> m_speed = 1;
    public void Land() => m_speed = -1;
}

public class MainLogic : MonoBehaviour
{
    public RotateLogic rotateLogic;
    public FlyLogic flyLogic;

    void Start()
    {
        Application.targetFrameRate = 60;
        rotateLogic.DoRotate();
    }

    void Update()
    {
        if(Input.GetKey(KeyCode.W))
            flyLogic.Fly();
        else if (Input.GetKey(KeyCode.S))
            flyLogic.Land();
    }
 }

17.1?節(jié)點操作

名稱查找節(jié)點

效率低,不適應變化;如果有父節(jié)點最好指定一下路徑;不存在返回null;不常用,通常用公開字段引用對象的方法;查找的是生效節(jié)點,不生效節(jié)點不納入查找范圍

void Start()
{
    GameObject node = GameObject.Find("無人機/旋翼");
    RotateLogic rl = node.GetComponent<RotateLogic>();
    rl.DoRotate();
}

?? 如果在最前面加/ 表示從根目錄開始查找


查找父級

父子級關系由 Transform 維持

  1. 獲取父級Transform,
  2. 通過父級Transform獲取父級GameObject
  3. 打印父節(jié)點名字
void Start()
{
    Transform parent = this.transform.parent;
    GameObject parentNode = parent.gameObject;
    Debug.Log(parentNode.name); // 等同 transform.name 
}

查找子級

transform 實現(xiàn)了迭代器接口可以被 foreach 遍歷,拿到多個子節(jié)點

void Start()
{
    foreach (Transform child in transform)
    {
        Debug.Log(child.name);
    }
}

也可通過 getChild(int) 索引獲取,下標從 0 開始。下面獲取第二個子節(jié)點transform,不存在返回null

Debug.Log(transform.GetChild(2).name);
Debug.Log(transform.GetChild(2) is Transform);

名稱查找子級

用法與名稱查找節(jié)點類似;不存在返回null;與名稱查找節(jié)點不同的是子級節(jié)點不生效,transform也能被查找到

void Start()
{
    Transform t = transform.Find("旋翼 (1)/旋翼 (2)");
    if (t is null) Debug.Log("Nothing found");
    else
        Debug.Log(t.name);
}

設置父級

transform組件實例方法 SetParent(node) 設置當前transform的父級,如果傳入null則無父節(jié)點(根目錄節(jié)點)

void Start()
{
    Transform node = transform.Find("/aa");
    transform.SetParent(node);
}

設置生效

生效與不生效;也相當于顯示與隱藏;個人理解為(啟用當前全部組件,禁用當前全部組件)

GameObject 類型實例的實例方法 SetActive;修改自身節(jié)點是否生效

void Start()
{
    var obj = transform.gameObject;
    Debug.Log(obj.activeSelf);
    obj.SetActive(false);
    Debug.Log(obj.activeSelf);
}

當前節(jié)點修改其他節(jié)點是否生效

private GameObject obj;

private void Start() =>
    obj = GameObject.Find("aa");

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        Debug.Log(obj.activeSelf);
        obj.SetActive(!obj.activeSelf);
        Debug.Log(obj.activeSelf);
    }
}

修改子節(jié)點是否生效

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        GameObject obj = transform.Find("dd").gameObject;
        Debug.Log(obj.activeSelf);
        obj.SetActive(!obj.activeSelf);
        Debug.Log(obj.activeSelf);
    }
}

練習、俄羅斯方塊

private int index = 0;

private void Start()
{
    foreach (Transform child in transform)
        child.gameObject.SetActive(false);    
    transform.GetChild(index).gameObject.SetActive(true);
}

private void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))ChangeShape();
}

private void ChangeShape()
{
    transform.GetChild(index).gameObject.SetActive(false);
    index = (index + 1) % transform.childCount;
    transform.GetChild(index).gameObject.SetActive(true);
}

18.1?資源使用

資源引用

情景:掛一個AudioSource(音頻播放)組件,不指定音頻AudioClip(音頻容器類);要求利用腳本指定播放的資源

注意:在使用 PlayOneShot 實例方法的情況下,音頻播放組件的 clip 字段并沒有被設定

public AudioClip bgm;

private void Start()
{
    var audioSource = GetComponent<AudioSource>();
    // audioSource.clip = bgm;
    // audioSource.Play();
    audioSource.PlayOneShot(bgm);
}

列表引用

情景:掛一個AudioSource組件,不指定音頻AudioClip;要求利用腳本隨機播放幾首歌曲里的一首;

public AudioClip[] bgms;
private void Start()
{
    if (bgms.Length == 0)
        Debug.Log("我歌呢");
    var audioSource = GetComponent<AudioSource>();
    // audioSource.PlayOneShot(bgms[Random.Range(0,bgms.Length)]);
    audioSource.clip = bgms[Random.Range(0, bgms.Length)];
    audioSource.Play();
    Debug.Log(audioSource.clip.name);
}

練習、三色球

直接修改顏色也可以直接修改Albedo的顏色(超出入門范疇)

public Material[] ms;
private int index = 0;
private void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        index = (index + 1) % ms.Length;
        Material m = ms[index];
        MeshRenderer mr = GetComponent<MeshRenderer>();
        mr.material = m;
    }
}

19.1?定時調用

延遲調用

繼承了 MonoBehaviour;利用了反射;delay、interval 是秒不是毫秒

  • Invoke(string func,float delay) 只調用一次
  • InvokeRepeating(string func,float delay,float interval) 首次執(zhí)行后循環(huán)調用
  • IsInvoking(func) 是否在調度隊列中
  • CancelInvoke(func) 取消調用、從調度隊列中移除

注意:每次 InvokeRepeating,都會添加一個新的調度(加到調度隊列),然后大循環(huán)每次循環(huán)遍歷調度隊列

private void Start()
{
    // Invoke("DoSomething",1);
    InvokeRepeating("DoSomething",1,2);
}

void DoSomething() =>
    Debug.Log("HELLO WORLD " + Time.time);

單線程引擎

Unity 引擎核心是單線程的

private void Start()
{
    Debug.Log(Thread.CurrentThread.ManagedThreadId);
    InvokeRepeating("DoSomething",1,2);
}

private void Update()
{
    Debug.Log(Thread.CurrentThread.ManagedThreadId);
}

void DoSomething() =>
    Debug.Log(Thread.CurrentThread.ManagedThreadId);

終止調度

調用一次 CancelInvoke(string func) 終止了兩個同函數(shù)的調度;全部都取消不用加參數(shù)

private static int COUNT = 1;
private void Start()
{
    InvokeRepeating("DoSomething",1,2);
    InvokeRepeating("DoSomething",1,2);
}

private void Update()
{
    if (Time.time > 10)
        if (IsInvoking("DoSomething"))
        {
            CancelInvoke("DoSomething");
            Debug.Log("調度被終止了");
        }
}

void DoSomething()
{
    int i = COUNT++;
    Debug.Log($"我是任務 {i}");
}

練習、紅綠燈

public Material[] colors;
private int index = 0;

private void Start()
{
    Invoke("ChangeColor",0);
}

void ChangeColor()
{
    GetComponent<MeshRenderer>().material = colors[index];
    index = (index + 1) % colors.Length;
    if (index == 1)
        Invoke("ChangeColor", 3);
    else if(index == 2)
        Invoke("ChangeColor", 0.5f);
    else 
        Invoke("ChangeColor", 3);
}

練習、加速減速

public float speedY = 0f;
private int control = 1;

private void Start()
{
    InvokeRepeating("SpeedControl",0,0.1f);
}

void Update()
{
    transform.Rotate(0,speedY * Time.deltaTime,0,Space.Self);
    if (Input.GetMouseButtonDown(0))
        control = -control;
}

void SpeedControl()
{
    speedY = speedY + 10f * control;
    speedY = speedY > 180 ? 180 : speedY;
    speedY = speedY < 0 ? 0 : speedY;
}

20.1?Vector3

特性

Vector3 是結構體,里面有三個字段 x,y,z,向量是有方向的量,有長度

  • v.magnitude 長度(模長)
  • v.normalized 單位向量標準化(長度為1的向量是單位向量)
    • 向量的每個分量都除以向量的模長
  • 常用靜態(tài)常量有很多
    • Vector3.zero (0,0,0)
    • Vector3.up (0,1,0)
    • Vector3.right (1,0,0)
    • Vector3.forward (0,0,1)

  • 向量有加減運算(初中知識)
  • 向量有乘法運算

    • 標量乘法:放大倍數(shù)
    • 點積:Vector3.Dot(a,b)
    • 叉積:Vector3.Cross(a,b)
  • 不可空值類型不能被設置為 null,可以留空不寫,即默認值 0,0,0

public Vector3 speed; // = null;  EXCEPTION

測距

物體之間的距離,確切的說是軸心點之間的距離

  • 向量相減然后求距離
  • 或直接用 Vector3.Distance(Vector3 a,Vector3 b)
public GameObject a;
public GameObject b;
private void Start()
{
    Vector3 apos = a.transform.position,bpos = b.transform.position;
   float disc = Vector3.Distance(apos, bpos);
   Debug.Log(disc);
   Debug.Log((apos-bpos).magnitude);
}

物體運動方向

讓一個物體沿著某一方向運動(Translate 有多個函數(shù)重載方法)

public Vector3 speed;
private void Update()
{
    transform.Translate(speed * Time.deltaTime,Space.Self);
}

21.1?預制體

創(chuàng)建

預先制作好的物體節(jié)點(模板),*.prefab

樣本節(jié)點做好后,拖到資源目錄下,會生成預制體文件。原始樣本節(jié)點可以刪除

prefab 文件只記錄了節(jié)點的信息;不包含材質、貼圖數(shù)據(jù),僅包含引用(導出時會將依賴一并導出)


實例

  • 預制體生成的節(jié)點實例在層級窗口是藍色
  • 右鍵菜單有預制體相選項 | 檢查器窗口上面有預制體相關選項
  • 預制體生成的節(jié)點實例可以Unpack斷開與預制體的鏈接,后續(xù)預制體的修改不會影響該節(jié)點

編輯

  • 單獨編輯
    • 雙擊預制體 | 點擊 Scenes 或返回箭頭退出
  • 原位編輯
    • 選擇預制體實例節(jié)點,點擊層級管理器右側箭頭或檢查器上的Open,此時僅選中的物體被編輯,其余物體是陪襯 | 點擊返回箭頭退出
    • 有 normal/gray/hidden 三種顯示模式
  • 覆蓋編輯
    • 修改預制體實例節(jié)點后,點擊檢查器上的 Overrides | 這個操作也可以撤銷節(jié)點修改

22.1?動態(tài)創(chuàng)建實例

UnityEngine.Object.Instantiate(Object perfab,Transform parent) 有多個重載版本

創(chuàng)建預制體實例后,應做初始化

  • parent 父節(jié)點(方便管理控制)
  • position 、localPosition 位置
  • eulerAngles / localEulerAngles 旋轉
  • Script 自帶的腳本組件
public GameObject bulletPrefeb;
public GameObject bulletFolder;
public GameObject Canno;
private void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        GameObject obj = Instantiate(bulletPrefeb, null);
        obj.transform.SetParent(bulletFolder.transform);
        obj.transform.position = transform.position;
        obj.transform.eulerAngles = Canno.transform.eulerAngles;
        // obj.transform.rotation = Canno.transform.rotation;
        obj.GetComponent<BulletLogic>().speed = 0.5f;
    }
}

22.3?銷毀實例

比如 22.1 的子彈案例

  • 飛出屏幕,銷毀
  • 按射程、飛行時間銷毀
  • 擊中目標,銷毀

UnityEngine.Object.Destroy(GameObject obj)

  • 不要寫成 Destroy(this) ,這相當于刪除當前組件
  • Destroy不會立即執(zhí);即創(chuàng)建出來實例的Start方法在Update執(zhí)行完后才會執(zhí)行 ?
public class BulletLogic : MonoBehaviour
{
    public float speed;
    public float maxDistance;
    void Start()
    {
        Debug.Log("Start Start");
        float lifetime = 1;
        if (speed > 0) lifetime = maxDistance / speed;
        Destroy(gameObject,lifetime);
        Debug.Log("Start Finish");
    }

    void Update() =>
        this.transform.Translate(0, 0, speed, Space.Self);
}

public class SimpleLogic : MonoBehaviour
{
    public GameObject bulletPrefeb;
    public GameObject bulletFolder;
    public GameObject Canno;
    public float speed = 0.5f;
    public float flyTime = 2f;
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            GameObject obj = Instantiate(bulletPrefeb, null);
            Debug.Log("Instantiate Start");
            obj.transform.SetParent(bulletFolder.transform);
            obj.transform.position = transform.position;
            obj.transform.eulerAngles = Canno.transform.eulerAngles;
            // obj.transform.rotation = Canno.transform.rotation;
            obj.GetComponent<BulletLogic>().speed = speed;
            obj.GetComponent<BulletLogic>().maxDistance = speed * flyTime;
            Debug.Log("Instantiate Finish");
        }
    }

練習?炮口旋轉

官方建議不要獲取對象歐拉角再覆蓋歐拉角,涉及轉換的一些問題

而是固定用一個Vector3當做對象的歐拉角

private Vector3 _eulerAngles;
public float rotateSpeed = 30f;
public GameObject Canno;
void Update()
{
    float delta = rotateSpeed * Time.deltaTime;
    if (Input.GetKey(KeyCode.W))
        if (_eulerAngles.x > -60)
            _eulerAngles.x -= delta;
    if (Input.GetKey(KeyCode.S))
        if (_eulerAngles.x < 30)
            _eulerAngles.x += delta;
    if (Input.GetKey(KeyCode.A))
        _eulerAngles.y -= delta;
    if (Input.GetKey(KeyCode.D))
        _eulerAngles.y += delta;
    Canno.transform.localEulerAngles = _eulerAngles;
}

23.1?簡單物理

剛體與碰撞體

剛體 RigidBody

使物體具有物理學特性。添加剛體組件后由物理引擎負責剛體的運動

碰撞體組件 Collider

設置物體的碰撞體積范圍。也由物理引擎負責

默認添加的碰撞體一般情況下會根據(jù)網(wǎng)格自動設置尺寸,可以另外編輯


反彈與摩擦

通過物理材質,設置一些參數(shù)后將該物理材質賦給碰撞體組件的物理材質引用


運動學剛體

RigidBody 組件參數(shù) Is Kinematic 打勾,此時為運動學剛體

?零質量,不會受重力影響,但可以設置速度來移動;這種運動剛體完全由腳本控制


碰撞檢測 ?

需滿足以下兩個條件

  • 物體是運動剛體
  • 碰撞體開啟了 Is Trigger

  • 物理引擎只負責探測(Trigger),不會阻止物體或者反彈
  • 物理引擎計算的是 Collider 之間的碰撞,和物體自身形狀無關
  • 當檢測到碰撞時,調用當前節(jié)點多個事件消息函數(shù),如 OnTriggerEnter
public Vector3 speed;
void Update() =>
    transform.Translate(speed * Time.deltaTime,Space.Self);

private void OnTriggerEnter(Collider other)
{
    Debug.Log("發(fā)生碰撞");
    Debug.Log(other.name);
}

練習、子彈銷毀物體

給子彈添加如下代碼

private void OnTriggerEnter(Collider other)
{
    Debug.Log(other.name);
    Destroy(other.gameObject);
    Destroy(gameObject);
}

25.1?射擊游戲

天空盒

Window | Rendering | Lighting (CTRL + 9)


子彈

public class BulletLogic : MonoBehaviour
{
    public float speed = 1f;

    void Update()
    {
        transform.Translate(0,0,speed * Time.deltaTime,Space.Self);
    }
    private void OnTriggerEnter(Collider other)
    {
        if (!other.name.StartsWith("怪獸")) return;
        Destroy(other.gameObject);
        Destroy(gameObject);
    }
}

發(fā)射與移動

public class PlayerLogic : MonoBehaviour
{
    public GameObject bulletPrefeb;
    public GameObject bulletFolder;
    public Transform firePos;
    public Transform fireEulerAngles;
    public float speed = 15f;
    public float lifeTime = 3f;
    public float interval = 2f;
    private float _interval = 2f;
    public float moveSpeed = 15f;
    private void Update()
    {
        _interval += Time.deltaTime;
        if (Input.GetMouseButtonDown(0) && _interval > interval)
        {
            _interval = 0f;
            GameObject obj = Instantiate(bulletPrefeb, null);
            obj.transform.SetParent(bulletFolder.transform);
            obj.transform.position = firePos.position;
            obj.transform.eulerAngles = fireEulerAngles.eulerAngles;
            obj.GetComponent<BulletLogic>().speed = speed;
            obj.GetComponent<BulletLogic>().lifeTime = lifeTime;
        }
        if(Input.GetKey(KeyCode.A))
            transform.Translate(-Time.deltaTime * moveSpeed,0,0,Space.Self);
        if(Input.GetKey(KeyCode.D))
            transform.Translate(Time.deltaTime * moveSpeed,0,0,Space.Self);
    }
}

怪獸生成器

public class CreatorLogic : MonoBehaviour
{
    public GameObject enemyPrefeb;
    void Start()
    {
        InvokeRepeating("CreateEnemy",1f,1f);
    }

    void CreateEnemy()
    {
        GameObject obj = Instantiate(enemyPrefeb,transform);
        var pos = transform.position;
        pos.x += Random.Range(-30, 30);
        obj.transform.position = pos;
        obj.transform.eulerAngles = new Vector3(0, 180, 0);
    }
}

添加爆炸特效

public GameObject explosionPrefeb;    
...
private void OnTriggerEnter(Collider other)
{
    if (!other.name.StartsWith("怪獸")) return;
    Destroy(other.gameObject);
    Destroy(gameObject);
    GameObject obj = Instantiate(explosionPrefeb, null); // 不要掛載子彈節(jié)點下面
    // 粒子特效播放完會自毀
    obj.transform.position = transform.position;
}

資源參考

Unity Documentation 、B站 阿發(fā)你好 入門視頻教程文章來源地址http://www.zghlxwxcb.cn/news/detail-707887.html

到了這里,關于Unity 游戲開發(fā)、01 基礎篇 | 知識大全、簡單功能腳本實現(xiàn)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包