223 lines
7.3 KiB
C#

using GatherAndDefend.Events;
using System.Threading.Tasks;
using System.Collections.Generic;
using UnityEngine;
public class WaveObserver : Singleton<WaveObserver>
{
private List<SpawnerTile> _subjects = new List<SpawnerTile>();
private List<float> _aliveEnemyCount = new List<float>();
private List<int> _copyConstantSpawn;
private List<List<int>> _copyGroupSpawn; //Contains count of enemies per group
private List<float> _groupSpawnTimers;
private WaveConfig _levelConfig;
private const int MAXTOUGHNESS = 10;
private int _spawnerTiming = 0;
private List<int> _intervalTiming = new List<int>();
private bool _once = true;
private int _currentGroupIndex = 0;
public void Init(WaveConfig config)
{
_levelConfig = Object.Instantiate(config);
_copyConstantSpawn = new List<int>();
_copyGroupSpawn = new List<List<int>>();
_groupSpawnTimers = new List<float>();
if (!_levelConfig)
{
Debug.LogError("level config was null");
return;
}
foreach (EnemyType enemy in _levelConfig.ConstantSpawn)
{
_copyConstantSpawn.Add(enemy.Count);
}
for (int index = 0; index < _levelConfig.NestedGroupSpawn.Count; index++)
{
_copyGroupSpawn.Add(new List<int>());
for (int nestedIndex = 0; nestedIndex < _levelConfig.NestedGroupSpawn[index].groupSpawn.Count; nestedIndex++)
{
_copyGroupSpawn[index].Add(_levelConfig.NestedGroupSpawn[index].groupSpawn[nestedIndex].Count);
}
_groupSpawnTimers.Add(_levelConfig.NestedGroupSpawn[index].triggerTime);
}
// Start game timer, at the end, player wins.
GameTimer();
}
private async void GameTimer()
{
await Task.Delay((int) _levelConfig.GameDuration * 60 * 1000);
EventAggregator.Instance.GetEvent<LastWaveCompletedEvent>().Invoke();
}
/**
* Called by spawner at the start of the game
* Assigns enemy to spawn and registers them
*/
public void Attach(SpawnerTile spawnerSubject)
{
spawnerSubject.Prefab = _levelConfig.GetRandomSpawn().GetEnemyObject();
_subjects.Add(spawnerSubject);
_aliveEnemyCount.Add(0);
_intervalTiming.Add(++_spawnerTiming);
// Ensures that only one spawner keeps track of the grouped spawn timer.
if (_once)
{
_once = false;
spawnerSubject.SetGroupSpawnTimers(_groupSpawnTimers);
}
}
/**
* Called by spawner when making enemies
* Assigns a new interval
*/
public void NotifySpawned(SpawnerTile spawnerSubject)
{
GameObject paramPrefab = spawnerSubject.Prefab;
spawnerSubject.ChangeSpawnSpeed(_levelConfig.Interval * _spawnerTiming);
if (paramPrefab.Equals(_levelConfig.ConstantSpawn[0].GetEnemyObject()))
{
int currentCount = 0;
for (int i = 0; i < _copyConstantSpawn.Count; i++)
{
if (_levelConfig.ConstantSpawn[i].GetEnemyObject() == paramPrefab)
{
currentCount = --_copyConstantSpawn[i];
break;
}
}
if (currentCount <= 0)
{
foreach (SpawnerTile spawner in _subjects)
{
if (spawner.Prefab.Equals(paramPrefab))
{
spawner.StopSpawn();
}
}
}
}
}
/**
* Called by enemy when they spawn
* Keeps track of their row
*/
public int NotifyEnemy(float yPosition, float toughness)
{
int index = FindEnemyIndex(yPosition);
_aliveEnemyCount[index] += toughness;
if (_aliveEnemyCount[index] >= MAXTOUGHNESS)
{
_subjects[index].StopSpawn();
}
return index;
}
/**
* Called when an enemy dies
* Reactivates spawning on that row if disabled before
*/
public void NotifyDies(int position, float toughness)
{
_aliveEnemyCount[position] -= toughness;
if (_aliveEnemyCount[position] < MAXTOUGHNESS)
{
_subjects[position].StartSpawn();
}
}
/**
* Called when an enemy is spawned automatically at the start of the game
* Adjusts the intervall between spawns
*/
public void NotifyOnStart(SpawnerTile spawnerSubject)
{
float interval = _levelConfig.GetUpdatedInterval();
foreach (var subject in _subjects)
{
subject.ChangeSpawnSpeed(interval);
}
NotifySpawned(spawnerSubject);
}
// To find which spawner an ennemy came from.
private int FindEnemyIndex(float yPosition)
{
for (int i = 0; i < _subjects.Count; i++)
{
if (_subjects[i].Position.y == yPosition)
{
return i;
}
}
return -1;
}
/**
* Spawners wait 1 second to have time to register them all
* Then gets assigned a random spawn interval
*/
public void NotifyEndCooldown(SpawnerTile spawnerTile)
{
System.Random rand = new System.Random();
int index;
do
{
index = rand.Next(_subjects.Count);
} while (_intervalTiming.Count <= index);
spawnerTile.ChangeSpawnSpeed(_levelConfig.Interval * _intervalTiming[index]);
_intervalTiming.Remove(index);
}
/**
* Called when it is time to spawn a group
* Assigns a random element of the group to a random spawner
*/
public bool NotifyGroupSpawn()
{
List<int> usedRows = new List<int>();
List<EnemyType> currentGroup = _levelConfig.NestedGroupSpawn[_currentGroupIndex].groupSpawn;
for (int groupIndex = 0; groupIndex < currentGroup.Count; groupIndex++) //Loops through enemy groups
{
if (_copyGroupSpawn[_currentGroupIndex][groupIndex] != 0)
{
CycleRows(usedRows, currentGroup, groupIndex);
/*If group is done OR max rows reached while group is not done*/
if (_copyGroupSpawn[_currentGroupIndex][groupIndex] > 0 || (usedRows.Count == _subjects.Count && _copyGroupSpawn[_currentGroupIndex][groupIndex] > 0))
{
return false;
}
}
}
_currentGroupIndex++;
return true;
}
/**
* Called to go through every row randomly without duplicate rows
*/
private void CycleRows(List<int> usedRows, List<EnemyType> currentGroup, int groupIndex)
{
System.Random rand = new System.Random();
while (usedRows.Count < _subjects.Count)
{
int currentRow = rand.Next(_subjects.Count);
if (!usedRows.Contains(currentRow)) //If picked row has laready been used
{
_subjects[currentRow].TriggerSpawn(currentGroup[groupIndex].GetEnemyObject());
_copyGroupSpawn[_currentGroupIndex][groupIndex]--;
usedRows.Add(currentRow);
}
if (_copyGroupSpawn[_currentGroupIndex][groupIndex] == 0) //If current ennemy has reached count of 0
{
break;
}
}
}
}