講師:sleepyboy
廢話可能會很多
新北市板橋區最強 DJ(16歲)
邊看教學邊備課
這我
↘ 我本人
# 講師介紹
# 目錄
目錄局
# 遊戲物件
遊戲物件
GameObject & Component
Sprite & Sprite Renderer
Transform
# 遊戲物件
Conponent
這個格子可以控制Conponent的啟用與否
可以把他想像成 GameObject 的功能
將游標移到值為數字的屬性上會出現雙箭頭,可以左右拖動直接調整數值
# 遊戲物件
Conponent
回復初始設置
快速移動屬性順序至最前/後
複製Conponent
以新增的方式貼上
以參數覆蓋的方式貼上
移除Conponent
可以用拖的
略過
# 遊戲物件
GameObject
一個GameObject盡量不要加種類相同的兩個Component,腦子會破掉
BUT
那如果我希望兩個物件一起移動,但又有不同的功能備分開操控如:角色和他的武器,要怎麼處理?
# 遊戲物件
GameObject
創建子物件!
# 遊戲物件
GameObject
原理:將子物件的位置改成與父物件的相對位置
例如,當子物件的LocalPosition(相對於父物件,會顯示於Inspector上)為(-5,9,0),父物件的Position為(6,15,0)
則子物件的實際位置為(1,24,0)
# 遊戲物件
Sprite
Sprite 是一個將多圖層/圖像整合在一個2D平面上的技術
# 遊戲物件
Sprite Renderer
而 Sprite Renderer 就是一種渲染器,渲染 Sprite 到畫面上
請注意:Sprite ≠ SpriteRenderer
Sprite(物件外觀圖):資料夾中的Assets
SpriteRenderer:綁定在GameObject上的Component,需要提供一個Sprite給它。
# 遊戲物件
Sprite Renderer
渲染對象Sprite 可以直接搜尋檔名、選擇檔案
渲染後疊加於Sprite上的顏色
X / Y 軸鏡向翻轉
圖片重疊排序階層,適用於較多物件的排序(類似不同圖層)
可直接在同排序階層(Layer)做上下排序(類似Canva的排序)
繪圖模式,等等說
# 遊戲物件
圖像Assets設置
隨便拖一張圖進你的專案
# 遊戲物件
圖像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 的檔案!不然腳本格式要自己新增會很麻煩
# 腳本局
基本結構
腳本都是這樣組成的!
# 腳本局
用 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();
}
[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