1ウェーブで出す雑魚敵の位置が近くに偏り過ぎないようにチェック。
衝突判定(Physics.OverlapSphere)のパターンと、intの配列のパターンを搭載。
衝突判定パターンでは、floatなランダム位置になるので、歯抜け気味に。
int配列パターンでは、整然とした隊列になります。
コード
EnemySpawnerA (衝突判定パターン)
- EnemyにColliderを付ける。
- EnemyをEnemyレイヤーに設定。
- 以下のコードを、新規スクリプト or GameManager等に追記する。
- シーンに設置した後、インスペクターから、Enemyプレハブを紐付け。
- 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配列パターン)
- 以下のコードを、新規スクリプト or GameManager等に追記する。
- シーンに設置した後、インスペクターから、Enemyプレハブを紐付け。
- 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();
}
}