【Unity/3D】敵キャラ出現位置の重複確認

敵キャラ出現位置の重複確認(int配列版)

1ウェーブで出す雑魚敵の位置が近くに偏り過ぎないようにチェック。
衝突判定(Physics.OverlapSphere)のパターンと、intの配列のパターンを搭載。

衝突判定パターンでは、floatなランダム位置になるので、歯抜け気味に。
int配列パターンでは、整然とした隊列になります。

コード

EnemySpawnerA (衝突判定パターン)

敵キャラ出現位置の重複確認(Physics.OverlapSphere版)
  1. EnemyにColliderを付ける。
  2. EnemyをEnemyレイヤーに設定。
  3. 以下のコードを、新規スクリプト or GameManager等に追記する。
  4. シーンに設置した後、インスペクターから、Enemyプレハブを紐付け。
  5. SpawnEnemiesを呼ぶ。


using UnityEngine;

public class EnemySpawnerA : MonoBehaviour
{

//敵キャラのプレハブを紐付けしておく。
	[SerializeField]
	GameObject enemyPrefab;

//敵を配置する最大値。
	static readonly int EnemyMax = 10;

//敵の出現基本位置。
	Vector3 spawnedEnemyPosition = new Vector3(0, 0, 3.0f);

//敵の出現位置を左右にズラす範囲(地面の幅 - 敵キャラの半径、等)。
	float spawnedEnemyPositionRandomRangeX = 4.5f;

//敵の出現の重複チェック半径。
	float spawnedEnemyRadius = 1.0f;

//重複判定の結果。NonAlloc版なので宣言しておく。
	Collider[] spawnedEnemyOverlapResults = new Collider[1];

	LayerMask enemyLayerMask;

//Enemyのタグ。1回のみの使用なので、別に良い気もするが、一応定数化。
	static readonly string EnemyTag = "Enemy";

//この回数チェックしても位置が重複しているなら、それ以降の敵の出現を中止。
	static readonly int CheckOverlapMax = 100;

	Quaternion spawnedEnemyRotation = Quaternion.Euler(0, 180, 0);



	void Awake()
	{
//敵のレイヤーのみを指定。
		enemyLayerMask = 1 << LayerMask.NameToLayer(EnemyTag);


//呼び方の一例。
		SpawnEnemies();

		spawnedEnemyPosition.z += 2.0f;
		SpawnEnemies();

		spawnedEnemyPosition.z += 2.0f;
		SpawnEnemies();
	}


	void SpawnEnemies()
	{
		for (int i = 0; i < EnemyMax; i++) {
			for (int j = 0; j < CheckOverlapMax; j++) {
				spawnedEnemyPosition.x = Random.Range(-spawnedEnemyPositionRandomRangeX, spawnedEnemyPositionRandomRangeX);
//QueryTriggerInteraction.Collideを設定しているので、ColliderがTriggerModeでもOk。
				if (Physics.OverlapSphereNonAlloc(spawnedEnemyPosition, spawnedEnemyRadius, spawnedEnemyOverlapResults, enemyLayerMask, QueryTriggerInteraction.Collide) == 0) {
					Instantiate(enemyPrefab, spawnedEnemyPosition, spawnedEnemyRotation);
//Jのループから抜ける。
					j = CheckOverlapMax;
				}

//Iのループから抜ける。
				if (j == CheckOverlapMax - 1)
					i = EnemyMax;
			}
		}
	}
}

EnemySpawnerB (int配列パターン)

  1. 以下のコードを、新規スクリプト or GameManager等に追記する。
  2. シーンに設置した後、インスペクターから、Enemyプレハブを紐付け。
  3. SpawnEnemiesを呼ぶ。


using System.Collections.Generic;
using UnityEngine;

public class EnemySpawnerB : MonoBehaviour
{

//敵キャラのプレハブを紐付けしておく。
	[SerializeField]
	GameObject enemyPrefab;

//敵を配置する最大値。
	static readonly int EnemyMax = 10;

//敵の出現基本位置。
	Vector3 spawnedEnemyPosition = new Vector3(0, 0, 3.0f);

//敵の出現位置を左右にズラす範囲(0を中心とするので、この例では7列になる)。
	int spawnedEnemyPositionIndexRandomRangeX = 3;

//敵の出現位置の間隔(Indexに掛ける)。
	float spawnedEnemyMargin = 1.5f;

//この回数チェックしても位置が重複しているなら、それ以降の敵の出現を中止。
	static readonly int CheckOverlapMax = 100;

	Quaternion spawnedEnemyRotation = Quaternion.Euler(0, 180, 0);

//敵の出現位置Indexのリスト
	List<int> spawnedEnemyPositionIndexList = new List<int>(EnemyMax);

	int spawnedEnemyPositionIndex;



//呼び方の一例。
	void Awake()
	{
		SpawnEnemies();

		spawnedEnemyPosition.z += 2.0f;
		SpawnEnemies();

		spawnedEnemyPosition.z += 2.0f;
		SpawnEnemies();
	}


	void SpawnEnemies()
	{
		for (int i = 0; i < EnemyMax; i++) {
			for (int j = 0; j < CheckOverlapMax; j++) {
//整数のRandom.Rangeなので、想定している範囲の結果を得るには、正の値を+1する。
				spawnedEnemyPositionIndex = Random.Range(-spawnedEnemyPositionIndexRandomRangeX, spawnedEnemyPositionIndexRandomRangeX + 1);

//整数のリストの重複確認。
				if (!spawnedEnemyPositionIndexList.Contains(spawnedEnemyPositionIndex)) {
					spawnedEnemyPositionIndexList.Add(spawnedEnemyPositionIndex);
					spawnedEnemyPosition.x = spawnedEnemyPositionIndex * spawnedEnemyMargin;
					Instantiate(enemyPrefab, spawnedEnemyPosition, spawnedEnemyRotation);
//Jのループから抜ける。
					j = CheckOverlapMax;
				}

//Iのループから抜ける。
				if (j == CheckOverlapMax - 1)
					i = EnemyMax;
			}
		}

//Indexのリストをリセット。
		spawnedEnemyPositionIndexList.Clear();
	}
}

タイトルとURLをコピーしました