A game component that spawns monsters and reacts to its own destruction. It tracks spawned monsters, spawns new ones on a cooldown, plays sounds and creates ‘blitz’ effects on death, and damages spawned monsters when the spawner dies.
using Sandbox;
using System;
using static HealthSystem;
public sealed class MonsterSpawner : Component, HealthSystem.IHealthEvent
{
[Property] GameObject DeadMonsterSpawner;
[Property] public LineRenderer LineRenderer;
[Property] GameObject BlitzPrefab;
[Property] public GameObject MonsterPrefab; // Wird von MonsterManager gepassed
public float MonsterSpawnStartDelay = 1f;
public float MonsterSpawnCooldown = 1f;
public float MonsterScaleFactor = 1f;
[Property] public int MaxMonsterSpawns = 1;
List<GameObject> SpawnedMonsters;
TimeUntil UntilNextSpawn;
Random random;
public interface IMonsterSpawnerEvent : ISceneEvent<IMonsterSpawnerEvent>
{
void OnMonsterSpawn();
}
void IHealthEvent.OnDeath()
{
Sound.Play( "sounds/spawner-dies.sound", WorldPosition);
SpawnedMonsters.RemoveAll( x => !x.IsValid );
foreach (var monster in SpawnedMonsters)
{
if ( monster == null ) { return; }
GameObject newBlitz = BlitzPrefab.Clone(monster.GetComponentInChildren<LineRenderer>().Points[0].WorldPosition, monster.WorldRotation.Angles().WithYaw(random.Float(0, 360)), new Vector3(10, 10, 10));
newBlitz.SetParent( monster.GetComponentInChildren<LineRenderer>().GameObject );
newBlitz.GetComponent<Blitz>().MonsterLineColor = LineRenderer.Color.Evaluate( 0.5f );
newBlitz.GetComponent<Blitz>().LightningStrike(0.2f);
// HealthSystem holen, wenn nicht da aus Children holen und damagen
HealthSystem healthSystem = monster.GetComponent<HealthSystem>();
if ( healthSystem != null ) healthSystem.Damage( healthSystem.CurrentHealth * 0.8f );
else { monster.GetComponentInChildren<HealthSystem>().Damage( monster.GetComponentInChildren<HealthSystem>().CurrentHealth * 0.8f ); }
}
GameObject newDeadMonsterSpawner = DeadMonsterSpawner.Clone(WorldPosition + Vector3.Up, WorldRotation, WorldScale);
foreach ( GameObject child in newDeadMonsterSpawner.Children )
{
child.GetComponent<Rigidbody>().ApplyImpulse( (child.WorldPosition - GameObject.WorldPosition).Normal * 3 * child.GetComponent<Rigidbody>().Mass );
child.GetComponent<Rigidbody>().AngularVelocity = random.VectorInSphere( random.Float( 3, 5 ) );
}
}
protected override void OnStart()
{
SpawnedMonsters = new List<GameObject>();
random = new Random();
UntilNextSpawn = MonsterSpawnStartDelay;
}
protected override void OnFixedUpdate()
{
// Solange Max Monsters gespawned sind ist bleibt der NextSpawn auf Cooldown
if ( SpawnedMonsters.Count >= MaxMonsterSpawns ) UntilNextSpawn = MonsterSpawnCooldown;
if (true)
{
SpawnedMonsters.RemoveAll( x => !x.IsValid );
}
// Wenn NextSpawn abgelaufen ist
if ( UntilNextSpawn )
{
SpawnMonster();
UntilNextSpawn = MonsterSpawnCooldown;
}
}
void SpawnMonster()
{
// Particle Effekt, Sound?
GameObject currentMonster = MonsterPrefab.Clone( WorldPosition + (Vector3)random.VectorInCircle() * random.Int(200, 500), WorldRotation, Vector3.One * MonsterScaleFactor * random.Float(0.9f, 1.1f) );
SpawnedMonsters.Add(currentMonster);
IMonsterSpawnerEvent.PostToGameObject( this.GameObject, x => x.OnMonsterSpawn() );
}
private void BlitzMonster( GameObject monster )
{
GameObject newBlitz = BlitzPrefab.Clone( WorldPosition, WorldRotation, Vector3.One * 0.1f );
LineRenderer blitzLine = newBlitz.GetComponentInChildren<LineRenderer>();
newBlitz.GetComponent<Blitz>().MonsterSpawner = GetComponent<MonsterSpawner>();
blitzLine.Points[0].WorldPosition = WorldPosition + Vector3.Up * 50;
blitzLine.Points[1].WorldPosition = WorldPosition + random.VectorInSphere().Normal * 16 + (monster.WorldPosition - WorldPosition) * 0.33f + Vector3.Up * 150;
blitzLine.Points[2].WorldPosition = WorldPosition + random.VectorInSphere().Normal * 16 + (monster.WorldPosition - WorldPosition) * 0.66f + Vector3.Up * 150;
blitzLine.Points[3].WorldPosition = monster.WorldPosition + Vector3.Up * 150;
}
}