目的:
這裡分享在球體表面生成物件的開發思路,透過C Sharp Script ,亂數生成X,Y的座標值,並帶入球型方程式得出一組座標值,並可將亂數值控制在半球體或水平線高度以上。可自訂隨機生成數次。本代碼以滑鼠觸發,每按一下可生成(Instantiate)數個物件。
程式主要兩大部分,第一部分為亂數生成座標,並最後在隨機控制Z軸座標,生成在球面的左側或右側。第二部分為生成數個物件的程式碼。
成果:
將物件亂數生成在球體表面。
原始程式碼:
首先,將此原代碼複製貼上另存至你的Script中。
這邊暫稱Spawn Orange,可以自己改變名字。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnOrange : MonoBehaviour
{
public float tempX, tempY, tempZ;
private float tempZ2;
public float BallToSpawnRadius;
public GameObject ToBeSpawnObject;
public int SpawnTimes;
private float tempSQRTRadius;
public float clampedSpwanHeight;
[SerializeField] Transform refPos;
private int i=1;
// Start is called before the first frame update
void Start()
{
//check if the original reference object is null, give 0,0,0 as ref.
if (refPos == null)
{
Vector3 RandPos = new Vector3(0f, 0f, 0f);
}
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
i = 1;
while (i < SpawnTimes)
{
PreCalculateSphere();
i++;
}
}
}
public void PreCalculateSphere()
{
//Randomize Oritentation on sphere
// 球面的方程式為(x−x0)2+(y−y0)2+(z−z0)2=r2
tempSQRTRadius = Mathf.Pow(BallToSpawnRadius, 2);
tempX = Random.Range(-BallToSpawnRadius, BallToSpawnRadius);
tempY = Random.Range((0+ clampedSpwanHeight), BallToSpawnRadius);
tempZ2 = tempSQRTRadius - (Mathf.Pow((tempX - refPos.position.x), 2) + Mathf.Pow((tempY - refPos.position.y), 2));
if (tempZ2 > 0 )
{
tempZ = Mathf.Sqrt(tempZ2);
//Debug.Log("TempX=" + tempX.ToString() + " " + "TempY=" + tempY.ToString() + " " + "TempZ=" + tempZ.ToString());
SpawningOrange();
}
else {
PreCalculateSphere();
}
}
public void SpawningOrange()
{
// Random Z direction
float Zdirection = Random.Range(0,10);
if (Zdirection < 5)
{
tempZ = -tempZ;
};
Vector3 RandPos = new Vector3(tempX, tempY, tempZ);
Instantiate(ToBeSpawnObject, RandPos, Quaternion.identity);
}
}
開發思路重點提要:
A. 第一個步驟就是要先找到數學方程式,可以到Google搜尋 球型方程式。
若設球面S的球心O(x0,y0,z0),半徑為r,
則球面的方程式為(x−x0) 2 +(y−y0) 2 +(z−z0) 2 =r 2
B. 再將此方程式轉為Unity3D 的C#程式碼。
這邊用到幾個數學函式 Mathf.*** API:
Pow 就是平方,乘兩次的意思。
Sqrt 就是開根號,英文叫做Square Root。
Abs 就是取絕對值,就是去掉負的直接轉正值。
上述的函數用法可以點擊文字連結,直接跳出原廠說明文件。
這段就是計算球體的方程式,先亂數生成兩個數值當作X與Y。
Z則是由球型方程式反推出來。此時會有兩個解,+Z或-Z,我們再利用亂數隨機給Z值正負值。
tempSQRTRadius = Mathf.Pow(BallToSpawnRadius, 2);
tempX = Random.Range(-BallToSpawnRadius, BallToSpawnRadius);
tempY = Random.Range((0+ clampedSpwanHeight), BallToSpawnRadius);
tempZ2 = tempSQRTRadius – (Mathf.Pow((tempX – refPos.position.x), 2) + Mathf.Pow((tempY – refPos.position.y), 2));
而Y值有加上一個 clampedSpwanHeight ,如此一來就能規範生成的高度。
使用方法:
套用此程式碼的方式非常簡單,先將Script拖曳到場景中的任一個物件。
並且指定好你要生成的物件ToBeSpawnObject,輸入要生成的次數SpawnTimes也就是數量,更重要的是球體的半徑BallToSpawnRadius。最後可以輸入要限制的高度,也就是從多高的地方開始長出ClampedSpawnHeight。而RefPos就是圓心的位置,若不指定則從0,0,0原點當作圓心開始生成。
如此一來按下撥放,在畫面內點一下滑鼠左鍵,就能依照設定的生成次數,自動隨機亂數生成物件數量。
可自行改變程式碼把半球體表面生成應用在需要的地方,例如自駕車的圓環障礙物等。
結論:
本文透過一個球型亂數表面生成物件案例,提供大家開發幾何形數學的開發思維,也包含了亂數產生數值,以及物件生成的方法 (Instantiate )。
同樣的思路可以用在任何數學相關的開發,例如正弦波位置、方塊物體等等。
都是先找方程式,再將座標或Transform產生出來,最後再做進一步的應用。希望對有需要的人有幫助。