extends Node3D class_name WorldManager enum STATE { INIT, IDLE, SPAWN, SPAWNING, FIGHT, WAVE_END, LEVEL_END } var level : Level var paths : Array[Node] var state : STATE = STATE.INIT var wave : int = 0 var currentTroop : Troop : get(): return level.waves[wave - 1].troops[currentTroopIdx] var currentTroopIdx : int = 0 var enemiesAlive : int = 0 @onready var troopTimer : Timer = $TroopTimer func _ready() -> void: $SFX/SFXPrepareYourself.play() EventBus.projectile_shooted.connect(onProjectileShooted) EventBus.lauch_next_wave.connect(changeState.bind(STATE.SPAWN)) troopTimer.timeout.connect(spawnTroop) func _input(event: InputEvent) -> void: if event.is_action_pressed("spawn_next_wave"): changeState(STATE.SPAWN) func _process(_delta: float) -> void: if state == STATE.INIT: return match state: STATE.SPAWN: spawnNextWave() state = STATE.SPAWNING STATE.SPAWNING when troopTimer.is_stopped(): state = STATE.FIGHT STATE.FIGHT when enemiesAlive == 0: if wave != level.waves.size(): $SFX/SFXWinner.play() EventBus.wave_finished.emit() state = STATE.WAVE_END STATE.WAVE_END when wave == level.waves.size(): EventBus.player_has_won.emit() state = STATE.LEVEL_END STATE.WAVE_END when level.auto_launch_wave: state = STATE.SPAWN func changeState(newState: STATE) -> void: match newState: STATE.SPAWN when [STATE.IDLE, STATE.WAVE_END].has(state): state = newState func spawnNextWave() -> void: currentTroopIdx = 0 wave += 1 if wave == level.waves.size(): $SFX/SFXFinalRound.play() else: $SFX/SFXFight.play() EventBus.wave_has_change.emit(wave, level.waves[wave - 1].troops[0].spawn_delay) spawnNextTroop() func spawnNextTroop() -> void: # Wave spawning is finished if currentTroopIdx == level.waves[wave - 1].troops.size(): return if currentTroop.spawn_delay == 0: spawnTroop() else: troopTimer.start(currentTroop.spawn_delay) func spawnTroop() -> void: var enemyScene : PackedScene = load(currentTroop.enemy) var totalDelay : float = 0 for n in currentTroop.number_to_spawn: spawnEnemy(enemyScene, currentTroop.lane_to_spawn, totalDelay) totalDelay += currentTroop.pack_delay currentTroopIdx += 1 spawnNextTroop() func spawnEnemy(enemyScene: PackedScene, laneToSpawn: int, delay: float) -> void: var enemy : PathFollow3D = createEnemy(enemyScene) if delay > 0: await get_tree().create_timer(delay, false).timeout paths[laneToSpawn].add_child(enemy) enemiesAlive += 1 func createEnemy(enemyScene: PackedScene) -> PathFollow3D : var PF3D : PathFollow3D = enemyScene.instantiate() var enemy : Enemy = PF3D.find_children("*", "Enemy")[0] enemy.died.connect(func(): enemiesAlive -= 1) return PF3D func addMap(mapScene : PackedScene) -> void: var map : Map = mapScene.instantiate() add_child(map) level = map.level paths = map.paths.get_children() Game.money = level.startingMoney Game.maxTier = level.tier_max Game.initTowers(level.allowedTowers) state = STATE.SPAWN if level.auto_start else STATE.IDLE func onProjectileShooted(projectile: Projectile, startPosition: Vector3) -> void: add_child(projectile) projectile.global_position = startPosition