Unity

講師:sleepyboy
  • 廢話可能會很多
  • 新北市板橋區最強 DJ(16歲)
  • 邊看教學邊備課
這我
↘ 我本人 
# 講師介紹

1.

2.

3.

# 目錄
目錄局
# 遊戲物件
 遊戲物件
  • GameObject & Component
  • Sprite & Sprite Renderer
    
  • Transform
# 遊戲物件
  •  Conponent

這個格子可以控制Conponent的啟用與否

可以把他想像成 GameObject 的功能

將游標移到值為數字的屬性上會出現雙箭頭,可以左右拖動直接調整數值

# 遊戲物件
  •  Conponent

回復初始設置

快速移動屬性順序至最前/後

複製Conponent

以新增的方式貼上

以參數覆蓋的方式貼上

移除Conponent

可以用拖的

略過

# 遊戲物件
  •  GameObject
一個GameObject盡量不要加種類相同的兩個Component,腦子會破掉

BUT

那如果我希望兩個物件一起移動,但又有不同的功能備分開操控如:角色和他的武器,要怎麼處理?
# 遊戲物件
  •  GameObject
創建子物件!
  1. 在 Hierachy 選定一個父物件(這個群組的頭領)然後把子物件選取向父物件拖曳
  2. 類似 Canva 的群組,子物件會和父物件一起移動
  3. 如果子物件被停用,不會停用父物件。但父物件被停用,子物件會被停用
# 遊戲物件
  •  GameObject
原理:將子物件的位置改成與父物件的相對位置

 

例如,當子物件的LocalPosition(相對於父物件,會顯示於Inspector上)為(-5,9,0),父物件的Position為(6,15,0)

則子物件的實際位置為(1,24,0)

# 遊戲物件
  •  Sprite 
  1. Sprite 是一個將多圖層/圖像整合在一個2D平面上的技術
    
    
  2. 因為這樣的圖像並不是背景的一部份,而是「懸浮」在背景之上,就像幽靈或精靈一樣,所以才會叫做「Sprite(精靈)」
# 遊戲物件
  •  Sprite Renderer
而 Sprite Renderer 就是一種渲染器,渲染 Sprite 到畫面上

請注意:Sprite ≠ SpriteRenderer

Sprite(物件外觀圖):資料夾中的Assets

SpriteRenderer:綁定在GameObject上的Component,需要提供一個Sprite給它。

# 遊戲物件
  •  Sprite Renderer

渲染對象Sprite 可以直接搜尋檔名、選擇檔案

渲染後疊加於Sprite上的顏色

X / Y 軸鏡向翻轉

圖片重疊排序階層,適用於較多物件的排序(類似不同圖層)

可直接在同排序階層(Layer)做上下排序(類似Canva的排序)

繪圖模式,等等說

# 遊戲物件
  • 圖像Assets設置
  1. 隨便拖一張圖進你的專案
  2. 點擊你剛剛拖進去的圖片,你就可以看到右方的Inspector視窗出現很多選項
# 遊戲物件
  • 圖像Assets設置

圖像的類型

 類似比例尺,初始值為100,改小會放大圖像(如50即邊長變為兩倍),改大則相反。如果圖像不合大小可先改這裡,盡量不要先動GameObject的大小

可以改圖片的旋轉中心(Pivot,原為中心(0.5,0.5))、拉伸限制

改完記得按 Apply

# 遊戲物件
  • Draw Mode
  1. Simple:只能依照原比例放大、縮小
  2. Sliced:可依照自己喜好調整Sprite之長寬,單位為場景中的座標單位長
  3. Tiled:把圖片以如同磁磚般重複的形式渲染出來(長寬調整如Sliced模式)
# 遊戲物件
  • 實作局
試試看剛剛提到的功能
有問題可以發問!
# 遊戲物件
  • Transform
一個儲存GameObject在場景座標中的位置、旋轉、尺寸比例的Component

GameObject 的座標,使用的是三維座標系統,但是2D遊戲中除了Camera的Z軸座標值為 -10 外,其他物件一律是0(否則Camera有機會看不到)

GameObject在三個座標軸上的旋轉角度,2D遊戲只會碰到Z軸上的旋轉

GameObject在三個座標軸上的尺寸比例,大於1會放大,在0~1之間會縮小,小於0時效果與以該軸為基準鏡像相同,比如說要讓遊戲角色面相反方向可以將X軸上的Scale改為-1(可以拿來做螺旋槳的效果)

# 遊戲物件
  • Transform
無論是Position、Rotation、Scale的數值都是用Vector3(三維向量)的資料型態來在腳本中儲存和使用的,等一下會講
# 腳本局
 腳本局
  • C#語言特性
  • 物件導向
  • 基礎結構
  • C# 語言特性
你可能聽說過的部分:
  1. 要加分號
  2. 資料型態有:int、float、double、bool、string、char
  3. 運算子有:+ - * / = += -= *= /= && || ==
  4. 語法如:for、while、if else、switch case、struct
  5. 函式
