From 41ceb7a01cc45fce35bc374b0617f778f678d12c Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 2 Aug 2023 17:27:45 -0400 Subject: [PATCH] Initial pass on wave spawning. --- Assets/Scriptables/Waves/SpawnPack_Test.asset | 4 +- Assets/Scriptables/Waves/SpawnWave_Test.asset | 6 +- Assets/Scripts/Wave/SpawnPackSO.cs | 5 +- Assets/Scripts/Wave/WaveSpawner.cs | 71 ++++++++----------- 4 files changed, 39 insertions(+), 47 deletions(-) diff --git a/Assets/Scriptables/Waves/SpawnPack_Test.asset b/Assets/Scriptables/Waves/SpawnPack_Test.asset index f951c46..60b6470 100644 --- a/Assets/Scriptables/Waves/SpawnPack_Test.asset +++ b/Assets/Scriptables/Waves/SpawnPack_Test.asset @@ -15,5 +15,5 @@ MonoBehaviour: possibleEnemies: - {fileID: 7321161463868935016, guid: 200dea255585b154f8222e550c23b55e, type: 3} - {fileID: 1158114420728610952, guid: 9dff131d77697b242ae2e2b68aa7e1db, type: 3} - minCount: 5 - maxCount: 10 + minCount: 30 + maxCount: 50 diff --git a/Assets/Scriptables/Waves/SpawnWave_Test.asset b/Assets/Scriptables/Waves/SpawnWave_Test.asset index f527390..7f3f0bd 100644 --- a/Assets/Scriptables/Waves/SpawnWave_Test.asset +++ b/Assets/Scriptables/Waves/SpawnWave_Test.asset @@ -26,8 +26,8 @@ MonoBehaviour: - {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2} - {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2} distribution: 2 - radius: 25 - packRadius: 7.5 + radius: 50 + packRadius: 7 timeBetweenSpawns: 0.01 - timeBetweenPacks: 0 + timeBetweenPacks: 0.1 timeToComplete: 0 diff --git a/Assets/Scripts/Wave/SpawnPackSO.cs b/Assets/Scripts/Wave/SpawnPackSO.cs index b4e3075..b3b5afc 100644 --- a/Assets/Scripts/Wave/SpawnPackSO.cs +++ b/Assets/Scripts/Wave/SpawnPackSO.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; using DefaultNamespace; using UnityEngine; using UnityEngine.Assertions; @@ -12,7 +13,7 @@ namespace Wave [SerializeField] [Min(0)] private int minCount; [SerializeField] [Min(0)] private int maxCount; - public IReadOnlyCollection EnemiesToSpawn() + public ReadOnlyCollection EnemiesToSpawn() { Assert.IsTrue(possibleEnemies.Count > 0); @@ -25,7 +26,7 @@ namespace Wave enemiesToSpawn.Add(possibleEnemies[enemyIndex]); } - return enemiesToSpawn; + return enemiesToSpawn.AsReadOnly(); } } } \ No newline at end of file diff --git a/Assets/Scripts/Wave/WaveSpawner.cs b/Assets/Scripts/Wave/WaveSpawner.cs index 74c4f4c..3d53c16 100644 --- a/Assets/Scripts/Wave/WaveSpawner.cs +++ b/Assets/Scripts/Wave/WaveSpawner.cs @@ -47,42 +47,45 @@ namespace Wave yield return SpawnWave(spawnWave); _timeSinceLastSpawnWaveStarted = 0.0f; - yield return new WaitUntil(() => - _timeSinceLastSpawnWaveStarted >= spawnWave.TimeToComplete - || HasWaveBeenCleared); + yield return new WaitUntil(() => _timeSinceLastSpawnWaveStarted >= spawnWave.TimeToComplete || HasWaveBeenCleared); endSpawnWaveEventChannel.RaiseEvent(spawnWave); - yield return new WaitForSeconds(timeBetweenClearedWaves); + + if (HasWaveBeenCleared) + { + yield return new WaitForSeconds(timeBetweenClearedWaves); + } } } private IEnumerator SpawnWave(SpawnWaveSO spawnWave) { var enemyPacksToSpawn = spawnWave.Packs.Select(pack => pack.EnemiesToSpawn()).ToList().AsReadOnly(); - var totalPacksToSpawn = enemyPacksToSpawn.Count; - - var numberPacksSpawned = 0; - foreach (var enemyPackToSpawn in enemyPacksToSpawn) + for (var packN = 0; packN < enemyPacksToSpawn.Count; packN++) { - numberPacksSpawned++; - var waveCompletionPercentage = (float) numberPacksSpawned / (float) totalPacksToSpawn; + var waveCompletionPercentage = (float)packN / (float)enemyPacksToSpawn.Count; - // TODO (Michael): Both the pack and enemy position samplers need to be a bit smarter. I think in most scenarios the pack circle just needs to not overlap with other pack circles. - // The enemy spawns probably need something like a poission disk sampler so that monsters dont overlap. The enemy spawn radius at the pack's position should also probably scale with the size of the pack. - var enemyPackSpawnCenter = CalculatePackSpawnPosition(waveCompletionPercentage, spawnWave); - - foreach (var enemy in enemyPackToSpawn) + var enemyPackSpawnOffset = SampleSpawnOffset(spawnWave.Distribution, spawnWave.Radius, waveCompletionPercentage); + enemyPackSpawnOffset += enemyPackSpawnOffset.normalized * (minimumSpawnRadius + spawnWave.PackRadius); + + var enemyPackSpawnPosition = spawnCenter.position + enemyPackSpawnOffset; + + var enemyPackToSpawn = enemyPacksToSpawn[packN]; + for (var enemyN = 0; enemyN < enemyPackToSpawn.Count; enemyN++) { - - var spawnLocation = CalculateEnemySpawnPosition(enemyPackSpawnCenter, spawnWave.PackRadius); - var spawnedEnemy = Instantiate(enemy, spawnLocation, Quaternion.identity); - enemyRuntimeSet.Add(spawnedEnemy); + var packCompletionPercentage = (float)enemyN / (float)enemyPackToSpawn.Count; + var enemySpawnOffset = SampleSpawnOffset(SpawnDistribution.DiskRandom, spawnWave.PackRadius, packCompletionPercentage); + var enemySpawnPosition = enemyPackSpawnPosition + enemySpawnOffset; + var spawnedEnemy = Instantiate(enemyPackToSpawn[enemyN], enemySpawnPosition, Quaternion.identity); + enemyRuntimeSet.Add(spawnedEnemy); + if (spawnWave.TimeBetweenSpawns > 0.0f) { yield return new WaitForSeconds(spawnWave.TimeBetweenSpawns); } + } if (spawnWave.TimeBetweenPacks > 0.0f) @@ -92,35 +95,23 @@ namespace Wave } } - private Vector3 CalculatePackSpawnPosition(float waveCompletionPercentage, SpawnWaveSO spawnWave) + private static Vector3 SampleSpawnOffset(SpawnDistribution distribution, float radius, float completionPercentage) { - var angle = waveCompletionPercentage * 2 * MathF.PI; + // TODO (Michael): Both the pack and enemy position samplers need to be a bit smarter. I think in most scenarios the pack circle just needs to not overlap with other pack circles. + // The enemy spawns probably need something like a poission disk sampler so that monsters dont overlap. The enemy spawn radius at the pack's position should also probably scale with the size of the pack. + var angle = completionPercentage * 2 * MathF.PI; var unitCirclePosition = Random.insideUnitCircle; var swizzledUnitCirclePosition = new Vector3(unitCirclePosition.x, 0, unitCirclePosition.y); - var spawnOffset = spawnWave.Distribution switch + return distribution switch { - SpawnDistribution.Uniform => new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * spawnWave.Radius, - SpawnDistribution.Random => swizzledUnitCirclePosition.normalized * spawnWave.Radius, - SpawnDistribution.DiskRandom => swizzledUnitCirclePosition * spawnWave.Radius, - _ => throw new ArgumentOutOfRangeException(nameof(spawnWave.Distribution), spawnWave.Distribution, null) + SpawnDistribution.Uniform => new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius, + SpawnDistribution.Random => swizzledUnitCirclePosition.normalized * radius, + SpawnDistribution.DiskRandom => swizzledUnitCirclePosition * radius, + _ => throw new ArgumentOutOfRangeException(nameof(distribution), distribution, null) }; - - spawnOffset += spawnOffset.normalized * (minimumSpawnRadius + spawnWave.PackRadius); - - return spawnCenter.position + spawnOffset; } - private Vector3 CalculateEnemySpawnPosition(Vector3 center, float radius) - { - var unitCirclePosition = Random.insideUnitCircle; - var swizzledUnitCirclePosition = new Vector3(unitCirclePosition.x, 0, unitCirclePosition.y); - - var spawnOffset = swizzledUnitCirclePosition * radius; - - return center + spawnOffset; - } - private void Update() { _timeSinceLastSpawnWaveStarted += Time.deltaTime;