切換
舊版
前往
大廳
主題

【碰撞器應用+UI應用】三、讓程式以Tag方式與物件連結

澄鷹 | 2018-07-25 19:57:10 | 巴幣 110 | 人氣 3260

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

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

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

  在【新手入門】四、用程式操控物件&程式說明中,我們有用程式取得元件過。不過那時候取得元件只有單純寫了一行:

變數名稱= GetComponent<元件名稱>();

  就搞定了。

  原因在那一節中已經有提到,因為腳本是直接套用在該物件上,所以直接用這行取得元件時,會直接取得該物件的元件。

  那麼,假設今天想要取得的元件並不是在腳本被套用的物件中呢?

  這會有兩種做法:

    1.在程式中新增公開變數(public),再回到Inspector中將想套用的物件或元件拖曳到公開變數的欄位裡。

    實際操作會長這樣:

程式

Inspector

    只要在程式中新增了public變數,在Inspector中就會多出一個可以被指定的欄位,至於該欄位應該放入甚麼類型的東西,就是寫在宣告變數時的資料型態。

    這種方法用在某些時候會很方便,但是當一個遊戲有許多物件或元件的取得都是以公開變數指派的方式來設定時,那麼該物件在Inspector中就會變得很長一串。像這樣:


    這會造成很多問題:

      a.調整其他元件的設定時會變得很不方便

      b.程式中的變數有異動,那麼那些欄位都需要重新設定。

      c.如果有一個以上的腳本要取得同一個元件的數值,會變得相當麻煩。

    所以,為了避免這種狀況,通常會使用第二種方法。

    2.以Tag方式與物件連結。

    這就是我們這節要討論的方法了,前面第一種解決方法有興趣的人可以先試試看,但這次我們就先不討論那個方法。

    那麼,開始吧。

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

  上一節,我們已經在場景中新增了我們這次更新所需要的所有物件,但是甚麼設定都還沒有。

  這次我們想要用tag的方式,取得「Score」和「Healthy」兩個物件,取得之後,才有辦法更便利地調整「Score」和「Healthy」兩個物件裡的元件數值。

  首先,我們需要在「Score」和「Healthy」兩個物件中分別設定tag。

  我們先選取Score,查看他的Inspector中,名稱下面的Tag。


  「Untagged」是幾乎所有物件的預設標籤,就是甚麼都沒設定的意思XDD

  把它點開之後,可以看到有許多標籤(tag)可以設定,不過這些都不是我們想要的,所以需要自己新增一個。

  點選最下方的「Add Tag...」


  在Inspector中,會跳出這個頁面:


  下面的「Sorting Layers」與「Layers」我們暫時先不理它。點選「Tags」下方白色框框的右下角,一個「+」的符號來新增標籤。


  在跳出來的視窗中,便是我們所要新增的標籤的名稱。在這裡,我將標籤的名稱設定為「Score」,然後按下Save。會變成這樣:


  然後,回到Hierarchy中,再點選一次Score物件。點選剛剛顯示「Untagged」的地方,應該可以發現,在那一串清單當中多出了一項「Score」


  不要猶豫,按下去吧!

  現在,我們在上一節新增的Score物件,已經有了一個我們自己設定的、名為「Score」的標籤。


  Score物件的標籤已經設定完畢。再來還剩下Healthy物件的標籤。

  回到Hierarchy點選「Healthy」物件後,以同樣的方法新增一個名為「Healthy」的標籤,並且把他設定為「Healthy」物件的標籤。


  ※注意,我們要設定的tag是在「Healthy」物件中。記得不要不小心把標籤設定在「Healthy」的子物件裡,這在之後取得元件時可能會發生錯誤。

  「Score」和「Healthy」兩個物件的標籤都設定完之後,再來就是需要用程式取得這兩個物件。

  在Hierarchy中點選Player,雙擊MainCS腳本開啟。


  直接上程式碼:

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
30
31
32
33
34
35
36
37
38
39
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;                //a.

public class MainCS : MonoBehaviour {

 Transform trans;
 Rigidbody2D rigid;
 Text score;                      //b.
 Slider healthy;                   //c.

 // Use this for initialization
 void Start () {
  trans = GetComponent<Transform>();
  rigid = GetComponent<Rigidbody2D>();
  score = GameObject.FindGameObjectWithTag   //d-1
   ("Score").GetComponent<Text> ();        //d-2
  healthy = GameObject.FindGameObjectWithTag
   ("Healthy").GetComponent<Slider> ();
 }

 // Update is called once per frame
 void Update () {

  print ("score: " + score.text + ", healthy.value: " +   //e-1
   healthy.value);                 //e-2

  if (Input.GetKey(KeyCode.LeftArrow)) {
   trans.Translate(Vector2.left * Time.deltaTime);
  } else if (Input.GetKey(KeyCode.RightArrow)) {
   trans.Translate(Vector2.right * Time.deltaTime);
  }

  if (Input.GetKeyDown(KeyCode.UpArrow)) {
   rigid.AddForce(Vector2.up * 200);
  }
 }
}
 
  我新增加了幾行程式碼,我們來看看新增加的那幾行程式,到底有甚麼功用:

  a.using UnityEngine.UI;
  在【新手入門】第四節中的程式說明有提到,最上面的using是腳本建立時就會先寫好的,如果有需要的話再自己增加東西。
  如同那一節提到的,我們這次會用到UI介面。所以需要增加
