課程簡介

這是 2017 年在嘉南藥理大學開設的「Unity 程式設計基本課程」,用兩週密集課程帶領學生從 Unity 基礎程式設計到完整的多人連線遊戲開發。

課程特色

目標: 快速掌握 Unity 程式設計,並開發一個多人連線射擊遊戲

課程設計:

  • 第一週:Unity C# 程式基礎(變數、流程控制、物件操作、輸入處理)
  • 第二週:多人連線遊戲開發(Unity Networking 完整 12 步驟)

技術棧:

Unity + C# + Unity Networking (UNET) → 多人連線 FPS 遊戲

課程大綱

第一週 (4/17) ♥♥ - Unity 程式基礎

千里之行,始於足下

學習內容:

1. 變數與資料型別

string 字串、int 整數、bool 布林

// 要買的飲料是什麼,要幾杯,老闆帥不帥
public string 飲料 = "珍奶";
public int 幾杯 = 1;
public bool 老闆帥 = true;

實用場景:

  • string:儲存文字、名稱、訊息
  • int:儲存數字、計數、分數
  • bool:儲存真假、狀態、開關

2. Debug.Log() 輸出訊息

// 將要顯示的句子用 + 組合起來一次顯示出來
Debug.Log("老闆我要" + 幾杯 + "杯" + 飲料);

用途:

  • 除錯(Debug)
  • 測試程式邏輯
  • 追蹤變數值

3. if-else 條件判斷

// 如果老闆帥就要電話,如果不帥就叫老闆快點
if (老闆帥) {
    Debug.Log("老闆可以給我你的電話號碼嗎");
} else {
    Debug.Log("老闆可以快點嗎 我趕時間");
}

應用:

  • 遊戲邏輯判斷
  • 條件分支
  • 狀態檢查

4. for 迴圈

// 睡不著的時候用迴圈數羊
Debug.Log("睡不著覺來數羊");

// 從第 1 隻開始數,要數到 1000 隻
for (int 第幾 = 1; 第幾 < 1000; 第幾++) {
    Debug.Log(第幾 + "隻羊");  // 現在數到第幾隻

    // 數到 300 隻就睡著了
    if (第幾 == 300) {
        Debug.Log("zzzZZZ");  // 睡著了
        break;  // 已經睡著就不再數了
    }
}

應用:

  • 重複執行程式碼
  • 遍歷陣列
  • 批次處理

5. transform.Translate() 物件移動

void OnGUI() {
    // X 軸控制
    if (GUI.Button(new Rect(10, 10, 200, 30), "X ++")) {
        Target.transform.Translate(1, 0, 0);  // 向 X 軸移動 1 單位
    }
    if (GUI.Button(new Rect(210, 10, 200, 30), "X --")) {
        Target.transform.Translate(-1, 0, 0);
    }

    // 鍵盤控制
    if (Input.GetKey(KeyCode.W)) {
        Target.transform.Translate(0, 0, 1);  // 向前移動
    }
    if (Input.GetKey(KeyCode.S)) {
        Target.transform.Translate(0, 0, -1);  // 向後移動
    }
}

控制方式:

  • GUI 按鈕控制
  • 鍵盤控制(WASD)
  • 三軸移動(X、Y、Z)

6. transform.Rotate() 物件旋轉

void OnGUI() {
    // X 軸旋轉
    if (GUI.Button(new Rect(10, 10, 200, 30), "X ++")) {
        Target.transform.Rotate(10, 0, 0);  // 以 X 軸旋轉 10 度
    }

    // Y 軸旋轉(左右轉)
    if (GUI.Button(new Rect(10, 40, 200, 30), "Y ++")) {
        Target.transform.Rotate(0, 10, 0);
    }

    // Z 軸旋轉(翻滾)
    if (GUI.Button(new Rect(10, 70, 200, 30), "Z ++")) {
        Target.transform.Rotate(0, 0, 10);
    }
}

7. Input.GetMouseButtonDown() 滑鼠輸入

void Update() {
    // 滑鼠按鍵檢測
    if (Input.GetMouseButtonDown(0)) {
        Debug.Log("按下滑鼠左鍵");
    }
    if (Input.GetMouseButtonDown(1)) {
        Debug.Log("按下滑鼠右鍵");
    }

    // 滑鼠移動控制旋轉
    // Input.GetAxis("Mouse X") 可以取得滑鼠左右移動的差值
    Target.transform.Rotate(0, Input.GetAxis("Mouse X"), 0);
}

8. Input.GetKey() 鍵盤輸入

