fgm24/Assets/Scripts/Enemy/EnemySpawner.cs

180 lines
4.9 KiB
C#
Raw Normal View History

2024-02-03 04:05:06 +01:00
using System;
using System.Linq;
2024-02-28 19:27:24 +01:00
using Unity.Netcode;
2024-02-03 04:05:06 +01:00
using UnityEngine;
2024-02-04 01:34:18 +01:00
using UnityEngine.AI;
2024-02-03 04:05:06 +01:00
2024-02-28 19:27:24 +01:00
public class EnemySpawner : NetworkBehaviour
2024-02-03 04:05:06 +01:00
{
// Shared
public int Wave = 0;
2024-02-04 00:16:27 +01:00
public float difficulty = 1f;
2024-02-03 04:05:06 +01:00
// Inspector
2024-02-04 07:16:08 +01:00
[SerializeField] private float difficultyIncreasePerWave = 1f;
2024-02-04 07:59:28 +01:00
[SerializeField] public float WaveTime = 20f;
2024-02-03 17:33:45 +01:00
[SerializeField] private float SpawnRadius = 10;
[SerializeField] private int NumEnemies = 6;
private GameObject[] players;
2024-02-04 00:08:51 +01:00
[SerializeField] private float initialSpawnDelay = 5;
2024-02-28 19:27:24 +01:00
[Space(10)]
[SerializeField] private Transform SpawnCenter;
2024-02-03 04:05:06 +01:00
2024-02-04 07:59:28 +01:00
// local
2024-02-03 04:05:06 +01:00
private bool nextWaveRequested = false;
2024-02-04 07:59:28 +01:00
public float timer = 0f;
2024-02-03 17:33:45 +01:00
private GameObject SpawnedEnenmyHolder;
[SerializeField] private EnemyList enemyList;
2024-02-03 04:05:06 +01:00
2024-02-03 17:33:45 +01:00
private bool SpawnerStarted = false;
public static EnemySpawner instance;
private static int idCounter = 0;
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);
}
}
2024-02-03 17:33:45 +01:00
private void Start()
{
SpawnedEnenmyHolder = new GameObject("SpawnedEnenmyHolder");
2024-02-04 00:08:51 +01:00
timer = WaveTime - initialSpawnDelay;
if (IsServer || IsHost) // If server then start spawning
2024-02-28 19:27:24 +01:00
StartSpawning();
2024-02-03 17:33:45 +01:00
}
2024-02-03 04:05:06 +01:00
2024-02-03 17:33:45 +01:00
public void Update()
2024-02-03 04:05:06 +01:00
{
2024-02-03 17:33:45 +01:00
if (SpawnerStarted)
timer += Time.deltaTime;
if (timer > WaveTime || nextWaveRequested)
2024-02-03 04:05:06 +01:00
{
SpawnWave(difficulty);
Wave++;
2024-02-04 07:16:08 +01:00
difficulty *= MathF.Cbrt(difficultyIncreasePerWave);
2024-02-03 17:33:45 +01:00
nextWaveRequested = false;
timer = 0;
2024-02-03 04:05:06 +01:00
}
2024-02-03 17:33:45 +01:00
2024-02-03 04:05:06 +01:00
}
2024-02-03 17:33:45 +01:00
public void StartSpawning() => SpawnerStarted = true;
public void StartNextWave() => nextWaveRequested = true;
2024-02-03 04:05:06 +01:00
void SpawnWave(float difficulty)
{
if (enemyList.List.Any(x=>x.Difficulty < 0.1f))
{
Debug.LogError("Difficulty on prefab too low!", enemyList);
return;
}
2024-02-03 17:33:45 +01:00
2024-02-03 22:36:28 +01:00
if (Wave != 0 && Wave % 10 == 0)
SpawnStrongestFirst(difficulty);
else
SpawnRandom(difficulty);
2024-02-03 17:33:45 +01:00
}
void SpawnStrongestFirst(float difficulty)
{
var decendingList = enemyList.List.Where(x => x.Difficulty < difficulty).OrderByDescending(x => x.Difficulty).ToArray();
2024-02-03 04:05:06 +01:00
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);
2024-02-03 22:31:54 +01:00
difficulty -= decendingList[i].Difficulty;
2024-02-03 04:05:06 +01:00
}
}
}
2024-02-03 17:33:45 +01:00
void SpawnRandom(float difficulty)
{
2024-02-04 00:26:32 +01:00
difficulty *= 1.1f;
2024-02-03 23:22:55 +01:00
while (difficulty > 1f) // Spawn until difficulty is less than 0.5f
2024-02-03 17:33:45 +01:00
{
var validEnemies = enemyList.List.Where(x => x.Difficulty <= difficulty).ToArray();
2024-02-03 23:22:55 +01:00
int enemyIndex = UnityEngine.Random.Range(0, validEnemies.Length);
var enemyToSpawn = validEnemies[enemyIndex];
2024-02-03 17:33:45 +01:00
difficulty -= enemyToSpawn.Difficulty;
2024-02-03 23:22:55 +01:00
int variant = UnityEngine.Random.Range(0, enemyToSpawn.prefabs.Length);
GameObject variantToSpawn = enemyToSpawn.prefabs[variant];
SpawnEnemy(variantToSpawn);
2024-02-03 17:33:45 +01:00
}
}
void SpawnEnemy(GameObject enemyPrefab)
{
GameObject enemy = Instantiate(enemyPrefab, GetRandomPointOnCircle(SpawnRadius), Quaternion.identity, SpawnedEnenmyHolder.transform);
enemy.GetComponent<NetworkID>().InitialID = idCounter++;
enemy.GetComponent<NetworkObject>().Spawn();
enemy.GetComponent<EnemyPathFinding>().targets = players.Select(x => x.transform).ToArray();
}
2024-02-28 19:27:24 +01:00
// Centrum is SpawnCenter
2024-02-04 01:34:18 +01:00
public Vector3 GetRandomPointOnCircle(float radius)
2024-02-03 17:33:45 +01:00
{
2024-02-04 01:34:18 +01:00
Vector3 point;
do
{
float angle = UnityEngine.Random.Range(0f, 360f);
float radians = Mathf.Deg2Rad * angle;
2024-02-28 19:27:24 +01:00
Vector3 position = SpawnCenter.position;
2024-02-04 01:34:18 +01:00
float x = position.x + radius * Mathf.Cos(radians);
float y = position.y + radius * Mathf.Sin(radians);
2024-02-03 17:33:45 +01:00
2024-02-29 20:21:36 +01:00
point = new Vector3(x, y, 0);
2024-02-04 01:34:18 +01:00
} while (IsPointOnNavMesh(point));
2024-02-03 17:33:45 +01:00
2024-02-04 01:34:18 +01:00
return point;
}
bool IsPointOnNavMesh(Vector3 point)
{
NavMeshHit hit;
return NavMesh.SamplePosition(point, out hit, 0.1f, NavMesh.AllAreas);
2024-02-03 17:33:45 +01:00
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(transform.position, SpawnRadius);
for (int i = 0; i < 10; i++)
{
2024-02-04 01:34:18 +01:00
Gizmos.DrawWireSphere(GetRandomPointOnCircle(SpawnRadius), 0.25f);
2024-02-03 17:33:45 +01:00
}
}
#endif
2024-02-03 04:05:06 +01:00
}