切換
舊版
前往
大廳
主題

【新手入門】四、用程式操控物件&程式說明

澄鷹 | 2018-05-28 23:38:42 | 巴幣 6 | 人氣 2807

  在上一節,我們把我們在這次的練習中所需要的所有物件都建立好了。這次就來說明一下如何將程式碼套用在物件上。也會稍微說明一下套用上去的程式碼究竟有甚麼樣個功能。

  ※教學內容若有錯誤,歡迎在下方留言向我反應,感謝你們~ 

  ※有些程式碼的說明可能不完全,那可能是我目前還不知道XDD

========================================================================
  在繼續製作以前,我們先稍微檢查一下之前列出來的架構需求:

  1.2D卷軸遊戲     #如果你的畫面最後與我上一節相同,那麼這一點其實已經做到了。
  2.我想要有一個不知道長甚麼樣子的主角能夠被我的方向鍵控制。他可以:
    a.左右行走
    b.跳
  3.我希望能有一塊地板可以撐住我的主角。
  4.鏡頭可以跟著主角移動。

  現在,我們只剩下角色操作的部分,以及要讓鏡頭跟著主角移動。
  開始之前,稍微透漏一下,讓鏡頭跟著主角移動,其實只需要一個很簡單的動作。期待一下吧XD

  好的!那麼,繼續製作。

-----------------------------------------------------------------------------------------------------------------------------

  由於需要透過「程式」讓玩家可以被程式控制,所以,我們需要在Project中新增「C#腳本(C# Script)」
  在Project中點擊右鍵→Create→C# Script

  建立C#腳本之後,就可以為他取一個你自己看得懂的名字,在這裡我將它命名為「MainCS.cs」
  現在,在Assets資料夾中,會有一個C# Script的檔案。

  ※如果在製作過程中,發現自己不小心按到了甚麼,結果MainCS.cs不見了,有可能是因為你按到了左邊上面那一塊「我的最愛」的清單:
  把它點回Assets就有了。
  如果點回Assets之後,發現還是沒有MainCS.cs,那就表示你沒仔細看我教學......還沒新增腳本。

  ※如果你的Assets資料夾裡面的檔案圖示非常小,小到變成了清單:
  那你可以調整右下角的卷軸,那可以幫你調整檔案圖示的大小。

  建立完成之後,把「MainCS.cs」雙擊點開。

  ※Unity的IDE有兩種,如果在安裝Unity時沒有特別設定的話,可能會同時有「Visual Studio」與「MonoDevoloped」兩種。看自己習慣用哪一個就用哪一個,我習慣用Mono。
  如果需要更改每次開啟腳本的預設程式,可以到Edit→Preferences...

  會跳出這個視窗:


  然後可以到External Tools→External Scripts Editor選擇自己的預設程式。


  打開腳本之後,廢話不多說,直接上程式碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MainCS : MonoBehaviour {                         //-----a.

    Transform trans;                                                         //-----b.
    Rigidbody2D rigid;                                                      //-----c.

    // Use this for initialization
    void Start () {                                                               //-----d.
        trans = GetComponent<Transform>();                   //-----e.
        rigid = GetComponent<Rigidbody2D>();                //-----f.
    }
    
    // Update is called once per frame
    void Update () {                                                           //-----g.
        
        if (Input.GetKey(KeyCode.LeftArrow)) {                  //-----h.
            trans.Translate(Vector2.left * Time.deltaTime);   //-----i.
        }else if (Input.GetKey(KeyCode.RightArrow)) {       //-----j.
            trans.Translate(Vector2.right * Time.deltaTime); //-----k.
        }

        if (Input.GetKeyDown(KeyCode.UpArrow)) {          //-----l.
            rigid.AddForce(Vector2.up * 200);                      //-----m.
        }
    }
}

  在開始說明程式碼以前,我們先把腳本套用到我們所需要的物件──「Player」上。

  套用腳本的方法有兩種,
    第一種:直接在Assets裡的MainCS.cs檔案拖曳到Player物件上。
    第二種:點選Player物件,在Inspector中新增元件,元件名稱就是腳本的檔名:

  套用上去之後,會看到Player物件最下方出現了腳本的元件,像這樣:
  如果看到這個,就表示已經成功套用了。很簡單吧XD

  若是迫不及待想要開始操縱角色的話,可以按下試玩鈕。
  『方向鍵左右鍵操控方向,上為跳。』
  讓一個物件動起來的感覺,是不是頗有成就感啊?