void Update() {
    // 方向鍵檢測
    if (Input.GetKey(KeyCode.UpArrow)) {
        print("向上方向鍵被按了");
    }
    if (Input.GetKey(KeyCode.DownArrow)) {
        print("向下方向鍵被按了");
    }
}

9. 完整的角色控制器

PlayerController.cs

void Update() {
    // 鍵盤控制移動
    if (Input.GetKey(KeyCode.W)) {
        gameObject.transform.Translate(0, 0, .1f);
    }
    if (Input.GetKey(KeyCode.S)) {
        gameObject.transform.Translate(0, 0, -.1f);
    }
    if (Input.GetKey(KeyCode.D)) {
        gameObject.transform.Translate(.1f, 0, 0);
    }
    if (Input.GetKey(KeyCode.A)) {
        gameObject.transform.Translate(-.1f, 0, 0);
    }

    // 鍵盤控制旋轉
    if (Input.GetKey(KeyCode.E)) {
        gameObject.transform.Rotate(0, 10, 0);
    }
    if (Input.GetKey(KeyCode.Q)) {
        gameObject.transform.Rotate(0, -10, 0);
    }

    // 滑鼠控制旋轉
    gameObject.transform.Rotate(0, Input.GetAxis("Mouse X") * 10, 0);
}

功能:

  • WASD 控制移動
  • QE 控制旋轉
  • 滑鼠控制視角

第二週 (4/24) ♥♥♥ - 多人連線遊戲開發

從基礎到實戰

完整的多人連線 FPS 遊戲開發(12 步驟)

步驟 1-3:專案設定與玩家建立

  1. 建立新專案
    • 開新 3D 專案
    • 建立 Main 場景
  2. 設定 NetworkManager
    • 建立空物件命名為 NetworkManager
    • 加入 NetworkManager 組件
    • 加入 NetworkManagerHUD 組件
  3. 建立 Player Prefab
    • 製作 Player 遊戲物件
    • 加入 NetworkIdentity 組件
    • 勾選 Local Player Authority
    • 將 Player Prefab 加入 NetworkManager/Spawn Info

步驟 4-6:玩家移動與同步

  1. 基本玩家控制
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    void Update()
    {
        var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
        var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;

        transform.Rotate(0, x, 0);  // 旋轉
        transform.Translate(0, 0, z);  // 前進後退
    }
}
  1. 網路同步移動
using UnityEngine;
using UnityEngine.Networking;

public class PlayerController : NetworkBehaviour
{
    void Update()
    {
        if (!isLocalPlayer) {
            return;  // 只控制自己的角色
        }

        var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
        var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;

        transform.Rotate(0, x, 0);
        transform.Translate(0, 0, z);
    }
}
  • 加入 NetworkTransform 組件
  • 實現位置同步
  1. 區分本地玩家
public override void OnStartLocalPlayer()
{
    GetComponent<MeshRenderer>().material.color = Color.blue;
}

步驟 7-9:射擊系統

  1. 建立子彈
    • 建立 Bullet 遊戲物件
    • 加入 Rigidbody
    • 製作成 Prefab
  2. 本地射擊
public GameObject bulletPrefab;
public Transform bulletSpawn;

void Update()
{
    // ... 移動程式碼 ...

    if (Input.GetKeyDown(KeyCode.Space)) {
        Fire();
    }
}

void Fire()
{
    var bullet = (GameObject)Instantiate(
        bulletPrefab,
        bulletSpawn.position,
        bulletSpawn.rotation);

    bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;
    Destroy(bullet, 2.0f);
}
  1. 網路同步射擊
void Update()
{
    // ... 移動程式碼 ...

    if (Input.GetKeyDown(KeyCode.Space)) {
        CmdFire();  // 改用 Command
    }
}

[Command]  // 在 Client 呼叫,在 Server 執行
void CmdFire()
{
    var bullet = (GameObject)Instantiate(
        bulletPrefab,
        bulletSpawn.position,
        bulletSpawn.rotation);

    bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;

    // 在所有 Client 上生成子彈
    NetworkServer.Spawn(bullet);

    Destroy(bullet, 2.0f);
}
  • Bullet 加入 NetworkIdentity
  • Bullet 加入 NetworkTransform
  • 將 Bullet Prefab 加入 Registered Spawnable Prefabs

步驟 10-12:血量系統與死亡重生

  1. 碰撞與血量

Bullet.cs

void OnCollisionEnter(Collision collision)
{
    var hit = collision.gameObject;
    var health = hit.GetComponent<Health>();
    if (health != null) {
        health.TakeDamage(10);
    }
    Destroy(gameObject);
}

Health.cs

public const int maxHealth = 100;
public int currentHealth = maxHealth;
public RectTransform healthBar;

