Made more enemies, easier to kill, more slashy. You get passive health regen, health orbs. Little key bindings tooltip.

This commit is contained in:
2026-06-30 22:57:11 +01:00
parent 7fa2efabaf
commit 97ebbb1618
17 changed files with 404 additions and 6 deletions
+92
View File
@@ -6,6 +6,7 @@ extends Node3D
@onready var players_container: Node3D = $PlayersContainer
@onready var weapons_container: Node3D = $WeaponsContainer
@onready var enemies_container: Node3D = $EnemiesContainer
var orbs_container: Node3D = null
@onready var enemy_spawner: EnemySpawner = $EnemySpawner
@onready var player_spawn_points: Node3D = $PlayerSpawnPoints
@onready var menu: Control = $Menu
@@ -59,6 +60,15 @@ func _ready():
add_child(enemies_container)
print("Created EnemiesContainer")
# Create or find health orbs container
if has_node("OrbsContainer"):
orbs_container = get_node("OrbsContainer")
else:
orbs_container = Node3D.new()
orbs_container.name = "OrbsContainer"
add_child(orbs_container)
print("Created OrbsContainer")
# Don't initialize weapons in _ready() - wait for Host/Join to be pressed
# This is handled in initialize_multiplayer() which is called after the
# multiplayer peer is properly set up
@@ -96,6 +106,13 @@ func initialize_multiplayer():
# Spawn armed enemies
_spawn_armed_enemies()
# Scatter a few health orbs so the pickup is visible from the start
_spawn_initial_health_orbs()
# Begin automatic timed enemy waves
if enemy_spawner:
enemy_spawner.start_auto_waves()
# Spawn the host player (peer ID 1)
print("[Level] Spawning host player")
var host_info = Network.players.get(1, {"nick": "Host", "skin": "blue"})
@@ -265,6 +282,11 @@ func _on_player_connected(peer_id, player_info):
print("[Server] Syncing enemy ", enemy.name, " at position ", enemy.global_position, " to peer ", peer_id)
rpc_id(peer_id, "_spawn_dummy_local", enemy_id, enemy.global_position)
# Sync existing health orbs to the newly joined player
print("[Server] Syncing health orbs to newly connected peer: ", peer_id)
for orb_id in _active_orbs.keys():
rpc_id(peer_id, "_spawn_health_orb_local", orb_id, _active_orbs[orb_id])
# Sync equipped weapons for all existing players to the newly joined player
print("[Server] Syncing equipped weapons to newly connected peer: ", peer_id)
for player_node in players_container.get_children():
@@ -647,6 +669,76 @@ func _client_spawn_weapon(weapon_data_path: String, spawn_position: Vector3, ini
print("[Client ", multiplayer.get_unique_id(), "] Calling spawn_world_weapon locally")
spawn_world_weapon(weapon_data_path, spawn_position, initial_velocity, weapon_id)
# ---------- HEALTH ORBS ----------
var _orb_spawn_counter: int = 0
var _active_orbs: Dictionary = {} # orb_id -> spawn position (Vector3), for late-join sync
## Spawn a health orb at a position (server only, replicates to all clients)
func spawn_health_orb(spawn_pos: Vector3):
if not multiplayer.is_server():
return
_orb_spawn_counter += 1
rpc("_spawn_health_orb_local", _orb_spawn_counter, spawn_pos)
## Spawn a health orb on all clients (call_local spawns on server too)
@rpc("any_peer", "call_local", "reliable")
func _spawn_health_orb_local(orb_id: int, spawn_pos: Vector3):
if not orbs_container:
push_error("[Level] OrbsContainer not found!")
return
var orb_name = "HealthOrb_" + str(orb_id)
if orbs_container.has_node(orb_name):
return # Already spawned (e.g. duplicate sync)
var orb_scene = load("res://level/scenes/health_orb.tscn")
if not orb_scene:
push_error("[Level] Failed to load health_orb.tscn")
return
var orb = orb_scene.instantiate()
orb.orb_id = orb_id
orb.name = orb_name
orb.position = spawn_pos
orbs_container.add_child(orb, true)
# Server tracks active orbs for late-join sync
if multiplayer.is_server():
_active_orbs[orb_id] = spawn_pos
print("[Peer ", multiplayer.get_unique_id(), "] Spawned health orb ", orb_name, " at ", spawn_pos)
## Remove a health orb from all clients (called by HealthOrb when collected)
func remove_health_orb(orb_id: int):
if not multiplayer.is_server():
return
if _active_orbs.has(orb_id):
_active_orbs.erase(orb_id)
rpc("_remove_orb_on_clients", orb_id)
## RPC to remove an orb on all clients
@rpc("any_peer", "call_local", "reliable")
func _remove_orb_on_clients(orb_id: int):
var orb_name = "HealthOrb_" + str(orb_id)
if orbs_container and orbs_container.has_node(orb_name):
orbs_container.get_node(orb_name).queue_free()
## Scatter a few health orbs at server start
func _spawn_initial_health_orbs():
if not multiplayer.is_server():
return
# Wait a frame for everything to be ready
await get_tree().process_frame
var orb_positions = [
Vector3(6, 1, 6),
Vector3(-6, 1, -6),
Vector3(-6, 1, 6),
]
for pos in orb_positions:
spawn_health_orb(pos)
# ---------- ARMED ENEMY SPAWNING ----------
var _armed_enemy_counter: int = 0