iT邦幫忙

2022 iThome 鐵人賽

DAY 8
0
自我挑戰組

Unity 基本功能實作與日常紀錄系列 第 8

Day8: Generate and Delete Random Position Object

  • 分享至 

  • xImage
  •  

實驗過程中常會需要有些目標點給受試者進行Target,如何隨機生成不同的距離與角度是很重要的,故我們今天先在 2D 平面上來實現,透過簡單的數學關係來達成我們想要的結果。三角函數是個很強大的,所以今天也會小試身手來創造在User 前面生成兩個隨機物件,且具有隨機距離與角度關係。

建置場景

  1. 首先我建立一個我想要生成的物件。我使用 Asset Store 的一個Open Package,名為 Meshtinit Free Chicken Mega Toon Series 裡面的公雞。因為我覺得很可愛。我們從 Window > Package Manager 去引入該 Package。

  2. 在左下角我們可以看到 Assets > Meshtinit Free Chicken Mega Toon Series > Prefabs, Prefabs 就會有我今天會需要使用到的公雞模型。 直接拉到 Scene 使用即可。

  3. 我們把該Prefab 拉到Scene 中。 接著就會看到 Hierarchy 自動生成該物件。 Reset 該物件上的 Transform 好讓其位置我們可以比較好控制。 Animator 目前在這邊不需要可以取消勾選,那是物件的動作行為,尚不需要。

  4. 接下來調整 Main Camera 的可視角度,更改 Position and Rotation。

新增腳本

  1. 首先新增一個空白物件 GenerateManagement ,並新增腳本元素 GenerateObj.cs。

  2. 開始撰寫文本上的內容。 因為這次包含三角函數的關係,但僅為 2D 平面的三角關係,所以並不會到很困難,但我這邊還是會細說每個步驟與宣告變數的意義。

  3. 首先宣告該當前公雞的位置,也就是目前 User 的位置。

public Transform ChickenObj;
  1. 宣告一個 Vector3 的變數好讓之後推算前面生成物件的位置時可以使用,不給任何公用型態預設就會是 private 型別。
Vector3 currentPosition;
  1. 為了要每次生成不同的角度與距離,我們宣告兩個陣列。
float[] angle = {0f, 30f, 60f, 90f, 120f, 150f, 180f};
float[] distance = {0.5f, 1f, 2, 2.5f};
  1. 宣告生成物件的List,這是為了要紀錄每個生成物件的位置,獲取一些Random 物件的一些資料。
List<GameObject> generateObj = new List<GameObject>();
  1. 想要生成的物件樣式與種類,我們也進行存取。注意到存取的型態要是 GameObject
public GameObject generateObjModel;
  1. 之後宣告一個生成物件的 ID, 幫助我們未來知道生成物件是誰,如同給個標籤。
private int ObjId = 0;

進入主程式

  1. 先想一下如果要在前方某一個角度與某一個距離生成物件,可以想一下該物件的原點向外的距離也就是 distance 一個半徑,那有角度、距離( distance)就可以透過 Cosine、Sine 來求出 deltaX, deltaZ。然後再從原點(User 位置) 向 x 軸與 z 軸延伸就會是新的座標點。 請注意到 Unity 是左手坐標系。現在觀察的是 2D 。前方為Z軸,側向為 X軸。

  2. 所以先定義該User(Chicken)原來的位置。

currentPosition = ChickenObj.position;
    1. 接著從剛剛設定好的 Distance, Angle Array,先隨機產生 Index,並透過隨機的Index 去取得元素。 接著將結果其顯示出來。
      隨機亂數生成的方法( 生成 initial ~ end-1 之間的亂數):
