CullingGroupを使って、カメラから見ていない位置を検索してゲームオブジェクトをインスタンス化してみました。
概要
シーンに、配置位置を表すゲームオブジェクトを置きます。同じ位置にBoundingSphereを設定しCullingGroupでカメラからの可視性を判定をします。
CullingGroup.QueryIndicesメソッドを使って、カメラから見えていないBoundingSphereを簡単に検索できます。
カメラから見えていないところでゲームオブジェクトが出現します。
シーン
シーンにはSphereゲームオブジェクトを複数配置しています。ここにプレハブをインスタンス化します。
Sphereのメッシュレンダラーを無効にして非表示にしています。
スクリプト
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InvisibleSpawner : MonoBehaviour
{
// シーンのゲームオブジェクト
[SerializeField] Transform[] spawnPoints;
// プレハブ
[SerializeField] MeshRenderer spherePrefab;
CullingGroup cullingGroup;
float elapsedTime;
// Start is called before the first frame update
void Start()
{
// CullingGroupをインスタンス化
cullingGroup = new CullingGroup();
// カメラを設定
cullingGroup.targetCamera = Camera.main;
// BoundingSphereの配列を初期化
BoundingSphere[] spheres = new BoundingSphere[spawnPoints.Length];
// ゲームオブジェクトの位置にBoundingSphereをインスタンス化
for (int i = 0; i < spheres.Length; i++)
{
spheres[i] = new BoundingSphere(spawnPoints[i].position, 1f);
}
// BoundingSphereの配列を設定
cullingGroup.SetBoundingSpheres(spheres);
// BoundingSphereの個数を設定
cullingGroup.SetBoundingSphereCount(spheres.Length);
}
private void OnDisable()
{
cullingGroup?.Dispose();
cullingGroup = null;
}
// Update is called once per frame
void Update()
{
elapsedTime += Time.deltaTime;
// 3秒ごとに処理
if(elapsedTime >= 3f)
{
elapsedTime = 0f;
// 結果のBoundingSphereインデックスの配列
int[] resultIndices = new int[spawnPoints.Length];
// 結果の個数
int numResults = 0;
// カメラから見えないBoundingSphereを検索
numResults = cullingGroup.QueryIndices(false, resultIndices, 0);
// 結果の個数が0なら終了
if (numResults == 0) return;
// 配列のなかからインデックスをランダムで一つ選ぶ
var index = resultIndices[Random.Range(0, numResults)];
// 同じインデックスの位置にプレハブをインスタンス化
Instantiate(spherePrefab, spawnPoints[index].position,Quaternion.identity);
}
}
}
スクリプトにはシーンのゲームオブジェクトと配置するプレハブがアタッチされています。
CullingGroupの設定はCullingGroupでカメラから見えているかどうかを判定すると同じです。
void Start()
{
// CullingGroupをインスタンス化
cullingGroup = new CullingGroup();
// カメラを設定
cullingGroup.targetCamera = Camera.main;
// BoundingSphereの配列を初期化
BoundingSphere[] spheres = new BoundingSphere[spawnPoints.Length];
// ゲームオブジェクトの位置にBoundingSphereをインスタンス化
for (int i = 0; i < spheres.Length; i++)
{
spheres[i] = new BoundingSphere(spawnPoints[i].position, 1f);
}
// BoundingSphereの配列を設定
cullingGroup.SetBoundingSpheres(spheres);
// BoundingSphereの個数を設定
cullingGroup.SetBoundingSphereCount(spheres.Length);
}
CullingGroupはクリーンアップされるようにしています。
private void OnDisable()
{
cullingGroup?.Dispose();
cullingGroup = null;
}
Updateメソッドで3秒ごとにゲームオブジェクトを配置します。
elapsedTime += Time.deltaTime;
// 3秒ごとに処理
if(elapsedTime >= 3f)
{
elapsedTime = 0f;
CullingGroup.QueryIndicesメソッドで、条件を指定してBoundingSphereを検索できます。引数にint型の配列を渡すと、条件に合致したBoundingSphereのインデックスが先頭から埋まります。残りの部分は初期値の0になっています。
条件に合うBoundingSphereの個数が返るので、インデックスの0と初期値を区別できます。
// 結果のBoundingSphereインデックスの配列
int[] resultIndices = new int[spawnPoints.Length];
// 結果の個数
int numResults = 0;
// カメラから見えないBoundingSphereを検索
numResults = cullingGroup.QueryIndices(false, resultIndices, 0);
結果の配列からランダムでインデックスを選びます。同じインデックスのゲームオブジェクトの位置にプレハブをインスタンス化しています。
// 結果の個数が0なら終了
if (numResults == 0) return;
// 配列のなかからインデックスをランダムで一つ選ぶ
var index = resultIndices[Random.Range(0, numResults)];
// 同じインデックスの位置にプレハブをインスタンス化
Instantiate(spherePrefab, spawnPoints[index].position,Quaternion.identity);
これでカメラから見えない位置にオブジェクトを配置できました。
参考:https://docs.unity3d.com/ja/2019.4/Manual/CullingGroupAPI.html