using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Unity.Mathematics; using Unity.VisualScripting; using UnityEngine; using UnityEngine.AI; using UnityEngine.UIElements; public class EnemySpawner : MonoBehaviour { // Shared public int Wave = 0; public float difficulty = 1f; // Inspector [SerializeField] private float difficultyIncreasePerWave = 1f; [SerializeField] public float WaveTime = 20f; [SerializeField] private List enemyDifficulties; [SerializeField] private float SpawnRadius = 10; [SerializeField] private int NumEnemies = 6; [SerializeField] public GameObject[] players; [SerializeField] private float initialSpawnDelay = 5; // local private bool nextWaveRequested = false; public float timer = 0f; private Camera mainCam; private GameObject SpawnedEnenmyHolder; [SerializeField] private List enemyList; private bool SpawnerStarted = false; public static EnemySpawner instance; private void Awake() { if (instance == null) { instance = this; } else { Destroy(instance); } } private void Start() { mainCam = Camera.main; SpawnedEnenmyHolder = new GameObject("SpawnedEnenmyHolder"); for (int i = 0; i < 6; i++) { enemyList.Add(new EnemyPrefabInfo() { Difficulty = i+1, prefabs = Resources.LoadAll("Enemies/" + (i+1)) }); } timer = WaveTime - initialSpawnDelay; StartSpawning(); } public void Update() { if (SpawnerStarted) timer += Time.deltaTime; if (timer > WaveTime || nextWaveRequested) { Task.Factory.StartNew(() => { Task.Delay(100); timer = 0; }); SpawnWave(difficulty); Wave++; difficulty *= MathF.Cbrt(difficultyIncreasePerWave); nextWaveRequested = false; timer = 0; } } public void StartSpawning() => SpawnerStarted = true; public void StartNextWave() => nextWaveRequested = true; void SpawnWave(float difficulty) { //SpawnStrongestFirst(difficulty); if (Wave != 0 && Wave % 10 == 0) SpawnStrongestFirst(difficulty); else SpawnRandom(difficulty); } void SpawnStrongestFirst(float difficulty) { var decendingList = enemyList.Where(x => x.Difficulty < difficulty).OrderByDescending(x => x.Difficulty).ToArray(); for (int i = 0; i < decendingList.Length; i++) { while (difficulty > decendingList[i].Difficulty) { GameObject enemy = Instantiate(decendingList[i].prefabs[UnityEngine.Random.Range(0, decendingList[i].prefabs.Length)], GetRandomPointOnCircle(SpawnRadius), Quaternion.identity, SpawnedEnenmyHolder.transform); difficulty -= decendingList[i].Difficulty; enemy.GetComponent().targets = players.Select(x=>x.transform).ToArray(); } } } void SpawnRandom(float difficulty) { difficulty *= 1.1f; while (difficulty > 1f) // Spawn until difficulty is less than 0.5f { var validEnemies = enemyList.Where(x => x.Difficulty <= difficulty).ToArray(); int enemyIndex = UnityEngine.Random.Range(0, validEnemies.Length); var enemyToSpawn = validEnemies[enemyIndex]; difficulty -= enemyToSpawn.Difficulty; int variant = UnityEngine.Random.Range(0, enemyToSpawn.prefabs.Length); GameObject variantToSpawn = enemyToSpawn.prefabs[variant]; GameObject enemy = Instantiate(variantToSpawn, GetRandomPointOnCircle(SpawnRadius), Quaternion.identity, SpawnedEnenmyHolder.transform); enemy.GetComponent().targets = players.Select(x => x.transform).ToArray(); } } public Vector3 GetRandomPointOnCircle(float radius) { Vector3 point; do { float angle = UnityEngine.Random.Range(0f, 360f); float radians = Mathf.Deg2Rad * angle; Vector3 position = transform.position; float x = position.x + radius * Mathf.Cos(radians); float y = position.y + radius * Mathf.Sin(radians); point = new Vector3(x, y, position.z); } while (IsPointOnNavMesh(point)); return point; } bool IsPointOnNavMesh(Vector3 point) { NavMeshHit hit; return NavMesh.SamplePosition(point, out hit, 0.1f, NavMesh.AllAreas); } #if UNITY_EDITOR private void OnDrawGizmosSelected() { Gizmos.color = Color.green; Gizmos.DrawWireSphere(transform.position, SpawnRadius); for (int i = 0; i < 10; i++) { Gizmos.DrawWireSphere(GetRandomPointOnCircle(SpawnRadius), 0.25f); } } #endif }