Random.Range(initial, end);
UnityEngine.Random.Range(initial, end); 
void randomObj()
    {
        int getAngle = Random.Range(0, angle.Length);
        int getDistance = Random.Range(0, distance.Length);
        float randomAngle = angle[getAngle];
        float randomDistance = angle[getDistance];   
        Debug.Log("Random Angle: " + randomAngle + ", Distance: " + randomDistance);
    }
  1. 開始撰寫整個核心,生成Object 的位置。 我這邊利用 Vector2 幫我儲存該 Delta X, Delta Z。請注意到這邊很重要的是隨機生成物件中使用Mathf.Sin, Mathf.Cos 的角度是徑度。
Vector2 offset = new Vector2(Mathf.Sin(randomAngle * Mathf.PI/180.0f), Mathf.Cos(randomAngle * Mathf.PI/180.0f)) * randomDistance;
  1. 套用在該生成物件上的 Vector3 位置資訊,我們要知道雖然我們處裡是在 2D 表面但要映射回3D表面。要注意到要從原來的位置往前推算,所以要加回剛剛的位置上的 x 與 z 的數值。
Vector3 newPosition = new Vector3(currentPosition.x + offset.y, 0f,currentPosition.z + offset.x);

概念如下:

float newX= Origin + distance * Mathf.Cos( angle * Mathf.PI / 180f);
float newZ = Origin + distance * Mathf.Sin( angle * Mathf.PI / 180f);
  1. 接著就將我們新的 x 座標與 z 座標就放進生成的物件上。這邊注意到 Instantiate內部的 Create Model 就是你想要生成物件的模型,之後會再 Unity 上去新增Prefab。 接下來就是新的 Vector3 去宣告新的位置。 因為 y 軸不變所以就以原點高度一致。後面者的 Quaternion.identity 說明就生成的方向就不變。
reateGenerateList[i] = (GameObject)GameObject.Instantiate(generateObjModel, newPosition, Quaternion.identity);
  1. 我們每次都要產生兩個物件在User前面,我們每次都要Radom該不同的角度與距離,這邊我們就將剛剛的所有總結起來。
void randomObj()
    {
        for(int i = 0; i < 2; i++)
        {
            int getAngle = Random.Range(0, angle.Length);
            int getDistance = Random.Range(0, distance.Length);
            float randomAngle = angle[getAngle];
            float randomDistance = distance[getDistance];   
            Debug.Log("Random Angle: " + randomAngle + ", Dista nce: " + randomDistance);
            Vector2 offset = new Vector2(Mathf.Sin(randomAngle * Mathf.PI/180.0f), Mathf.Cos(randomAngle * Mathf.PI/180.0f)) * randomDistance;
            Vector3 newPosition = new Vector3(currentPosition.x + offset.y, currentPosition.y ,currentPosition.z + offset.x);
            createGenerateList[i] = (GameObject)GameObject.Instantiate(generateObjModel, newPosition, Quaternion.identity);
        }
      
    }
  1. 增添一個刪除物件的方法。把我們剛剛生成的物件給刪除。 非常簡單。
void resetObj()
    {
        for(int i = 0 ; i < 2; i++)
        {
            Destroy(createGenerateList[i]);
        }

    }
  1. 撰寫一下控制方式,按下 L 為新增兩個隨機物件,按下 P 為刪除物件。
void Update() 
    {
        if(Input.GetKeyDown("l"))
        {
            randomObj();
        }else if(Input.GetKeyDown("p"))
        {
            resetObj();
        }
        
    }
  1. 回到 Unity 後,將其我們要的物件放置進腳本中。注意到要生成的物件放置成Prefab 中。

  2. 執行開始可以看到每次生成兩個以User 為基準向外看去的兩個隨機位置上的物件。

結論

  1. 今天說明到如何藉由簡單的數學關係生成隨機在User前方不同距離與角度的物件。
  2. 注意到 Mathf.Cos, Mathf.Sin 計算時需要使用到的角度是徑度。
  3. 隨機想生成的物件的方法、如何刪除不必要的物件。

上一篇
Day7: Understand Animation Curve
下一篇
Day9: Teleport in VR
系列文
Unity 基本功能實作與日常紀錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言