Unity C# 程式基礎
與遊戲控制邏輯入門

從組件架構、生命週期、變數、GetComponent、條件判斷到 Time.deltaTime,最後串成一個 2D 跑酷遊戲。

按 ← → 鍵或下方按鈕切換頁面

腳本就是「自訂組件」

GameObject 是空車架

本身沒有功能,必須安裝組件:引擎組件讓車能跑,喇叭組件讓車能響。

2D 圖片預設組件

  • Transform:位置、旋轉、縮放
  • Sprite Renderer:顏色、透明度、圖層順序

建立腳本

Project 面板右鍵 Create → C# Script,或在 Inspector 按 Add Component → New Script。名稱用 PascalCase,如 PlayerMovement。

檔名必須等於類別名

PlayerMovement.cs 裡寫成 class Playermovement(大小寫不同),Unity 就無法辨認,也無法掛載到物件。

三個核心生命週期函式

函式執行時機用途
Start()物件啟用時,只執行一次初始化、GetComponent 綁定組件
Update()每一幀執行一次偵測按鍵、計時器、非物理邏輯
FixedUpdate()固定時間間隔,不受幀率影響Rigidbody2D 的移動與受力

為什麼物理放 FixedUpdate

Update 的次數取決於硬體:144 FPS 與 30 FPS 的電腦,每秒執行次數差很多,直接移動剛體會讓速度不一致。

void 是什麼

代表函式執行完不回傳任何資料。回傳整數寫 int,回傳文字寫 string。

變數:先「報戶口」再使用

// 資料類型 變數名稱 = 初始值;
public float speed = 5f;   // 公開到 Inspector,可即時調參
public static float speed = 5f; // 其他腳本用 GroundMove.speed 直接存取

常見型態

  • int:整數(分數、關卡)
  • float:小數,數值後要加 f(5f)
  • string:文字,用雙引號
  • bool:true / false(isGrounded、isDead)
  • GameObject[]:陣列,索引從 0 開始

實用小技巧

float 轉成 UI 文字時,用 distance.ToString("F0") 去掉小數位,只顯示整數公尺。

Tag 區分大小寫

Inspector 的 Tag 是 Ground,程式碼寫 "ground" 條件就會失效。

GetComponent:取得組件控制權

Rigidbody2D rb;      // 1. 宣告
Animator anim;

void Start() {          // 2. 在 Start 或 Awake 綁定
    rb   = GetComponent<Rigidbody2D>();
    anim = GetComponent<Animator>();
}                          // 3. 之後用 rb、anim 控制屬性

常用組件

  • Rigidbody2D:rb.linearVelocityX 設定水平速度
  • Animator:anim.SetBool("run", true)
  • SpriteRenderer:spr.flipX = true 解決倒退跑
  • AudioSource:.Play() / .Stop()

Awake 與 Start

Awake 最早執行,適合組件自身的內部綁定(如 AudioManager 取得 AudioSource)。Start 在 Awake 之後,適合依賴其他物件的初始化,這樣其他腳本在 Start 播放音效時,AudioSource 已準備好。

if 判斷與玩家輸入

if (Input.GetKey(KeyCode.RightArrow))      movement = speed;
else if (Input.GetKey(KeyCode.LeftArrow)) movement = -speed;
else                                       movement = 0f;

// && 兩個條件必須同時成立:防止空中連跳
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
    rb.linearVelocity = new Vector2(movement, jump);

GetKey 與 GetKeyDown

GetKey:按住時每一幀都是 true。GetKeyDown:按下瞬間只回傳一次 true,適合跳躍、攻擊、確認。

餘數運算子 %

groundCount % 10 == 0 在第 10、20、30 個地面成立,可藉此用 speed *= 1.5f 逐步加速。

== 與 = 不同

== 是比較是否相等,= 是把右邊的值指派給左邊。

Time.deltaTime:讓速度與硬體無關

Time.deltaTime 是上一幀到這一幀所花的秒數。乘上它,就把「每幀移動」轉成「每秒移動」。

情境(速度 10 單位/秒)計算每秒總距離
144 FPS10 × (1/144) × 144 幀10 單位
30 FPS10 × (1/30) × 30 幀10 單位
distance += GroundMove.speed * Time.deltaTime;  // 精確反映實際跑了幾公尺

不乘的後果:每幀 +5,144 FPS 每秒 720 單位,30 FPS 只有 150 單位,遊戲速度被硬體綁定。

綜合應用:2D 跑酷遊戲架構

腳本職責
PlayerMovementUpdate 偵測輸入、翻轉圖片、受限跳躍;FixedUpdate 套用水平速度;OnTrigger 以 Ground 標籤設定父物件跟著平台移動,以 Deathline 標籤判定死亡
GroundMakerInvokeRepeating 定時呼叫,Instantiate 隨機生成地形,每 10 個地面加速
GameManager按 Enter 開始、累加距離並更新 UI、死亡後顯示 Game Over,按任意鍵 SceneManager.LoadScene 重載
AudioManagerAwake 先取得 AudioSource,提供 PlayTitle / PlayBgm 給其他腳本呼叫

劃分權責

一個腳本專注一件事。

善用變數

public 即時調參,static 跨腳本共享。

平滑時間

物理放 FixedUpdate,距離乘 Time.deltaTime。