Unity
講師:sleepyboy

-
廢話可能會很多
-
新北市板橋區最強 DJ(16歲)
-
邊看教學邊備課
這我
↘ 我本人
# 講師介紹
1.
2.
3.
# 目錄
目錄局
# 遊戲物件
遊戲物件

-
GameObject & Component
-
Sprite & Sprite Renderer
-
Transform
# 遊戲物件
-
Conponent

這個格子可以控制Conponent的啟用與否
可以把他想像成 GameObject 的功能
將游標移到值為數字的屬性上會出現雙箭頭,可以左右拖動直接調整數值
# 遊戲物件
-
Conponent

回復初始設置
快速移動屬性順序至最前/後
複製Conponent
以新增的方式貼上
以參數覆蓋的方式貼上
移除Conponent
可以用拖的
略過
# 遊戲物件
-
GameObject
一個GameObject盡量不要加種類相同的兩個Component,腦子會破掉
BUT
那如果我希望兩個物件一起移動,但又有不同的功能備分開操控如:角色和他的武器,要怎麼處理?
# 遊戲物件
-
GameObject
創建子物件!
- 在 Hierachy 選定一個父物件(這個群組的頭領)然後把子物件選取向父物件拖曳
- 類似 Canva 的群組,子物件會和父物件一起移動
- 如果子物件被停用,不會停用父物件。但父物件被停用,子物件會被停用

# 遊戲物件
-
GameObject
原理:將子物件的位置改成與父物件的相對位置
例如,當子物件的LocalPosition(相對於父物件,會顯示於Inspector上)為(-5,9,0),父物件的Position為(6,15,0)
則子物件的實際位置為(1,24,0)
# 遊戲物件
-
Sprite
-
Sprite 是一個將多圖層/圖像整合在一個2D平面上的技術
- 因為這樣的圖像並不是背景的一部份,而是「懸浮」在背景之上,就像幽靈或精靈一樣,所以才會叫做「Sprite(精靈)」


# 遊戲物件
-
Sprite Renderer
而 Sprite Renderer 就是一種渲染器,渲染 Sprite 到畫面上
請注意:Sprite ≠ SpriteRenderer
Sprite(物件外觀圖):資料夾中的Assets
SpriteRenderer:綁定在GameObject上的Component,需要提供一個Sprite給它。

# 遊戲物件
-
Sprite Renderer

渲染對象Sprite 可以直接搜尋檔名、選擇檔案
渲染後疊加於Sprite上的顏色
X / Y 軸鏡向翻轉
圖片重疊排序階層,適用於較多物件的排序(類似不同圖層)
可直接在同排序階層(Layer)做上下排序(類似Canva的排序)
繪圖模式,等等說
# 遊戲物件
-
圖像Assets設置
-
隨便拖一張圖進你的專案
- 點擊你剛剛拖進去的圖片,你就可以看到右方的Inspector視窗出現很多選項

# 遊戲物件
-
圖像Assets設置

圖像的類型
類似比例尺,初始值為100,改小會放大圖像(如50即邊長變為兩倍),改大則相反。如果圖像不合大小可先改這裡,盡量不要先動GameObject的大小
可以改圖片的旋轉中心(Pivot,原為中心(0.5,0.5))、拉伸限制

改完記得按 Apply
# 遊戲物件
-
Draw Mode

-
Simple:只能依照原比例放大、縮小
-
Sliced:可依照自己喜好調整Sprite之長寬,單位為場景中的座標單位長
-
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# 語言特性
你可能聽說過的部分:
-
要加分號
-
資料型態有:int、float、double、bool、string、char
- 運算子有:+ - * / = += -= *= /= && || ==
-
語法如:for、while、if else、switch case、struct
- 函式
# 腳本局
-
C# 語言特性
你沒聽說過的部分:
-
注意變數的作用域(全域、區域變數)
-
使用小數的時候,因為Unity預設讀取double格式,建議都定義成double型態,如果要用float記得在數字後加f,如:
-
C# 是一種物件導向的語言
float a = 0.1f
# 腳本局
-
物件導向
# 腳本局
用「我坐在電腦前上Unity小社課」這個情境用物件導向的方式的話
類別(class) | 物件名稱 | 物件屬性 | 操作方法 |
---|---|---|---|
人類 | 我 | 兩隻眼睛 | 看簡報 |
電腦 | (電腦的型號) | Intel 處理器、 記憶體... |
在螢幕上顯示簡報 |
表格內的東西,就是一種物件。然後人類、電腦是一種類別,之後類別底下指出具體的名稱,知道這個物件的屬性和操作方法後,就可以和該物件互動
-
物件導向
# 腳本局
另外一個概念叫做繼承,拿剛剛的例子來說,比如某電腦有特殊的屬性,如:上面有貼阿夸的貼紙,但這台電腦同時也會有其他電腦都有的屬性。這樣就可以讓該電腦繼承「電腦」這個類別,然後新增一些特殊的屬性。

-
實作局-創建腳本
-
從左下角的Project 視窗中點進assets資料夾
-
創建一個資料夾命名為Script
-
在Scripts資料夾裡面 Create → C# Script 新增一個腳本檔案 取名隨意,第一個字母記得大寫


# 腳本局
-
請注意
-
不要直接用 VS Code 新增 .cs 的檔案!不然腳本格式要自己新增會很麻煩
- 以後如果寫完腳本要記得放進目標角色的 Inspector ,這樣腳本才會真的套用在那個角色上
# 腳本局
基本結構
腳本都是這樣組成的!
# 腳本局
用 VS Code 打開檔案以後會看到裡面長這樣
# 腳本局
第 1 ~ 3 行:類似 import 或是 include 的
指令,之後有需要會加,現
在不用理他
第 5 行:代表你正在寫一個叫做 Sample ,繼
承 MonoBehaviour 的 class
第 8 ~ 11 行:腳本開始運作時會執行一次裡
面的東西
第 14 ~ 17 行:腳本開始運作時會每一幀都
會執行一次裡面的東西
(還有一個FixedUpdate,常用於角色移動、物理狀態更新)

-
實作局-修改圖片的座標
# 腳本局
這個實作局可以先聽完再跟著一起做
-
首先,創建一個 Transform 物件(移動的時候也會用到這個Conponent)
-
創建一個函數(取名隨意,但是你最後要認得這個函數在幹嘛)
-
宣告的東西放在 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();
}
-
使用GetComponent<Component Name>()函式
可以理解成一個與Component連結的東西,讓你能夠存取/修改其內容記得寫在Start()之內、Test()之前才有初始化的效果
-
於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
Unity 小社課第 1 局
By April first
Unity 小社課第 1 局
- 259