這一行程式。我們之後在使用UI介面的程式時,程式才能運作。

  如果不太明白「不能運作」的概念,不妨把這一行程式刪除看看:
  在MonoDevelop中,所有我們這次有新增的程式,都有一部份變成了紅字。

  然後再回到Unity觀看,會發現在Console中跳出了兩個錯誤:
  這兩個錯誤直接翻譯的意思是:「找不到『Text』與『Slider』資料型態,是否漏了『UnityEngine.UI』或『UnityEngine.Experimental.UIElements』?」

  因為我們在程式裡有宣告了兩個分別為「Text」和「Slider」資料型態的變數。但是他找不到有這兩個資料型態的存在,這兩個資料型態完全不存在於「System.Collections」、「System.Collections.Generic」、「UnityEngine」這三個類別裡。

  所以我們需要新增這行程式,讓我們的程式能使用「UI」類別裡的東西。
  如此一來,「Text」與「Slider」資料型態就可以使用了。
  b.Text score;
  我們之後會需要用「Score」物件裡的「Text」元件來顯示我們的分數。由於分數會在遊戲中不停地修改,所以我們需要宣告一個Text資料型態的變數,讓我們之後可以任意改變Text顯示的文字。變數名稱就設定為「score」
  c.Slider healthy;
  之後我們的角色會因為碰觸到我們先前新增的「Damage」與「Complement」,而讓血量產生變化。
  所以我們需要宣告一個Slider資料型態的變數,讓我們之後可以對Slider的數值進行修改。變數名稱就設定為「healthy」
  d.score = GameObject.FindGameObjectWithTag ("Score").GetComponent<Text> ();
  剛剛已經宣告了score的資料型態是Text,不過這次與上一次不同,這次想取得的「Text」元件並不在這個腳本所在的物件(Player)裡。
  不過,我們剛剛已經有把我們想取得元件的那個物件,掛上了一個名為「Score」的標籤。
  所以我們先用GameObject.FindGameObjectWithTag ("Score")在場景中找到那個物件,找到這個物件之後直接取得這個物件底下的「Text」元件,然後把它丟到「score」變數中。
  這就是這一行程式實際上做的事情。

  前半段GameObject.FindGameObjectWithTag ("Score")是找到具有這個tag的物件之後,回傳整個物件(GameObject),後半段GetComponent<Text> ()就是我們在【新手入門】中有提到的,取得元件的寫法。

  ※前半段的程式碼,在Unity API是查不到的,不過有一個用法完全相同的程式:
  
  這兩個程式是可以互換的。
  e.print ("score: " + score.text + ", healthy.value: " + healthy.value);
  這行其實沒有甚麼特別的,只是在Console中印出文字而已,在【新手入門】二、操作介面介紹中有介紹到Console裡出現的訊息類型,這就是屬於第一種:「訊息」

  用print來印出一段文字,在遊戲製作中可以用在除錯、提示上,是很方便的。

  前面已經宣告過Text、Slider資料型態的變數,並且已經用Tag的方式取得元件了。但是該如何知道是否真的有取得元件?我們就用這行程式來顯示我們所取得的Text元件裡的文字,並且取得血條當前的數值。

  由於這段程式是放在Update()中,所以遊戲開始之後,會不斷地印出這串文字。

  如果已經做到這裡,不妨回到Unity畫面,將Console放在旁邊,並按下試玩按鈕試玩看看。如果有看到Console中不停地出現文字,那就表示元件取得已經成功了。
 

  ※若上了程式碼後回到Unity場景中並點擊試玩,發現有以下錯誤:


  這兩個錯誤的意思就是它找不到我們叫它找的物件或元件。

  只要程式嘗試抓取物件或元件,但是卻無法在場景中找到該物件或元件時,就會出現這段錯誤訊息。

  所以如果出現這則錯誤訊息,那有可能是Tag的設定有錯誤:沒有設定到Tag、設定到錯的物件,或是Tag的拼字錯誤、大小寫錯誤等。

  如果出現這個錯誤,可以再回去好好檢查一下,看有哪個步驟出了問題。



  到目前為止,我們已經知道該如何用tag的方式取得其他物件中的元件。我們沒有讓物件在Inspector中的元件底下有多餘的欄位,也沒有讓場景多出甚麼不該有的東西,原來的製作環境在沒有產生多餘東西的狀況下就取得了某個指定的物件(或元件)。

  這在日後的遊戲製作一定會有很大的幫助。

  學會了新的取得元件的方法,有沒有覺得Unity似乎也沒有想像中的這麼複雜阿

  在這一節中,我們已經將程式與UI介面連結起來。日後若有需要更改UI類型的元件數值,就可以直接用我們今天所宣告的變數去調整。

  不過,在我們原本的構想中,只是連結還不夠,我們還沒把我們的遊戲改造成心目中的模樣。

  所以下一節,我們會開始著手功能的部分。主角碰觸物件後扣血、補血、加分,並且將這些變化顯示在UI物件中,開始進入程式的世界~

  那麼,這次的教學就到這裡結束,我們下一節再會。


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

  【碰撞器應用+UI應用】


  三、讓程式以Tag方式與物件連結


  補、遊戲製作談
 
送禮物贊助創作者 !
0
留言

創作回應

杏紙
不好意思我想請問一下,我的console 印出來會是"Score(UnityEngine.UI.Text),Healthy(UnityEngine.UI.Slider)"
我想請問一下可能是哪裡出了問題呢??謝謝><
2020-08-31 13:11:12
澄鷹
方便讓我看一下你的程式嗎?
我想有可能的原因應該是因為在印出資訊的時候
不小心把score.text的.text與healthy.value的.value省略了
所以她才會印出他原本的元件資訊而不是元件內的值
可以檢查看看
2020-08-31 18:52:50
杏紙
有了><!!!照著修改之後就可以正常輸出了!!
真的是.text跟.value沒有打的原因@@
謝謝你><
2020-09-01 19:23:46
澄鷹
漂亮[e12]
2020-09-01 21:01:41

更多創作