本帖最後由 JLChnToZ 於 2014-2-16 17:29 編輯
大家好~ 這是我的第一次發教學帖
這次我會教大家如何使用 Unity 編寫一個簡單的遊戲
嘛... 既然說是基礎, 那麼就... 仿製一個簡單點的遊戲吧 (笑)
這一隻怎樣?

(按圖片進去看看吧, 這是論壇的 Flash 遊戲而已)
在開始之前, 我已假定大家會用 3D 軟件 (如 Maya) 建模,還有就是怎樣也會寫一點類 C++ (C#, Java 之類的) 的程式語言
[[如果不會用 3D 軟件的話請先去惡補一下,
這論壇是有這方面的教學的!]]
好了啦~ 事不宜遲, 先把咱們的 Unity 打開吧~
首先, 開一個新的 Project... 至於名字呢... 既然是 Missle... 就叫 Missle Game 吧~!
然後呢, 放一盞燈 (spot light) 進去吧~
接著把燈放到主鏡頭 (Main Camera) 裡, 再把座標旋轉全部歸零
至於鏡頭呢... 把它的起始座標設成這樣吧,
背景顏色方面, 變成深灰色吧:
調好後應該會在場景編輯畫面看到這個樣子:
都弄好之後先儲存一下唄~ ((叫 Main Scene 好了, 已經懶得想名字了啦~
好了~ 基本的燈光和鏡頭已經設好了, 再來就要開始搭場景了~
大家先去看一下上面的遊戲, 不難發現整個遊戲場景像是在一個管道裡, 所以...
咱們先弄管子吧!
現在來打開你熟悉的 3D 軟件 (咱最熟悉 Maya, 所以就拿 Maya 來用了)
用你的方法拉一條直管出來
直徑最好是 100, 長度最少 1000+, 管子的厚度不重要的說~
直接把這管子匯出成 fbx 款式 (或者其他 Unity 支援的格式也可)
直接命名為 "Pipe" 好了
先不要急著關掉 3D 軟件~ 咱們還有東西沒做好的~
再來就是做障礙物, 先把管子的厚度弄大, 還有就是不要太長, 短短的就好:
把這個環也匯出吧, 命名為 "Part1" 就好
然後就發揮你的創意, 把這個環裡面做點變化, 例如這樣:
再次匯出成 "Part2" 吧
重複幾次, 做幾個版本, 這部分就完成了~
到這裡, 你應該會先後儲存了這些檔案:
不用說了, 這些通通拉到 Unity 裡吧!
如果你是喜歡整潔的人, 不妨在 Assets 開一個資料夾, 才把這些模組拉到裡面
然後, 先把那直直的管子拉到場景裡, 同樣的, 所有座標歸零:
接著就是最精采的部分----遊戲編程!
先開一個 Dummy 的遊戲物件, 用來處理遊戲程式的
接著, 把它命名為 "MainController" 以及把它的 Tag 選成 "GameController"
然後打開最下面的 "Add Component" -> "New Script", 開一個新的腳本叫 "LevelController" 吧 (別忘了把 Language 記成 C#, 否則下面你會出錯滴)
點兩下這個 "LevelController", 等一下之後應該會出現 MonoDevelop 的畫面了~
先來一個簡單的~ 用滑鼠移動鏡頭吧~
把程式碼改成這樣再 save:
- using UnityEngine;
- using System.Collections;
- public class LevelController : MonoBehaviour {
- Vector3 lastMousePos;
- // Use this for initialization
- void Start () {
- lastMousePos = Input.mousePosition; // 儲存起始滑鼠位置
- }
-
- // Update is called once per frame
- void Update () {
- Vector3 pos = Input.mousePosition; // 現在的滑鼠位置
- Vector3 diff = (pos - lastMousePos) / 100; // 與上一個位置的差
- Camera.main.transform.position += new Vector3(diff.x, 0, diff.y); // 移動鏡頭
- lastMousePos = pos; // 儲存新的滑鼠位置
- }
- }
複製代碼
這個時候你可以回去 Unity 測試一下了~ (建議不要把 MonoDevelop 關閉, 否則等下再修改程式的時候又要非常有耐性的等它啟動)
應該不難發現移動滑鼠雖然可以移動鏡頭, 但完全沒有限制其範圍, 要移動到管子外完全不是難事吧?
這不是咱們想要的, 所以有必要追加點限制...
再回去 MonoDevelop 的畫面, 追加以下程式到原本的程式中:
- ...
- Vector3 lastMousePos;
- const float maxDistance = 0.7F; // 限定最大距離
- ...
- void Start () {
- lastMousePos = Input.mousePosition; // 儲存起始滑鼠位置
- cameraPos = Camera.main.transform.position; // 儲存起始鏡頭位置
- }
- ...
- void Update () {
- Vector3 pos = Input.mousePosition; // 現在的滑鼠位置
- Vector3 diff = (pos - lastMousePos) / 100; // 與上一個位置的差
- Vector3 pos2 = Camera.main.transform.position; // 取得現在的鏡頭位置
- ...
複製代碼
再儲存測試吧, 現在應該限制了可移動的範圍吧 (?)
接著咱們就要把障礙物也放進去了, 把 Asset 裡的 "Part1" 拉到場景中吧~ (重複的話不想再說了, 座標要清零~)
然後就再次的... 創建一個新的 Script... 這次叫 "PartBehavior" 吧
點兩下剛創建的程式, 再次進入 MonoDevelop
輸入以下的程式:
- using UnityEngine;
- using System.Collections;
- public class PartsBehavior : MonoBehaviour {
- public float speed = 0.1F; // 速度
- public float startpos = 0F; // 開始位置
- public float endpos = 10F; // 結束位置
- // Use this for initialization
- void Start () {
- }
-
- // Update is called once per frame
- void Update () {
- if(gameObject.transform.position.y >= endpos) { // 如果 Y 座標大於最大值
- gameObject.transform.position -= new Vector3(0, endpos - startpos, 0); // 回去開始位置
- } else { // 否則
- gameObject.transform.position += Vector3.up * speed; // 以速度的值移動
- }
- }
- }
複製代碼
現在測試一下應該會發現整個場景會好像不斷向前走, 但感覺那個環與環之間的距離好像太疏了吧?
好~ 那就複製多點吧!
回去 "LevelController", 追加以下的程式:
- ...
- public int DodgeObjectCount = 5; // 環的數量
- public float DodgeObjectDistance = 2; // 環之間的距離
- public PartsBehavior[] behaviors; // 環的行為定義
- // Use this for initialization
- void Start () {
- ...
- GameObject go = GameObject.Find ("part1"); // 取得 "Part1" 的程式
- behaviors = new PartsBehavior[DodgeObjectCount+1]; // 初始化環的定義數量
- behaviors[DodgeObjectCount] = go.GetComponent<PartsBehavior>(); // 取得第一個環的行為定義
- for(int i = 0; i < DodgeObjectCount; i++) {
- GameObject g = (GameObject)Instantiate(go); // 複製一個環
- g.transform.position += Vector3.up * DodgeObjectDistance * (i + 1); // 設定這個環的位置
- behaviors[i] = g.GetComponent<PartsBehavior>(); // 取得這個環的定義
- }
- }
- ...
複製代碼
測試一下~ 現在應該多點.... 也太密了吧
那現在需要做的就是... 把數量減少
順帶一提, 除了在 MonoDevelop 裡面直接改預設數值之外, 還可以在 Unity 裡面直接修改的
基本上全部在 MonoDevelop 裡面定義的公用變數都可以在 Unity 裡面作個別修改, 換句話說, 同一段程式可以重複使用的同時也可以有不同的參數
所以這次可以這樣改:
現在應該會看到舒服多了吧? (笑
雖然如此, 但不也覺得太單調了吧? 每個環都是一模一樣的, 一點考驗性也沒有
現在就來難點的東西了囉~ 讓那些環都隨機起來好了
現在回去 "PartsBehavior" 修改修改吧:
- ...
- private MeshFilter meshFilt; // 形狀的處理器
- private Mesh initMesh; // 起始的形狀
- public Mesh mesh1; // 第一個形狀
- public Mesh mesh2; // 第二個形狀
- public Mesh mesh3; // 第三個形狀
-
- float rotatespeed;
- // Use this for initialization
- void Start () {
- meshFilt = gameObject.GetComponent<MeshFilter>(); // 取得形狀處理器
- initMesh = meshFilt.mesh; // 定義起始形狀
- }
-
- // Update is called once per frame
- void Update () {
- if(gameObject.transform.position.y >= endpos) { // 當 Y 座標大於結束位置時
- ...
- switch(Random.Range (0, 3)) { // 隨機改變形狀
- case 0: meshFilt.mesh = initMesh; break;
- case 1: meshFilt.mesh = mesh1; break;
- case 2: meshFilt.mesh = mesh2; break;
- case 3: meshFilt.mesh = mesh3; break;
- }
- ...
複製代碼
再回去 Unity, 把其餘的障礙物也定義到程式裡吧:
點 Mesh 1, Mesh 2,... 右邊的圓圈選擇吧
現在應該沒有那麼單調了
再來, 讓那些障礙物旋轉吧~
在 "PartsBehavior" 加入這些程式:
- ...
- float rotatespeed;
- // Use this for initialization
- void Start () {
- ...
- rotatespeed = (Random.value - 0.5F) * 2;
- }
- // Update is called once per frame
- void Update () {
- if(gameObject.transform.position.y >= endpos) {
- ...
- rotatespeed = (Random.value - 0.5F) * 2;
- }
- ...
複製代碼
現在再測試應該會轉了
下次我會再發佈障礙物判定的教學等等~
這次教學的參考專案:
以上的教學我不介意轉載, 但轉載前請先通知一下, 謝謝