feat: Implement core game managers, player movement logic, and initial UI scenes.

This commit is contained in:
2025-12-27 05:45:57 +08:00
parent 6870016ba6
commit c5e9d073fa
23 changed files with 1456 additions and 97 deletions
+169 -15
View File
@@ -78,6 +78,17 @@ var spawn_point_selected = false
# Action for hilighter
var highlighted_spawn_points = []
var _is_highlighting: bool = false
# Character selection and animation
@onready var anim_player: AnimationPlayer = $AnimationPlayer
@onready var character_bob: Node3D = $Bob
@onready var character_masbro: Node3D = $Masbro
@onready var character_gatot: Node3D = $Gatot
@onready var character_oldpop: Node3D = $Oldpop
var selected_character: String = "Masbro" # Default character (matches tscn default visibility)
const AVAILABLE_CHARACTERS: Array[String] = ["Bob", "Masbro", "Gatot", "Oldpop"]
@export var movement_range: int = 1:
@@ -124,6 +135,9 @@ func _ready():
_init_managers()
# Initialize character selection from LobbyManager
_setup_character()
# Early setup for bots
if is_bot == true or is_in_group("Bots"):
# Initialize behavior tree for bots
@@ -162,11 +176,13 @@ func _ready():
enhanced_gridmap.initialize_astar()
enhanced_gridmap.set_diagonal_movement(use_diagonal_movement)
# Request current spawn positions before highlighting
request_spawn_positions_update()
highlight_available_spawn_points()
# Remove this line as goals are now managed by the host
# Skip manual spawn selection if random spawn is enabled
# Host will assign positions via RPC
if not LobbyManager.get_randomize_spawn():
# Request current spawn positions before highlighting
request_spawn_positions_update()
highlight_available_spawn_points()
# Remove this line as goals are now managed by the host
#append_random_goals()
playerboard.resize(25)
@@ -181,21 +197,26 @@ func _ready():
if enhanced_gridmap:
enhanced_gridmap.initialize_astar()
enhanced_gridmap.set_diagonal_movement(use_diagonal_movement)
current_position = find_valid_starting_position()
update_player_position(current_position)
# Only set position if not using random spawn (host will assign via RPC)
# AND not already assigned
if not LobbyManager.get_randomize_spawn() and not spawn_point_selected:
current_position = find_valid_starting_position()
update_player_position(current_position)
#append_random_goals()
playerboard.resize(25)
playerboard.fill(-1)
# Ensure proper initial positioning
global_position = Vector3(
current_position.x * cell_size.x + cell_size.x * 0.5,
1.0,
current_position.y * cell_size.z + cell_size.z * 0.5
)
if is_multiplayer_authority():
rpc("sync_position", current_position)
# Ensure proper initial positioning (only if NOT using random spawn and not already positioned)
# When random spawn is enabled, the host assigns positions via set_spawn_position RPC
if not LobbyManager.get_randomize_spawn() and not spawn_point_selected:
global_position = Vector3(
current_position.x * cell_size.x + cell_size.x * 0.5,
1.0,
current_position.y * cell_size.z + cell_size.z * 0.5
)
if is_multiplayer_authority():
rpc("sync_position", current_position)
func _init_managers():
movement_manager = load("res://scripts/managers/player_movement_manager.gd").new()
@@ -233,6 +254,125 @@ func _init_managers():
add_child(powerup_manager)
powerup_manager.initialize(self, enhanced_gridmap)
# =============================================================================
# Character Selection
# =============================================================================
func set_character(character_name: String) -> void:
"""Show only the selected character model and hide others. Updates AnimationPlayer root."""
if character_name not in AVAILABLE_CHARACTERS:
push_warning("Invalid character name: %s" % character_name)
return
selected_character = character_name
# Hide all character models
if character_bob: character_bob.visible = false
if character_masbro: character_masbro.visible = false
if character_gatot: character_gatot.visible = false
if character_oldpop: character_oldpop.visible = false
# Show selected character and update AnimationPlayer root
var active_character: Node3D = null
match character_name:
"Bob":
if character_bob:
character_bob.visible = true
active_character = character_bob
"Masbro":
if character_masbro:
character_masbro.visible = true
active_character = character_masbro
"Gatot":
if character_gatot:
character_gatot.visible = true
active_character = character_gatot
"Oldpop":
if character_oldpop:
character_oldpop.visible = true
active_character = character_oldpop
# Update AnimationPlayer's root node to point to active character
if anim_player and active_character:
anim_player.root_node = anim_player.get_path_to(active_character)
# Start with idle animation
play_idle_animation()
@rpc("any_peer", "call_local", "reliable")
func sync_character(character_name: String) -> void:
"""Sync character selection across all clients."""
set_character(character_name)
func _setup_character() -> void:
"""Initialize character based on LobbyManager selection or defaults."""
var character_name = "Masbro" # Default
var player_authority_id = get_multiplayer_authority()
# Look up character from LobbyManager for this player (works for all players)
if LobbyManager:
var players = LobbyManager.get_players()
for player_data in players:
if player_data.get("id") == player_authority_id:
character_name = player_data.get("character", "Masbro")
break
set_character(character_name)
# If this is our local player, also sync to other clients for late joiners
if is_multiplayer_authority():
rpc("sync_character", character_name)
# =============================================================================
# Animation Functions
# =============================================================================
# Animation speed multiplier for fast-paced gameplay
const ANIMATION_SPEED: float = 2.0
func play_walk_animation() -> void:
"""Play walking animation at increased speed."""
if anim_player and anim_player.has_animation("animation-pack/walk_forward"):
anim_player.play("animation-pack/walk_forward", -1, ANIMATION_SPEED)
func play_pickup_animation() -> void:
"""Play pickup/grab tile animation at increased speed."""
if anim_player and anim_player.has_animation("animation-pack/take_tile_1"):
anim_player.play("animation-pack/take_tile_1", -1, ANIMATION_SPEED)
func play_put_animation() -> void:
"""Play put/drop tile animation at increased speed."""
if anim_player and anim_player.has_animation("animation-pack/drop_tile_1"):
anim_player.play("animation-pack/drop_tile_1", -1, ANIMATION_SPEED)
func play_special_animation() -> void:
"""Play special ability animation (backflip) at increased speed."""
if anim_player and anim_player.has_animation("animation-pack/backflip_1"):
anim_player.play("animation-pack/backflip_1", -1, ANIMATION_SPEED * 1.5)
func play_idle_animation() -> void:
"""Play idle animation at normal speed."""
if anim_player and anim_player.has_animation("animation-pack/idle"):
anim_player.play("animation-pack/idle")
# =============================================================================
# Screen Shake
# =============================================================================
@rpc("any_peer", "call_local", "reliable")
func trigger_screen_shake(shake_type: String) -> void:
"""Trigger screen shake effect. Called via RPC when targeted or completing goals."""
var main = get_tree().get_root().get_node_or_null("Main")
if main:
var screen_shake_manager = main.get_node_or_null("ScreenShakeManager")
if screen_shake_manager:
match shake_type:
"targeted":
screen_shake_manager.shake_targeted()
"goal":
screen_shake_manager.shake_goal_complete()
_:
screen_shake_manager.shake_light()
# Add function to check if position is at finish line
func is_at_finish_line() -> bool:
return race_manager.is_at_finish_line()
@@ -1121,6 +1261,20 @@ func sync_position(pos: Vector2i):
current_position.y * cell_size.z + cell_size.z * 0.5
) + cell_offset
@rpc("any_peer", "call_local", "reliable")
func set_spawn_position(pos: Vector2i):
"""Set spawn position - used by random spawn system."""
current_position = pos
spawn_point_selected = true
# Clear any spawn highlights
clear_spawn_highlights()
# Update visual position
global_position = Vector3(
current_position.x * cell_size.x + cell_size.x * 0.5,
cell_size.y,
current_position.y * cell_size.z + cell_size.z * 0.5
) + cell_offset
func highlight_valid_obstacle_cells():
action_manager.highlight_valid_obstacle_cells()