public void TakeDamage(int amount)
{
    currentHealth -= amount;
    if (currentHealth <= 0) {
        currentHealth = 0;
        Debug.Log("Dead!");
    }

    healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
}

Billboard.cs(血條面向鏡頭)

void Update()
{
    transform.LookAt(Camera.main.transform);
}
  1. 網路同步血量
using UnityEngine.Networking;

public class Health : NetworkBehaviour
{
    public const int maxHealth = 100;

    [SyncVar(hook = "OnChangeHealth")]  // 同步變數
    public int currentHealth = maxHealth;

    public RectTransform healthBar;

    public void TakeDamage(int amount)
    {
        if (!isServer)  // 只在 Server 處理
            return;

        currentHealth -= amount;
        if (currentHealth <= 0) {
            currentHealth = 0;
            Debug.Log("Dead!");
        }
    }

    void OnChangeHealth(int health)
    {
        // 當血量改變時更新 UI
        healthBar.sizeDelta = new Vector2(health, healthBar.sizeDelta.y);
    }
}
  1. 死亡與重生
public void TakeDamage(int amount)
{
    if (!isServer)
        return;

    currentHealth -= amount;
    if (currentHealth <= 0) {
        currentHealth = maxHealth;

        // 在 Server 呼叫,在所有 Client 執行
        RpcRespawn();
    }
}

[ClientRpc]
void RpcRespawn()
{
    if (isLocalPlayer) {
        // 回到起始位置
        transform.position = Vector3.zero;
    }
}

技術亮點

1. Unity Networking (UNET) 架構

Client-Server 模型:

Client 1 ←→ Server ←→ Client 2

關鍵組件:

  • NetworkManager:管理網路連線
  • NetworkIdentity:識別網路物件
  • NetworkBehaviour:網路腳本基類
  • NetworkTransform:同步位置與旋轉

2. 網路同步機制

[Command]:Client → Server

[Command]
void CmdFire() {
    // 在 Client 呼叫,在 Server 執行
}

[ClientRpc]:Server → All Clients

[ClientRpc]
void RpcRespawn() {
    // 在 Server 呼叫,在所有 Client 執行
}

[SyncVar]:自動同步變數

[SyncVar(hook = "OnChangeHealth")]
public int currentHealth;

3. 權威性設計

Server Authority(伺服器權威):

  • 血量在 Server 計算
  • 防止作弊
  • 確保一致性

Local Player Authority(本地玩家權威):

  • 移動由 Client 控制
  • 減少延遲
  • 提升手感

4. 完整的遊戲功能

玩家移動 → 射擊 → 子彈飛行 → 碰撞偵測 → 扣血 → 血條更新 → 死亡重生

每個環節都考慮網路同步!


課程特色

1. 循序漸進

第一週:打好 C# 基礎 第二週:實戰多人遊戲

從單機到聯機,步步為營。


2. 實作導向

  • 不只講理論,每個概念都有程式碼範例
  • 配有影片示範
  • 可下載完整專案

3. 趣味教學

用生活化的例子教程式:

  • 買飲料 → 變數
  • 數羊 → 迴圈
  • 老闆帥不帥 → 條件判斷

4. 令人興奮的進度

用 ♥ 符號表示課程的刺激程度:

  • 第一週 ♥♥:基礎但有趣
  • 第二週 ♥♥♥:超級刺激的多人遊戲!

學習成果

學生將學會:

  1. Unity C# 基礎
    • 變數與資料型別
    • 流程控制(if、for)
    • 物件操作(移動、旋轉)
    • 輸入處理(鍵盤、滑鼠)
  2. Unity Networking
    • Client-Server 架構
    • NetworkManager 設定
    • 網路物件同步
    • Command/ClientRpc/SyncVar
  3. 完整遊戲開發
    • 角色控制系統
    • 射擊系統
    • 血量與 UI 系統
    • 死亡與重生機制
  4. 多人遊戲設計思維
    • 權威性設計
    • 作弊防護
    • 網路延遲處理
    • 狀態同步

課程資源

完整教學網站: https://yazelin.github.io/cnu2017/

GitHub 開源專案: https://github.com/yazelin/cnu2017

範例下載:

參考資源:

相關課程:


課程資訊

  • 學校:嘉南藥理大學
  • 課程名稱:Unity 程式設計基本課程
  • 授課時間:2017 年 4 月(共 2 週密集課程)
  • 授課教師Hungsiu
  • 教案協作:Yaze Lin
  • 專案主題:多人連線 FPS 射擊遊戲
  • 技術棧:Unity + C# + UNET
  • 特色:從零基礎到多人遊戲、趣味化教學、完整 12 步驟實作