wave behavior and fixed explosion

This commit is contained in:
2026-05-16 19:48:48 +02:00
parent b3ae3e37ea
commit 1898d91a28
27 changed files with 355 additions and 21 deletions

View File

@@ -36,7 +36,8 @@ public partial class TokenManager : Node
if (RequestQueue.First() != owner.GetInstanceId()) return null; // Next in line is not the requester
RequestQueue.RemoveAt(0);
var token = new Token(owner.GetInstanceId(), () => UseToken(owner.GetInstanceId()));
var ownerInstanceId = owner.GetInstanceId();
var token = new Token(ownerInstanceId, () => UseToken(ownerInstanceId));
Tokens.Add(token.InstanceId, token);
return token;
}

View File

@@ -0,0 +1,21 @@
using Godot;
namespace Movementtests.managers;
[GlobalClass]
public partial class EnemyDescription(PackedScene scene, EnemyDescription.EnemyType type, RMovement? movementOverride) : Resource
{
public enum EnemyType
{
Normal,
Projectile,
}
[Export(PropertyHint.NodeType)] public required PackedScene Scene { get; set; } = scene;
[Export] public required EnemyType Type { get; set; } = type;
[Export] public RMovement? MovementOverride { get; set; } = movementOverride;
public EnemyDescription() : this(ResourceLoader.Load<PackedScene>("uid://dxt0e2ugmttqq"), EnemyType.Normal, null) {}
}

View File

@@ -0,0 +1 @@
uid://rhdkfi7nuvu1

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using Godot;
namespace Movementtests.managers;
[GlobalClass]
public partial class SingleWave(EnemyDescription[] enemies) : Resource
{
[Export] public Godot.Collections.Dictionary<EnemyDescription, int> EnemiesToSpawn { get; set; } = [];
public SingleWave() : this([]) {}
}

View File

@@ -0,0 +1 @@
uid://cr8wog705ane6

View File

@@ -0,0 +1,11 @@
using Godot;
namespace Movementtests.managers;
[GlobalClass]
public partial class WaveContent(SingleWave[] waves) : Resource
{
[Export] public SingleWave[] Waves { get; set; } = waves;
public WaveContent() : this([]) {}
}

View File

@@ -0,0 +1 @@
uid://dijmv0wqc1xuv

View File

@@ -0,0 +1,100 @@
using System.Collections.Generic;
using System.Linq;
using Chickensoft.AutoInject;
using Chickensoft.Collections;
using Chickensoft.Introspection;
using Godot;
using Movementtests.tools;
namespace Movementtests.managers;
[GlobalClass, Meta(typeof(IAutoNode))]
public partial class WaveManager : Node
{
public override void _Notification(int what) => this.Notify(what);
public WaveContent WaveContent { get; set; }
public int CurrentWaveIndex { get; set; }
public int CurrentWaveCount => WaveContent.Waves.Length;
public Godot.Collections.Dictionary<EnemyDescription, int> CurrentWave =>
WaveContent.Waves[CurrentWaveIndex].EnemiesToSpawn;
public Dictionary<ulong, Enemy?> CurrentSpawnedEnemies { get; set; } = [];
public Set<Spawner> SpawnersInUse { get; set; } = [];
public List<Spawner> Spawners { get; set; } = [];
public void RegisterSpawner(Spawner spawner) => Spawners.Add(spawner);
public void InitializeFromResource(WaveContent waveContent) => WaveContent = waveContent;
public void StartWaves()
{
CurrentWaveIndex = 0;
StartNextWave();
}
public void StartNextWave()
{
if (CurrentWave.Count == 0)
{
GD.PrintErr("Wave has no enemies");
return;
}
if (Spawners.Count == 0)
{
GD.PrintErr("No spawners registered");
return;
}
SpawnEnemiesAsAvailable();
}
public void SpawnEnemiesAsAvailable()
{
var randomizedSpawners = Spawners.ToArray();
randomizedSpawners.Shuffle();
foreach (var (enemyDescription, numberRemaining) in CurrentWave)
{
if (numberRemaining <= 0) continue;
foreach (var spawner in randomizedSpawners)
{
if (!spawner.SupportedEnemyTypes.Contains(enemyDescription.Type)) continue;
if (SpawnersInUse.Contains(spawner)) continue;
var spawnedEnemy = spawner.SpawnEnemy(enemyDescription);
if (spawnedEnemy == null) continue;
CurrentSpawnedEnemies[spawnedEnemy.GetInstanceId()] = spawnedEnemy;
SpawnersInUse.Add(spawner);
spawnedEnemy.OnKilled += instanceId=> SpawnedEnemyDied(instanceId, spawner);
CurrentWave[enemyDescription]--;
break;
}
}
var remainingEnemiesToSpawn = CurrentWave.Values.Sum();
if (remainingEnemiesToSpawn <= 0) return; // Wave is fully spawned
GetTree().CreateTimer(1.0f).Timeout += SpawnEnemiesAsAvailable; // Call back the same function later to try and spawn the rest
}
public void SpawnedEnemyDied(ulong instanceId, Spawner spawner)
{
CurrentSpawnedEnemies.Remove(instanceId);
SpawnersInUse.Remove(spawner);
if (CurrentSpawnedEnemies.Count == 0) FinishWave();
}
public void FinishWave()
{
if (CurrentWaveIndex >= CurrentWaveCount) return; // All waves finished
CurrentWaveIndex++;
GetTree().CreateTimer(1.0f).Timeout += StartNextWave; // Start next wave in 1s
}
}