# 腳本局
  • C# 語言特性
你沒聽說過的部分:
  1. 注意變數的作用域(全域、區域變數)
  2. 使用小數的時候,因為Unity預設讀取double格式,建議都定義成double型態,如果要用float記得在數字後加f,如:
    
    
    
  3. C# 是一種物件導向的語言
float a = 0.1f
# 腳本局
  • 物件導向
# 腳本局

用「我坐在電腦前上Unity小社課」這個情境用物件導向的方式的話

類別(class) 物件名稱 物件屬性 操作方法
人類 兩隻眼睛 看簡報
電腦 (電腦的型號) Intel 處理器、
記憶體...
在螢幕上顯示簡報

表格內的東西,就是一種物件。然後人類、電腦是一種類別,之後類別底下指出具體的名稱,知道這個物件的屬性和操作方法後,就可以和該物件互動

  • 物件導向
# 腳本局

另外一個概念叫做繼承,拿剛剛的例子來說,比如某電腦有特殊的屬性,如:上面有貼阿夸的貼紙,但這台電腦同時也會有其他電腦都有的屬性。這樣就可以讓該電腦繼承「電腦」這個類別,然後新增一些特殊的屬性。

  • 實作局-創建腳本
  1. 從左下角的Project 視窗中點進assets資料夾
  2. 創建一個資料夾命名為Script
  3. 在Scripts資料夾裡面 Create → C# Script 新增一個腳本檔案
    取名隨意,第一個字母記得大寫
# 腳本局
  • 請注意
  1. 不要直接用 VS Code 新增 .cs 的檔案!不然腳本格式要自己新增會很麻煩
  2. 以後如果寫完腳本要記得放進目標角色的 Inspector ,這樣腳本才會真的套用在那個角色上
# 腳本局
基本結構

腳本都是這樣組成的!

# 腳本局
用 VS Code 打開檔案以後會看到裡面長這樣
# 腳本局

第 1 ~ 3 行:類似 import 或是 include 的  
       指令,之後有需要會加,現 
       在不用理他

 

第 5 行:代表你正在寫一個叫做 Sample ,繼 
    承 MonoBehaviour 的 class

第 8 ~ 11 行:腳本開始運作時會執行一次裡
         面的東西

第 14 ~ 17 行:腳本開始運作時會每一幀都
           會執行一次裡面的東西

(還有一個FixedUpdate,常用於角色移動、物理狀態更新)

  • 實作局-修改圖片的座標
# 腳本局
這個實作局可以先聽完再跟著一起做
  1. 首先,創建一個 Transform 物件(移動的時候也會用到這個Conponent)
  2. 創建一個函數(取名隨意,但是你最後要認得這個函數在幹嘛)
  3. 宣告的東西放在 class 裡面
    Transform catTransform;
    void Flash(){
        
    }
  • 實作局-修改圖片的座標
# 腳本局
安裝成果抽查!
如果你的 VS Code 沒有裝爛,你輸入以下指令:
catTransform.
之後會看到一個物件底下所有成員的清單
紫色方塊是函數

扳手是變數

  • 實作局-修改圖片的座標
# 腳本局
再來就是把這行指令完成
catTransform.position = Vector3.forward;
這行指令會把位置設成(0,0,1),然後把角色隨便放到畫面中的一個位置

再來就是把這個函式放到剛剛提到的 Start 函式中,這樣函式才會在遊戲剛開始的時候被呼叫、執行
  • 實作局-修改圖片的座標
