2018年1月19日 星期五

[Unity] Unity入門教學(二) - 當物件撞上了物件

Unity入門教學(二)

在上次的物件移動中,球體之所以可以在地板上移動是因為球體跟地板這兩個物件中都帶有碰撞器(Collider)的零件,這個零件可以使物件實體化但並不具物理特性.

所有實體化的物件可以跟有剛體的物件產生碰撞的,預設的所有碰撞並不會觸發任何其他行為,在上一次的練習裡,一開始球體是會往下掉到地板上,當球體接觸到地板時,這兩者也只是接觸著而已,並沒有其他任何事情發生.

這次我們試著加入新的物件,讓球體碰撞該物件後,讓該物件消失.

首先在場景中新增一個Cube物件 (Game Object > 3D Object > Cube),把Position改為(2, 1, 2),或隨個人喜好.


接著在Cube裏加入一個Script,就命名為CollideCube好了.

開始編輯Script (滑鼠雙擊),把預設的Start跟Update兩個方法移除後,加入一個void OnCollisionEnter(Collision collision)的方法.

這個方法也是官方定義的,功能是用來偵測Collider的碰撞,這個方法通常是使用在被碰撞物件的身上. 當物件被碰撞時,會執行方法裡面的程式碼. 我們在裡面寫了一行Destroy(gameObject),Destroy是用來銷毀物件用,需要將你想銷毀的物件放進去執行就可以了,要注意的是放進去的資料型態一定是要GameObject才能執行. 試著存檔後執行看看吧.

附帶說明一下,OnCollision這系列會有三種方法可以使用,分別是OnCollisionEnter, OnCollisionStay, OnCollisionExit,分別代表著接觸到碰撞體的瞬間、碰撞後未分開及與碰撞體分開的瞬間這三種情況,可以視自己的需求使用. 在這邊也可以試試看把OnCollisionEnter改為OnCollisionExit,執行看看會有什麼不一樣吧.

大家在執行時有沒發現到,當我們使用碰撞使物件消失時,會有一點點的延遲產生,因為必須先讓球體撞到方塊後才會觸發摧毀方塊,這樣在這個遊戲上顯得有點不流暢,那麼該怎麼處理這種狀況呢?

我們先前提到Collider這個零件可以讓物件實體化,在Collider裡面有個設定叫做觸發器(IsTrigger)的選項,當這個選項被勾起時,這個物件將不再被實體化,而是變成了一個可觸發範圍,也就是這個物件會變成可被穿透的.

當觸發器被勾選時,原本在程式裡面所使用的OnCollision系列的方法自然就失效了,因為已經撞不到了,那該怎麼辦呢?? 官方另外提供了OnTrigger系列的方法可以使用,跟OnCollision系列一樣分為三個OnTriggerEnter、OnTriggerStay及OnTriggerExit,分別代表著剛接觸到這個觸發範圍的瞬間、停滯在觸發範圍內及離開觸發範圍的瞬間這三種狀況,在這裡,就讓大家自己試著去把碰撞改為觸發,親自體驗一下兩者的不同吧.


2018年1月18日 星期四

[Unity] Unity入門教學(一) - 讓物件動起來

Unity入門教學 (一)

在Unity的世界裡,每個專案(Project)都是由一個或多個場景(Scene)所組成,而每個場景則是由一個或多個物件(GameObject)所構成.

現在就讓我們來建立一個新的專案吧!

啟動Unity後,會看到如下圖的畫面.

點擊右上角的New

輸入專案名稱,指定好專案存放位置就可以點擊Create project建立專案了.

有了專案後,Unity會先幫我們建立一個預設的場景,在3D專案中會有一個定向光(Directional light)及一個攝影機(Main camera).

點擊場景中的物件,可以看到物件的內容(Inspector),也可以對物件內容做修改.

在物件中可以加入各式各樣的零件(Component),每個零件都有不一樣的功能,而每個物件一定有一個最基本的零件存在且不可移除,它就是Transform.

Transform的功能是用來表示每個物件在場景中的位置(Position)、旋轉角度(Rotation)以及大小(Scale).


定向光及攝影機都是由Transform加上其他零件所組成,比方說定向光 = Transform + light


接下來,讓我們試著建立新物件吧!

在Hierarchy裏點選右鍵 > 3D Object > Plane


一個3D平面就產生了,接著再產生一個Sphere

由於這兩個物件的Position是一樣的,所以會看到兩個物件重疊在一起,試著把Sphere的position中的Y值改成1吧,應該會看到下圖的畫面

這時候試著點擊畫面上方的播放鍵,會發現....完全沒事情發生呢,因為目前的物件都只有外型跟碰撞器,並沒有其他零件讓它們可以有其他功能,所以接下來我們要試著要在物件裡加入新的零件了.

點擊Hierarchy中的Sphere物件,在它的Inspector點擊下方的Add Component,幫Sphere加入剛體(Rigidbody).





再點一次播放鍵試試看

現在Sphere會直接往下掉了,這是由於在它身上我們加入了剛體,這個零件主要是讓物件具有物理特性,像是重力、質量、阻力、受力及碰撞等等.