View File

@@ -0,0 +1 @@
uid://cprjrwfk8d0vf

View File

@@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="EnemyDescription" format=3 uid="uid://cfyafss8ncbhh"]
[ext_resource type="PackedScene" uid="uid://cmlud1hwkd6sv" path="res://scenes/enemies/flying_enemy/flying_enemy.tscn" id="1_yvgr4"]
[ext_resource type="Script" uid="uid://rhdkfi7nuvu1" path="res://managers/Wave/EnemyDescription.cs" id="2_hsb6g"]
[resource]
script = ExtResource("2_hsb6g")
Scene = ExtResource("1_yvgr4")
metadata/_custom_type_script = "uid://rhdkfi7nuvu1"

View File

@@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="EnemyDescription" format=3 uid="uid://3clksludry8g"]
[ext_resource type="PackedScene" uid="uid://dxt0e2ugmttqq" path="res://scenes/enemies/grounded_enemy/grounded_enemy.tscn" id="1_wxdbf"]
[ext_resource type="Script" uid="uid://rhdkfi7nuvu1" path="res://managers/Wave/EnemyDescription.cs" id="2_gk6ig"]
[resource]
script = ExtResource("2_gk6ig")
Scene = ExtResource("1_wxdbf")
metadata/_custom_type_script = "uid://rhdkfi7nuvu1"

View File

@@ -0,0 +1,17 @@
[gd_resource type="Resource" script_class="SingleWave" format=3 uid="uid://dm71u0ryn0w1o"]
[ext_resource type="Resource" uid="uid://cfyafss8ncbhh" path="res://managers/Wave/resources/flying_enemy_desc.tres" id="1_bcssi"]
[ext_resource type="Script" uid="uid://rhdkfi7nuvu1" path="res://managers/Wave/EnemyDescription.cs" id="2_3r6ce"]
[ext_resource type="Resource" uid="uid://3clksludry8g" path="res://managers/Wave/resources/grounded_enemy_desc.tres" id="2_mmsra"]
[ext_resource type="Resource" uid="uid://lnturc3ibr5c" path="res://managers/Wave/resources/projectile_enemy_desc.tres" id="3_3r6ce"]
[ext_resource type="Script" uid="uid://cr8wog705ane6" path="res://managers/Wave/SingleWave.cs" id="5_qckro"]
[resource]
script = ExtResource("5_qckro")
Enemies = Array[Object]([ExtResource("1_bcssi"), ExtResource("2_mmsra"), ExtResource("3_3r6ce")])
EnemiesToSpawn = Dictionary[ExtResource("2_3r6ce"), int]({
ExtResource("1_bcssi"): 1,
ExtResource("2_mmsra"): 1,
ExtResource("3_3r6ce"): 1
})
metadata/_custom_type_script = "uid://cr8wog705ane6"

View File

@@ -0,0 +1,10 @@
[gd_resource type="Resource" script_class="EnemyDescription" format=3 uid="uid://lnturc3ibr5c"]
[ext_resource type="PackedScene" uid="uid://dx3y8sjftqk8f" path="res://scenes/enemies/projectile_enemy/projectile_enemy.tscn" id="1_2nepo"]
[ext_resource type="Script" uid="uid://rhdkfi7nuvu1" path="res://managers/Wave/EnemyDescription.cs" id="2_bn1dh"]
[resource]
script = ExtResource("2_bn1dh")
Scene = ExtResource("1_2nepo")
Type = 1
metadata/_custom_type_script = "uid://rhdkfi7nuvu1"