# 腳本局
最後腳本的內容大概是這樣
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement : MonoBehaviour
{
    Transform catTransform;
    void Flash(){
        catTransform.position = Vector3.forward;
    }
    // Start is called before the first frame update
    void Start()
    {
        Flash();
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
  • 實作局-修改圖片的座標
# 腳本局
欸?怎麼好像沒有動靜?
  • 實作局-修改圖片的座標
# 腳本局
那你可能......
  • 實作局-修改圖片的座標
# 腳本局
非常的正常!
  • 實作局-修改圖片的座標
# 腳本局

因為現在的catTransform只是一個空的物件,根本還沒對應到任何一個實際的Transform Component,有兩種方法可以解決這個問題

void Start()
{
	catTransform=GetComponent<Transform>();
    Flash();
}
  1. 使用GetComponent<Component Name>()函式
    可以理解成一個與Component連結的東西,讓你能夠存取/修改其內容記得寫在Start()之內、Test()之前才有初始化的效果

     
  2. 於catTransform的宣告前加入[SerializeField]
    Inspector中會多一個可互動的框,並手動拖曳Transform Component進框框
[SerializeField]Transform catTransform;
  • 實作局-修改圖片的座標
# 腳本局
剛剛講到的功能,還有一種方式可以達成相同的功能
transform.position = Vector3.forward;
「transform」的成員來表示Script所屬的GameObject的Transform Component,所以可以這樣寫就好
雖然這顯得剛剛的內容聽起來像是廢話,但是除了 Transform 之外的 Conponent 都可以用剛剛的方法存取或修改
# 角色移動
 角色移動
  • Vector、Transform
  • 讀取鍵鼠輸入
  • Vector2、Vector3
會存取一個二維、三維座標系的一個點



例如 Transform.position 就是一個 Vector3 變數
# 腳本局
  • Transform
# 腳本局
正如剛剛在講 Conponent 的時候提到的,儲存一個GameObject的位置、旋轉及尺寸比例資訊
  • 讀取鍵鼠輸入
# 腳本局
如果想讓玩家控制角色動起來,那明顯要先讀到玩家給了什麼樣的指令
  • 讀取鍵鼠輸入
# 腳本局
首先找到左上角 Edit -> Project Settings ,然後在裡面找到 Input Manager
  • 讀取鍵鼠輸入
# 腳本局
點一下 Axes 旁邊的小三角形,你會看到:

用來存Axis 的名字(Horizontal
水平、Vertival 垂直)

用來該軸座標值正負的按鍵

另一組用來該軸座標值正負的按鍵

輸入設備的類型

後覆蓋(?

控制的軸(因為這邊是Horizontal所以控制X軸)

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

public class OldPlayerMoveSample : MonoBehaviour
{
    float horizontal; //水平軸值,-1~1
    float vertical; //垂直軸值,-1~1
    float dx; //一次水平方向移動距離
    float dy; //一次垂直方向移動距離
    float boundedx; //被限制過的水平移動位置
    float boundedy; //被限制過的垂直移動位置
    
    [SerializeField] float moveSpeed = 10f; //移動速度
    
    [SerializeField] float xBound; //水平邊界
    [SerializeField] float yBound; //垂直邊界
    SpriteRenderer spriteR; //圖像渲染器(獲取Sprite邊界)
    Vector3 spriteRBound; //Sprite邊界
    
    void Start() {
        spriteR = GetComponent<SpriteRenderer>(); 
        spriteRBound = spriteR.bounds.size/2; //Vector直接除2可以得到半長寬
        yBound = 5f;
        xBound = yBound/9f*16f; //16:9
    }

    void Facing(){ //前面講過的翻轉,以軸值來判斷角色移動方向,讓角色能左右轉向(之後可以把功能像這樣包裝成函式會很好管理)
        if(horizontal <= -0.01f && transform.localScale.x > 0){
            transform.localScale = new Vector3(-transform.localScale.x,transform.localScale.y,transform.localScale.z);
        }
        else if(horizontal >= 0.01f && transform.localScale.x < 0){
            transform.localScale = new Vector3(-transform.localScale.x,transform.localScale.y,transform.localScale.z);
        }
    }

    void Move(){ //負責移動的函式,兩種改位置方法擇一
        //計算一次移動的距離,乘Time.deltaTime是為了讓一秒內移動的距離接近Input * moveSpeed的值
        dx = horizontal * Time.deltaTime * moveSpeed; 
        dy = vertical * Time.deltaTime * moveSpeed;

        transform.Translate(new Vector3(dx, dy, transform.localPosition.z)); /*改位置方法1:transfrom.Translate(Vector3)
                                                                               會把position.x/y/z值分別加上傳入的
                                                                               Vector3.x/y/z(如果要限制邊界要寫if else,邊界內才移動)*/

        //計算限制後的位置,前面的半長寬會用在這,spriteRBound.x為半寬(水平),.y則為半長(垂直)
        // Mathf.Clamp(value, min, max)可以將傳入的value限制在min跟max之間,低於min則等於min,高於max則等於max
        boundedx = Mathf.Clamp(transform.localPosition.x + dx , -xBound + spriteRBound.x, xBound - spriteRBound.x);
        boundedy = Mathf.Clamp(transform.localPosition.y + dy , -yBound + spriteRBound.y , yBound - spriteRBound.y);

        transform.position = new Vector3(boundedx, boundedy, transform.localPosition.z); /*改位置方法2:分別計算最後的x/y值後
                                                                                           直接改localPosition*/
    }

    void Update(){ //輸入一律放在Update裡
        horizontal = Input.GetAxis("Horizontal"); //回傳平滑處理過的水平軸值(-1~1)
        vertical = Input.GetAxis("Vertical"); //回傳平滑處理過的垂直軸值(-1~1)
        // horizontal = Input.GetAxisRaw("Horizontal"); //回傳未平滑處理的水平軸值(-1 or 0 or 1)
        // vertical = Input.GetAxisRaw("Vertical"); //回傳未平滑處理的垂直軸值(-1 or 0 or 1)

        Facing();
    }

    void FixedUpdate() { //移動程式放在FixedUpdate裡
        Move();
    }
}
# PRESENTING CODE
  • 整個腳本大概長醬 謝謝水獺學長的code
Made with Slides.com