再來進入這篇的主題了,要如何讓物件動起來呢?答案是我們可以透過將腳本(Script)當成零件加進物件中,讓物件照著我們寫的腳本去動作就可以了.

在Sphere中加入新的零件,我們這次選擇New Script


命名腳本名稱及使用的程式語言,Unity目前只支援C Sharp及 Java Script兩種,筆者使用的是C Sharp. 點選Create and Add.


Inspector下方就多了一個Script 零件了


接著我們要開始編輯剛剛產生的腳本檔案,產生出來的檔案都會在Project這個視窗底下的Assets區裡面,我們可以看到剛產生的腳本,請點擊兩下開啟.


順利開啟後會看到下圖的程式碼,這是每個Script產生時Unity會預先寫好的東西.


接著就要開始寫腳本了,沒有程式基礎的朋友們也不用太緊張,我們會一步一步地教學跟說明喔.

在寫任何腳本前,先思考一下這個腳本到底要做什麼? 想清楚後,依序在腳本內寫好每個步驟,腳本就完成了,就如同現實生活中你想做的每件事,其實都是有分解動作的,比方說你想喝一杯水,那麼首先你必須先取得這杯水,再用手拿起來往嘴巴倒或是透過吸管吸取,最後吞嚥. 你可能覺得這不是大家都知道的事嗎? 沒錯,這是大家都知道的事,也就是所謂的邏輯,邏輯並沒有你想的那麼困難,你只是被邏輯這兩個字所誤導了.

我們現在希望能夠 讓玩家透過鍵盤去操控Sphere,讓它能在Plane上移動,那麼這件事會需要有哪些步驟呢??

1. 取得Sphere的剛體:剛體代表著Sphere的物理特性,也就是要對它施力的話,必須是施力在剛體上.

2. 取得外部輸入:取得鍵盤按鍵輸入的數據,才能去計算到底要對剛體施多大的力.

3. 對剛體施力:透過前面取得的零件跟數據,計算出力的大小並施加在剛體上.

將動作分解好後,一步一步做做看吧!

1. 取得Sphere的剛體



首先,先大概知道一下每個腳本是由一個或多個Class組成,而每個Class底下可以有一個或多個Method. Class跟Method的內容都是被定義在大括弧{}內. Method可以設定被呼叫後會不會回傳結果,需要的話就會在Method名稱前面加上回傳結果的資料型態,不需回傳的話就設定為void即可.

在上圖中就可以看到有一個叫MoveSphere的class,而裡面包含了一個全域變數rb跟一個不需回傳結果的方法Start.

什麼是全域變數呢?? 簡單來說,宣告在class內且method外的變數,都可以讓class內的method使用,所以我們叫它做全域變數.

void Start() 這個方法是官方定義的腳本生命週期的其中一個,其他生命週期中的方法可以參考這裏. void Start() 這個方法只有在物件初始化完畢後會執行一次,所以我們可以在void Start()裡面去取得剛體. 取得的方法是gameObject.GetComponent<Rigidbody>(),這裡需要注意的地方有三個:

1. 在腳本中小寫的gameObject代表著掛載這個腳本的物件,所以當用gameObject.getComponent<Rigidbody>()時,是指取得目前這個物件底下的Rigidbody零件.

2. getComponent<>()的<>裡面是可以替換成各種零件,像是getComponent<Rigidbody>(),getComponent<Sprite>().

3. 如果想取得的零件是script,<>裡面需要放置script name,像是getComponent<MoveSphere>();

2. 外部輸入

透過Input.GetAxis("Horizontal") 及 Input.GetAxis("Vertical"),我們可以取得水平及垂直軸的輸入狀況,預設是透過鍵盤的上下(垂直)左右(水平)四個方向鍵來輸入,取得的輸入數值範圍會介於-1~1之間,型態是float,就是你持續按了上方向鍵時,輸入得值最大就是1,反之是-1.


在上圖中,我們先建立一個void FixedUpdate() 這個方法,這個方法也是官方定義的,這個方法會週期性的執行,間隔時間預設是0.02sec,可以透過Edit > Project Setting > Time去修改.


接著我們在FixUpdated裡面宣告了兩個float的變數,分別去接收Input.GetAxis得到的值,得到後再新增個三維向量變數 Vector3 movement,這個Vector3是要拿來當作對剛體施加的力,由於是3D,所以我們把水平軸的值放到Vector3的x,垂直軸則放在Vector3的z,注意喔,不是放在y而是z.

3. 施力

我們先設定一個全域變數speed,資料型態是int,且在前面加上public,這樣代表這個全域變數是對外開放的,一但設定了之後,在Inspector裏就可以指定該變數的值,如下圖.


再來就是對剛體施力了,我們先前已經先拿到了剛體rb,所以直接輸入rb.AddForce(),再把施力大小放進()裏,就完成了,在上一個步驟我們定義力量大小是movement,將movement乘上speed放進()裏,在Inspector設定剛剛的speed後存檔並播放,試著使用方向鍵移動看看吧!

最後完成的程式碼如下圖.