feature-waves #16

Merged
madxmike merged 2 commits from feature-waves into main 2023-08-10 16:24:42 -05:00
40 changed files with 944 additions and 0 deletions

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

8
Assets/EventChannels.meta generated Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 243302c56bf8926489fe86e5626dd4d3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

14
Assets/EventChannels/EndSpawnWave.asset generated Normal file
View File

@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 908e283bf3a54c859a0771fd8aed7bce, type: 3}
m_Name: EndSpawnWave
m_EditorClassIdentifier:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b8a8049e92364834ebac76909a03324b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 908e283bf3a54c859a0771fd8aed7bce, type: 3}
m_Name: StartSpawnWave
m_EditorClassIdentifier:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3f9039af54fd5d240b144e1ab3bbeb72
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Runtime Sets.meta generated Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 57024de5f8ad4f74ba5d83bb062a7612
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f1e329a7f6343f88553db21ffb55693, type: 3}
m_Name: ActiveEnemyRuntimeSet
m_EditorClassIdentifier:
Items: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7c32c32e039cdda409e8a56d2e320f2d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

128
Assets/Scenes/test.unity generated
View File

@ -497,6 +497,73 @@ MonoBehaviour:
cameraController: {fileID: 1176001025}
rotationSensitivity: 100
zoomSensitivity: 0.05
--- !u!1 &880655848
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 880655850}
- component: {fileID: 880655849}
- component: {fileID: 880655851}
m_Layer: 0
m_Name: LevelDirector
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &880655849
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 880655848}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bb718e52728142e4a8db081fd6a36a70, type: 3}
m_Name:
m_EditorClassIdentifier:
startNewSpawnWaveEventChannel: {fileID: 11400000, guid: 3f9039af54fd5d240b144e1ab3bbeb72, type: 2}
endSpawnWaveEventChannel: {fileID: 11400000, guid: b8a8049e92364834ebac76909a03324b, type: 2}
enemyRuntimeSet: {fileID: 11400000, guid: 7c32c32e039cdda409e8a56d2e320f2d, type: 2}
spawnCenter: {fileID: 19609788}
minimumSpawnRadius: 10
timeBetweenClearedWaves: 0
timeBeforeFirstWave: 0
--- !u!4 &880655850
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 880655848}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &880655851
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 880655848}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a91533ae182d470c88ce779956713e02, type: 3}
m_Name:
m_EditorClassIdentifier:
waveSpawner: {fileID: 880655849}
spawnWaves:
- {fileID: 11400000, guid: e7512725c2f0b3148bd090141c5eed5d, type: 2}
--- !u!1 &1038072789
GameObject:
m_ObjectHideFlags: 0
@ -685,3 +752,64 @@ Transform:
m_Father: {fileID: 1176001024}
m_RootOrder: -1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &5742654212719732323
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_RootOrder
value: 5
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6229410894397123332, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_Name
value: TestEnemy
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 200dea255585b154f8222e550c23b55e, type: 3}

8
Assets/Scriptables/Waves.meta generated Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 409432f90c2931d49a55a87ded944aa9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,19 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 52673fed940f4a67b5a08641a55feff6, type: 3}
m_Name: SpawnPack_Test
m_EditorClassIdentifier:
possibleEnemies:
- {fileID: 7321161463868935016, guid: 200dea255585b154f8222e550c23b55e, type: 3}
- {fileID: 1158114420728610952, guid: 9dff131d77697b242ae2e2b68aa7e1db, type: 3}
minCount: 30
maxCount: 50

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 970a884aa40996749b022ebb2765d769
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 17a69c35e3e64b6d9f655533478f9772, type: 3}
m_Name: SpawnWave_Test
m_EditorClassIdentifier:
packs:
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
- {fileID: 11400000, guid: 970a884aa40996749b022ebb2765d769, type: 2}
distribution: 2
radius: 50
packRadius: 7
timeBetweenSpawns: 0.01
timeBetweenPacks: 0.1
timeToComplete: 0

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e7512725c2f0b3148bd090141c5eed5d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