-----------------------------------------------------------------------------------------------------------------------------

  再來,我要開始說明上面那段程式碼了。

  最上面那三行using是建立腳本之後他自己就會先做好的。如果程式碼中會用到它其他的東西,就會需要自己增加using的內容,不然程式碼可能會無法運作。
  比如說如果之後需要在遊戲裡面增加UI介面,並且用程式碼去控制UI介面的功能的話,那到時候就會需要在上面增加一行:
  using UnityEngine.UI;
  不過,這次的練習中不需要再另外using,所以這部份就跳過,直接用他已經預設好的內容就可以了。

  再來我會找一些比較重要的程式稍微說明一下:
  a.public class MainCS : MonoBehaviour
  這行也是已經預設好的寫法,基本上不用改,但是要特別注意的一點是:
  這裡的「MainCS」就是這個腳本的檔名,必須完全相同,否則會錯誤。
  b.Transform trans;
  我們待會要用程式來控制角色移動,所以會需要「改變他的位置」,既然要改變他的位置,那一定會與控制物件位置的元件「Transform」有關。
  所以,這行程式就是宣告一個Transform資料型態的變數,並且將它命名為「trans」
  c.Rigidbody2D rigid;
  我們的目的除了讓角色可以移動之外,還要讓角色可以「跳躍」。「跳躍」這個動作是讓角色能夠「抵抗重力」而向上的力道。
  讓玩家能夠「抵抗重力」,會與Rigidbody 2D元件有關,所以,這行程式就是宣告一個Rigidbody 2D資料型態的變數,並且將它命名為「rigid」
  d.void Start ()
  這行是預設好的程式碼,在「Start ()」方法裡的程式,會在遊戲最一開始被執行一次
  所以這裡放的東西,通常都是變數的預設值、初始運算......等初始的資料。
  e.trans = GetComponent<Transform>();
  剛剛已經宣告過trans是一個Transform型別的變數。但是,如果只是宣告變數,那個變數並不存在任何意義,所以我們要在遊戲一開始的時候,告訴電腦:
  「這個trans變數,就是這個物件的Transform元件」我們以後要用trans這個名字來控制這個物件的Transform元件。

  GetComponent,取得元件。

  這個函數是用來取得元件用的,至於取得甚麼元件?就是寫在後面的<>中。

  ※注意:<Transform>()的()並不是多打的,是他必須這麼書寫,這個在Unity API中的範例有寫使用方法。
  有不知道的語法都可以上Unity API尋找,大多都能找得到解答,很好用的

  在我撰寫的程式中,我很直接地將trans變數指向GetComponent<Transform>(),或許有一些人會有疑問:他怎麼會知道我要的是這個物件的Transform?而不會指向其他物件的Transform?
  這是因為,我們這個腳本是直接套用在Player上面的,如果沒有特別撰寫,就是直接抓取被套用的該物件的元件。
  如果有需要在這個腳本抓取其他物件的元件,那會有進一步的作法,我們之後有機會再來探討這方面的問題。
  f.rigid = GetComponent<Rigidbody2D>();
  這行與e.相同,就是將rigid變數指向Player的Rigidbody 2D元件。

  ※由於e.與f.都是將一開始宣告的變數指定給欲控制的元件,屬於初始值宣告的一種,所以會習慣放在Start()方法裡。
  g.void Update ()
  這行也是預設好的程式碼,這點與d.一樣,不過,「Update ()」方法,是會在遊戲中的每一幀都執行一次,所以這裡面的程式,在遊戲中每一分每一秒都會被執行。它會持續不斷的執行這個方法裡面的程式。
  所以,如果在遊戲中有需要判斷時間的地方,大多都會被寫在這裡。
  h.if (Input.GetKey(KeyCode.LeftArrow))
  這一行是判斷式,整行的描述用口語來解釋就是:「如果玩家按著左方向鍵......」

  if應該不用解釋,這就是條件判斷的起點。
  Input.GetKey的回傳值是布林值,用來判斷玩家按住按鍵的狀態,如果按著,就回傳true,反之就回傳false。
  這點在Unity API也會有寫哦。

  但是,判斷玩家按著按鍵,是按著甚麼按鍵呢?在GetKey()的括弧裡面,我們可以放上「KeyCode.按鍵名稱」來指定判斷的按鍵。
  我在這裡使用了「LeftArrow」,來指定判斷的按鍵是左方向鍵。

  ※其實Input.GetKey有很多兄弟姊妹,它有許多類似的函數,可能會隨著遊戲需求不同而有不同的寫法,我順便趁這個機會介紹一下
    (1)Input.GetKey:就是我們所使用的這種,判斷為「按著」按鍵時。
    (2)Input.GetKeyDown:這是只有在按鍵按下去的那一瞬間,判斷為「按下」按鍵時。
    (3)Input.GetKeyUp:這是只有在放開按鍵的那一瞬間,判斷為「放開」按鍵時。
  i.trans.Translate(Vector2.left * Time.deltaTime);
  這一行開始要透過trans來控制物件的位置了。
  Translate()是用來移動物件的方法。括弧內需要放入向量型別的數值。我在裡面放入了Vector2.left
  Vector2是一種2D的向量型別,我直接用它原本就擁有left方法,讓這個物件朝向左邊移動。
  Vector2.left其實就是向量座標(-1,0)
  照上述所說,那麼trans.Translate(Vector2.left)不就可以讓物件向左移動了嗎?那後面那一串Time.deltaTime是甚麼?
  Time.deltaTime是遊戲中每一幀所經過的時間,如果直接用trans.Translate(Vector2.left)來控制物件移動,那麼物件每幀移動的距離會非常大、移動速度會非常快。所以我需要把它乘以遊戲中每一幀經過的時間,把他的數值縮小,好讓它能夠在每一幀移動「與每幀經過時間相同的數值」的距離。
  如果還是不懂,可以偷偷把Time.deltaTime刪掉然後試玩看看XDD
  j.else if (Input.GetKey(KeyCode.RightArrow))
  概念與h.相同,只是將LeftArrow改成了RightArrow。
  我會將左右鍵的判斷寫在同一個if裡面,是為了避免左右鍵一起按造成主角無法移動的現象。
  k.trans.Translate(Vector2.right * Time.deltaTime)
  概念與i.相同,也只是將left改成了right。
  l.if (Input.GetKeyDown(KeyCode.UpArrow)) {
  這裡與h.j.不一樣的地方是,我把GetKey改成了GetKeyDown。
  在g.有提過,Update()方法裡面的程式,會在每一幀都被執行,所以如果我的判斷是「按著」方向鍵(GetKey)的話,那主角就不會有跳躍的感覺,而是只要玩家一直按著,主角就會不斷的往天空飛。這並不是我們想要的效果。
  GetKeyDown,會讓判斷專注在「按下的那一瞬間」。所以不管玩家有沒有按著,只要有按下去,就只會執行一次。這才是我們希望有的效果。

  m.rigid.AddForce(Vector2.up * 200);
  這一行是透過rigid來控制Rigidbody 2D元件。
  AddForce,增加力。是Rigidbody2D裡的方法,功用是針對這個物件,讓他擁有無形的「力」
  在剛剛c.宣告Rigidbody 2D變數的時候,有提到「跳躍」這個動作是讓角色能夠「抵抗重力」而向上的力道。
  所以我們需要用這個方法,讓玩家擁有一個「往上」的無形的「力」。
  於是,我們在AddForce()方法的括號中,加上剛剛學會的Vector2.up,來指定這個「力」的方向。
  至於後面的 * 200,可以任意調整,如果想讓玩家跳高一點,就把數值調高,反之則然。


  很好,現在我們的主角可以被我們的方向鍵控制左右行走、跳躍了。我們只剩做後一個步驟。
  ──讓攝影機隨著玩家移動。

  這個步驟其實相當簡單,在沒有任何其他要求的情況下,只要把「Main Camera」物件丟到「Player」下面就好。像這樣:

  現在,點擊Play試玩遊戲,攝影機是不是緊緊跟著主角不放阿XD?

  最後,再來做完成的確認:

  1.2D卷軸遊戲
  2.我想要有一個不知道長甚麼樣子的主角能夠被我的方向鍵控制。他可以:
    a.左右行走
    b.跳
  3.我希望能有一塊地板可以撐住我的主角。
  4.鏡頭可以跟著主角移動。

  今天把較為基礎的程式方面的問題釐清了。
  我們已經了解該怎麼用程式控制元件,也了解了Start()與Update()的差別。
  懂得如何判斷按鍵,以及按鍵狀態的各種寫法。
  最簡單的連結大致上都了解了。我們在程式這方面的教學也告一段落。

  下一節將會是這一章的最後一節。我會說明該怎麼把做好的遊戲匯出成執行檔,並且打包給其他朋友遊玩。

  那麼,這次的教學到此結束,我們下次再見!

========================================================================

  【新手入門】




  四、用程式操控物件&程式說明

送禮物贊助創作者 !
0
留言

創作回應

相關創作

更多創作