using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Unity.Mathematics; using Unity.Netcode; using Unity.VisualScripting; using UnityEngine; using UnityEngine.AI; using UnityEngine.UIElements; public class EnemySpawner : NetworkBehaviour { // Shared public int Wave = 0; public float difficulty = 1f; // Inspector [SerializeField] private float difficultyIncreasePerWave = 1f; [SerializeField] public float WaveTime = 20f; [SerializeField] private float SpawnRadius = 10; [SerializeField] private int NumEnemies = 6; private GameObject[] players; [SerializeField] private float initialSpawnDelay = 5; [Space(10)] [SerializeField] private Transform SpawnCenter; // local private bool nextWaveRequested = false; public float timer = 0f; private GameObject SpawnedEnenmyHolder; [SerializeField] private EnemyList enemyList; private bool SpawnerStarted = false; public static EnemySpawner instance; private void OnEnable() { GameManager.OnPlayersReady += OnPlayersReady; } private void OnPlayersReady(GameObject[] players) { this.players = players; } private void Awake() { if (instance == null) { instance = this; } else { Destroy(instance); } } private void Start() { SpawnedEnenmyHolder = new GameObject("SpawnedEnenmyHolder"); timer = WaveTime - initialSpawnDelay; if (IsServer || IsHost) // If server then start spawning StartSpawning(); } public void Update() { if (SpawnerStarted) timer += Time.deltaTime; if (timer > WaveTime || nextWaveRequested) { 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) { if (enemyList.List.Any(x=>x.Difficulty < 0.1f)) { Debug.LogError("Difficulty on prefab too low!", enemyList); return; } if (Wave != 0 && Wave % 10 == 0) SpawnStrongestFirst(difficulty); else SpawnRandom(difficulty); } void SpawnStrongestFirst(float difficulty) { var decendingList = enemyList.List.Where(x => x.Difficulty < difficulty).OrderByDescending(x => x.Difficulty).ToArray(); for (int i = 0; i < decendingList.Length; i++) { while (difficulty > decendingList[i].Difficulty) { GameObject enemyToSpawn = decendingList[i].prefabs[UnityEngine.Random.Range(0, decendingList[i].prefabs.Length)]; SpawnEnemy(enemyToSpawn); difficulty -= decendingList[i].Difficulty; } } } void SpawnRandom(float difficulty) { difficulty *= 1.1f; while (difficulty > 1f) // Spawn until difficulty is less than 0.5f { var validEnemies = enemyList.List.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]; SpawnEnemy(variantToSpawn); } } void SpawnEnemy(GameObject enemyPrefab) { GameObject enemy = Instantiate(enemyPrefab, GetRandomPointOnCircle(SpawnRadius), Quaternion.identity, SpawnedEnenmyHolder.transform); enemy.GetComponent().Spawn(); enemy.GetComponent().targets = players.Select(x => x.transform).ToArray(); } // Centrum is SpawnCenter public Vector3 GetRandomPointOnCircle(float radius) { Vector3 point; do { float angle = UnityEngine.Random.Range(0f, 360f); float radians = Mathf.Deg2Rad * angle; Vector3 position = SpawnCenter.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 }