11
Assets/Scripts/Enemy.cs Normal file
View File

@ -0,0 +1,11 @@
using UnityEngine;
namespace DefaultNamespace
Review

who

who
Review

Anything in the top level package gets put under DefaultNamespace. Rider puts this automatically when you make a new file in the top level package. Really we want to set the namespace for that package to IdleSurvivors or something.

Anything in the top level package gets put under DefaultNamespace. Rider puts this automatically when you make a new file in the top level package. Really we want to set the namespace for that package to IdleSurvivors or something.
{
// TODO (Michael): Empty behavior until we decide more on how enemies should be structured. Mainly being used for
// other systems to have something to reference.
public class Enemy : MonoBehaviour
{
}
}

3
Assets/Scripts/Enemy.cs.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0ce366659158473783c8d53d2f3fc5f5
timeCreated: 1690856221

View File

@ -0,0 +1,11 @@
using UnityEngine;
namespace DefaultNamespace
{
[CreateAssetMenu(menuName = "Enemy Runtime Set", fileName =
"EnemyRuntimeSet")]
public class EnemyRuntimeSetSO : RuntimeSetSO<Enemy>
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5f1e329a7f6343f88553db21ffb55693
timeCreated: 1690858329

3
Assets/Scripts/Events.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5741392326404cb387003f002d90acee
timeCreated: 1690857552

View File

@ -0,0 +1,17 @@
using UnityEngine;
using UnityEngine.Events;
using Wave;
namespace Events
{
[CreateAssetMenu(menuName = "Events/Spawn Wave SO Event Channel")]
public class SpawnWaveSOEventChannelSO : ScriptableObject
{
public event UnityAction<SpawnWaveSO> OnEventRaised;
public void RaiseEvent(SpawnWaveSO spawnWave)
{
OnEventRaised?.Invoke(spawnWave);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 908e283bf3a54c859a0771fd8aed7bce
timeCreated: 1690857571

3
Assets/Scripts/Level.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eb1638a1c58a4878adf9166dddc40738
timeCreated: 1690927890

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Wave;
namespace Level
{
public class LevelDirector : MonoBehaviour
{
[SerializeField] private WaveSpawner waveSpawner;
[SerializeField] private List<SpawnWaveSO> spawnWaves;
private void Start()
{
waveSpawner.Begin(spawnWaves);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a91533ae182d470c88ce779956713e02
timeCreated: 1690927896

View File

@ -0,0 +1,26 @@
using System.Collections.Generic;
using UnityEngine;
public abstract class RuntimeSetSO<T> : ScriptableObject
{
[HideInInspector] [SerializeField] private List<T> items = new();
public IReadOnlyCollection<T> Items => items;
public bool IsEmpty => items.Count == 0;
public void Add(T thing)
{
if (!items.Contains(thing))
{
items.Add(thing);
}
}
public void Remove(T thing)
{
if (items.Contains(thing))
{
items.Remove(thing);
}
}
}

3
Assets/Scripts/RuntimeSetSO.cs.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 942f0916a83b433891dd4c6a9bbb50fd
timeCreated: 1690858304

3
Assets/Scripts/Wave.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6515ffdab88e4d23b8f09dace4a2157a
timeCreated: 1690921607

View File

@ -0,0 +1,9 @@
namespace Wave
{
public enum SpawnDistribution
{
Uniform,
Random,
DiskRandom
Review

missing trailing comma

missing trailing comma
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2a4df8269a27463eaf87da9ae1283dcb
timeCreated: 1690925288

View File

@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using DefaultNamespace;
using UnityEngine;
using UnityEngine.Assertions;
namespace Wave
{
[CreateAssetMenu(fileName = "SpawnPack", menuName = "Spawn/Pack", order = 0)]
public class SpawnPackSO : ScriptableObject
{
[SerializeField] private List<Enemy> possibleEnemies;
[SerializeField] [Min(0)] private int minCount;
[SerializeField] [Min(0)] private int maxCount;
public ReadOnlyCollection<Enemy> EnemiesToSpawn()
{
Assert.IsTrue(possibleEnemies.Count > 0);
var count = Random.Range(minCount, maxCount);
var enemiesToSpawn = new List<Enemy>();
for (var i = 0; i < count; i++)
{
var enemyIndex = Random.Range(0, possibleEnemies.Count);
enemiesToSpawn.Add(possibleEnemies[enemyIndex]);
}
return enemiesToSpawn.AsReadOnly();
}
}
}

3
Assets/Scripts/Wave/SpawnPackSO.cs.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 52673fed940f4a67b5a08641a55feff6
timeCreated: 1690938542

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
namespace Wave
{
[CreateAssetMenu(fileName = "SpawnWave", menuName = "Spawn Wave", order = 0)]
public class SpawnWaveSO : ScriptableObject
{
[SerializeField] private List<SpawnPackSO> packs;
[SerializeField] private SpawnDistribution distribution;
[SerializeField] [Min(10)] private float radius;
[SerializeField] [Min(0)] private float packRadius;
[SerializeField] [Min(0)] private float timeBetweenSpawns;
[SerializeField] [Min(0)] private float timeBetweenPacks;
[SerializeField] [Min(0)] private float timeToComplete;
public IReadOnlyCollection<SpawnPackSO> Packs => packs;
public SpawnDistribution Distribution => distribution;
public float Radius => radius;
public float PackRadius => packRadius;
public float TimeBetweenSpawns => timeBetweenSpawns;
public float TimeBetweenPacks => timeBetweenPacks;
public float TimeToComplete => timeToComplete;
}
}

3
Assets/Scripts/Wave/SpawnWaveSO.cs.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 17a69c35e3e64b6d9f655533478f9772
timeCreated: 1690856578

View File

@ -0,0 +1,120 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using DefaultNamespace;
using Events;
using UnityEngine;
using UnityEngine.Assertions;
using Random = UnityEngine.Random;
namespace Wave
{
public class WaveSpawner : MonoBehaviour
{
[SerializeField] private SpawnWaveSOEventChannelSO startNewSpawnWaveEventChannel;
Review

nit: verbose name

nit: verbose name
[SerializeField] private SpawnWaveSOEventChannelSO endSpawnWaveEventChannel;
[SerializeField] private EnemyRuntimeSetSO enemyRuntimeSet;
[SerializeField] private Transform spawnCenter;
[SerializeField] private float minimumSpawnRadius;
[SerializeField] [Min(0)] private float timeBetweenClearedWaves;
[SerializeField] [Min(0)] private float timeBeforeFirstWave;
private float _timeSinceLastSpawnWaveStarted;
private Coroutine _handleSpawnWaves;
private bool HasWaveBeenCleared => enemyRuntimeSet.IsEmpty;
public void Begin(IEnumerable<SpawnWaveSO> spawnWaves)
{
Assert.IsNull(_handleSpawnWaves);
_handleSpawnWaves = StartCoroutine(CO_HandleSpawnWaves(spawnWaves));
}
public void End()
{
StopCoroutine(_handleSpawnWaves);
}
private IEnumerator CO_HandleSpawnWaves(IEnumerable<SpawnWaveSO> spawnWaves)
{
yield return new WaitForSeconds(timeBeforeFirstWave);
foreach (var spawnWave in spawnWaves)
{
startNewSpawnWaveEventChannel.RaiseEvent(spawnWave);
yield return SpawnWave(spawnWave);
_timeSinceLastSpawnWaveStarted = 0.0f;
yield return new WaitUntil(() => _timeSinceLastSpawnWaveStarted >= spawnWave.TimeToComplete || HasWaveBeenCleared);
endSpawnWaveEventChannel.RaiseEvent(spawnWave);
if (HasWaveBeenCleared)
{
yield return new WaitForSeconds(timeBetweenClearedWaves);
}
}
}
private IEnumerator SpawnWave(SpawnWaveSO spawnWave)
{
var enemyPacksToSpawn = spawnWave.Packs.Select(pack => pack.EnemiesToSpawn()).ToList().AsReadOnly();
for (var packN = 0; packN < enemyPacksToSpawn.Count; packN++)
{
var waveCompletionPercentage = (float)packN / (float)enemyPacksToSpawn.Count;
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++)
Review

there's no foreach-ish loop appropriate to use here?

there's no foreach-ish loop appropriate to use here?
Review

I need to keep track of the count of enemies that have spawned

I need to keep track of the count of enemies that have spawned
{
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)
{
yield return new WaitForSeconds(spawnWave.TimeBetweenPacks);
}
}
}
private static Vector3 SampleSpawnOffset(SpawnDistribution distribution, float radius, float completionPercentage)
{
// 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);
return distribution switch
{
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)
};
}
private void Update()
{
_timeSinceLastSpawnWaveStarted += Time.deltaTime;
}
}
}

3
Assets/Scripts/Wave/WaveSpawner.cs.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bb718e52728142e4a8db081fd6a36a70
timeCreated: 1690856916

179
Assets/TestEnemy Variant.prefab generated Normal file
View File

@ -0,0 +1,179 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &8302155952709515973
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7488072351778741751}
- component: {fileID: 3366913879355185749}
- component: {fileID: 1785543729989221829}
- component: {fileID: 1100616685365383236}
m_Layer: 0
m_Name: Capsule
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7488072351778741751
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8302155952709515973}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4279102732078913915}
m_RootOrder: -1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &3366913879355185749
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8302155952709515973}
m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &1785543729989221829
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8302155952709515973}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!136 &1100616685365383236
CapsuleCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8302155952709515973}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 2
m_Radius: 0.5
m_Height: 2
m_Direction: 1
m_Center: {x: 0, y: 0, z: 0}
--- !u!1001 &8470021174966258656
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6229410894397123332, guid: 200dea255585b154f8222e550c23b55e, type: 3}
propertyPath: m_Name
value: TestEnemy Variant
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects:
- {fileID: 6791948486170648146, guid: 200dea255585b154f8222e550c23b55e, type: 3}
m_AddedGameObjects:
- targetCorrespondingSourceObject: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
insertIndex: -1
addedObject: {fileID: 7488072351778741751}
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 200dea255585b154f8222e550c23b55e, type: 3}
--- !u!4 &4279102732078913915 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 5686324643192967835, guid: 200dea255585b154f8222e550c23b55e, type: 3}
m_PrefabInstance: {fileID: 8470021174966258656}
m_PrefabAsset: {fileID: 0}

7
Assets/TestEnemy Variant.prefab.meta generated Normal file
View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9dff131d77697b242ae2e2b68aa7e1db
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

152
Assets/TestEnemy.prefab generated Normal file
View File

@ -0,0 +1,152 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &6229410894397123332
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5686324643192967835}
- component: {fileID: 7321161463868935016}
m_Layer: 0
m_Name: TestEnemy
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5686324643192967835
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6229410894397123332}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 572175646573100614}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &7321161463868935016
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6229410894397123332}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0ce366659158473783c8d53d2f3fc5f5, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &6791948486170648146
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 572175646573100614}
- component: {fileID: 2871351465463266601}
- component: {fileID: 4344212730668217775}
- component: {fileID: 9190027053535473730}
m_Layer: 0
m_Name: Model
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &572175646573100614
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6791948486170648146}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 5686324643192967835}
m_RootOrder: -1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &2871351465463266601
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6791948486170648146}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &4344212730668217775
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6791948486170648146}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!135 &9190027053535473730
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6791948486170648146}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 0.5
m_Center: {x: 0, y: 0, z: 0}

7
Assets/TestEnemy.prefab.meta generated Normal file
View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 200dea255585b154f8222e550c23b55e
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: