Made more enemies, easier to kill, more slashy. You get passive health regen, health orbs. Little key bindings tooltip.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user