feat: Implement a new portal door game mode with arena partitioning, dynamic connections, and multiplayer synchronization.
This commit is contained in:
@@ -210,36 +210,53 @@ func _setup_room_partitions():
|
||||
var _pending_sync_data = null
|
||||
|
||||
func _spawn_portal_doors():
|
||||
# Check if doors already exist to avoid duplicates
|
||||
if not doors.is_empty():
|
||||
print("[PortalModeManager] Doors already exist, skipping spawn. Count: ", doors.size())
|
||||
return
|
||||
# 1. Use synced configs if they exist (passed via main.rpc("sync_portal_configs"))
|
||||
var door_configs = get_meta("door_configs") if has_meta("door_configs") else []
|
||||
|
||||
# 2. If no synced configs (e.g. Server start), generate base + extras
|
||||
if door_configs.is_empty():
|
||||
if not multiplayer.is_server():
|
||||
print("[PortalModeManager] Client waiting for portal configs sync...")
|
||||
return
|
||||
|
||||
door_configs = [
|
||||
# BASE DOORS (2 per room)
|
||||
{"room": 0, "pos": Vector2i(6, 2), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East
|
||||
{"room": 0, "pos": Vector2i(2, 6), "rot": 0, "offset": Vector2i(0, -1)}, # South
|
||||
{"room": 1, "pos": Vector2i(7, 2), "rot": PI / 2, "offset": Vector2i(1, 0)}, # West
|
||||
{"room": 1, "pos": Vector2i(11, 6), "rot": 0, "offset": Vector2i(0, -1)}, # South
|
||||
{"room": 2, "pos": Vector2i(2, 7), "rot": 0, "offset": Vector2i(0, 1)}, # North
|
||||
{"room": 2, "pos": Vector2i(6, 11), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East
|
||||
{"room": 3, "pos": Vector2i(11, 7), "rot": 0, "offset": Vector2i(0, 1)}, # North
|
||||
{"room": 3, "pos": Vector2i(7, 11), "rot": PI / 2, "offset": Vector2i(1, 0)} # West
|
||||
]
|
||||
|
||||
# Server adds extras
|
||||
var extra_options = [
|
||||
{"room": 0, "pos": Vector2i(6, 5), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East (Gap from 6,2)
|
||||
{"room": 1, "pos": Vector2i(7, 5), "rot": PI / 2, "offset": Vector2i(1, 0)}, # West (Gap from 7,2)
|
||||
{"room": 2, "pos": Vector2i(6, 8), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East (Gap from 6,11)
|
||||
{"room": 3, "pos": Vector2i(7, 8), "rot": PI / 2, "offset": Vector2i(1, 0)} # West (Gap from 7,11)
|
||||
]
|
||||
extra_options.shuffle()
|
||||
door_configs.append(extra_options[0])
|
||||
door_configs.append(extra_options[1])
|
||||
|
||||
# Broadcast to clients
|
||||
main.rpc("sync_portal_configs", door_configs)
|
||||
|
||||
# 3. Spawn the doors
|
||||
if not doors.is_empty(): return # Guard against double spawn
|
||||
|
||||
print("[PortalModeManager] Spawning %d doors. Peer: %d" % [door_configs.size(), multiplayer.get_unique_id()])
|
||||
|
||||
print("[PortalModeManager] Spawning portal doors. Peer ID: ", multiplayer.get_unique_id())
|
||||
var portal_scene = load("res://scenes/portal_door.tscn")
|
||||
var stands_container = main.get_node_or_null("Stands")
|
||||
|
||||
if not stands_container:
|
||||
print("[PortalModeManager] Warning: 'Stands' container not found, creating one...")
|
||||
stands_container = Node3D.new()
|
||||
stands_container.name = "Stands"
|
||||
main.add_child(stands_container)
|
||||
|
||||
var door_configs = [
|
||||
# Room 0
|
||||
{"room": 0, "pos": Vector2i(6, 2), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East
|
||||
{"room": 0, "pos": Vector2i(2, 6), "rot": 0, "offset": Vector2i(0, -1)}, # South
|
||||
# Room 1
|
||||
{"room": 1, "pos": Vector2i(7, 2), "rot": PI / 2, "offset": Vector2i(1, 0)}, # West
|
||||
{"room": 1, "pos": Vector2i(11, 6), "rot": 0, "offset": Vector2i(0, -1)}, # South
|
||||
# Room 2
|
||||
{"room": 2, "pos": Vector2i(2, 7), "rot": 0, "offset": Vector2i(0, 1)}, # North
|
||||
{"room": 2, "pos": Vector2i(6, 11), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East
|
||||
# Room 3
|
||||
{"room": 3, "pos": Vector2i(11, 7), "rot": 0, "offset": Vector2i(0, 1)}, # North
|
||||
{"room": 3, "pos": Vector2i(7, 11), "rot": PI / 2, "offset": Vector2i(1, 0)} # West
|
||||
]
|
||||
|
||||
|
||||
for i in range(door_configs.size()):
|
||||
var cfg = door_configs[i]
|
||||
if not portal_scene:
|
||||
@@ -278,7 +295,8 @@ const PORTAL_COLORS = [
|
||||
Color(0, 1, 1), # Cyan
|
||||
Color(1, 0, 1), # Magenta
|
||||
Color(1, 1, 0), # Yellow
|
||||
Color(0, 1, 0) # Green
|
||||
Color(0, 1, 0), # Green
|
||||
Color(1, 0.5, 0) # Orange
|
||||
]
|
||||
|
||||
func _randomize_connections():
|
||||
@@ -490,7 +508,8 @@ func handle_portal_interaction(player, door):
|
||||
|
||||
var current_time = Time.get_ticks_msec()
|
||||
if player_portal_cooldowns.has(player.name):
|
||||
if current_time - player_portal_cooldowns[player.name] < 1000:
|
||||
# Reduce cooldown to 200ms (more responsive than 1s, but enough to avoid jitter)
|
||||
if current_time - player_portal_cooldowns[player.name] < 200:
|
||||
return
|
||||
player_portal_cooldowns[player.name] = current_time
|
||||
|
||||
|
||||
@@ -35,7 +35,8 @@ func _on_body_entered(body: Node3D):
|
||||
if body.is_in_group("Players") or body.get("is_bot"):
|
||||
var current_time = Time.get_ticks_msec()
|
||||
if body.has_meta("last_portal_time"):
|
||||
if current_time - body.get_meta("last_portal_time") < 1000:
|
||||
# Reduce cooldown to 200ms to match manager logic and allow fast re-entry
|
||||
if current_time - body.get_meta("last_portal_time") < 200:
|
||||
return
|
||||
|
||||
body.set_meta("last_portal_time", current_time)
|
||||
|
||||
Reference in New Issue
Block a user