update feature & bugfix

This commit is contained in:
2026-01-23 22:26:44 +08:00
parent 89a3beb2b2
commit d262bb8dc0
12 changed files with 198 additions and 87 deletions
+17 -4
View File
@@ -51,8 +51,8 @@ func _ready():
queue_free()
return
# Wait for actor to be fully ready
await get_tree().create_timer(1.0).timeout
# Wait for actor to be fully ready (player._ready awaits 0.5s then creates managers)
await get_tree().create_timer(1.5).timeout
enhanced_gridmap = actor.enhanced_gridmap
if not enhanced_gridmap:
@@ -335,10 +335,23 @@ func _try_move() -> bool:
_is_processing_action = true
_current_action = "moving"
# Wait for movement to finish (signal from movement manager)
await actor.movement_manager.movement_finished
# Wait for movement to finish or timeout (safety)
# Race: Signal vs Timeout
# Since Godot 4 doesn't support 'await' racing easily without helper,
# we'll just wait for the signal but ensure movement manager emits it.
# safer approach: check if is_moving goes false
# Safety timeout to prevent infinite loop
var max_wait_time = 2.0
var elapsed = 0.0
while actor.is_player_moving and is_instance_valid(self):
await get_tree().process_frame
elapsed += get_process_delta_time()
if elapsed > max_wait_time:
print("[BotController] Movement timed out!")
break
if not is_instance_valid(self): return true
_is_processing_action = false
_current_action = "idle"
+7 -16
View File
@@ -42,10 +42,7 @@ func rotate_towards_target(target_pos: Vector2i):
func simple_move_to(grid_position: Vector2i) -> bool:
if is_moving:
# Calculate direction for buffering
var direction = grid_position - player.current_position
# FIX: Only buffer if direction is DIFFERENT from current move (prevents overshoot)
if direction != current_move_direction:
buffer_move_input(direction)
return false
@@ -53,11 +50,9 @@ func simple_move_to(grid_position: Vector2i) -> bool:
if not player.is_multiplayer_authority():
return false
# Check if player is frozen
if player.get("is_frozen"):
return false
# Check if target is within 1-tile range
var distance: int
if use_diagonal_movement:
distance = max(abs(grid_position.x - player.current_position.x), abs(grid_position.y - player.current_position.y))
@@ -67,32 +62,23 @@ func simple_move_to(grid_position: Vector2i) -> bool:
if distance != 1:
return false # Only single-step moves allowed
# Check if target position is within grid bounds
if not enhanced_gridmap.is_position_valid(grid_position):
return false
# Check for finish line logic (delegated back to player or race manager)
if player.has_method("can_move_to_finish") and not player.can_move_to_finish(grid_position):
return false
# Check walkability and obstacles
var cell_item = enhanced_gridmap.get_cell_item(Vector3i(grid_position.x, 0, grid_position.y))
if cell_item == -1 or cell_item in enhanced_gridmap.non_walkable_items:
return false
# Check for player collision and try to push
if player.is_position_occupied(grid_position):
# Direction for the push
var push_dir = grid_position - player.current_position
if not try_push(grid_position, push_dir):
return false
# If push succeeded, the tile is now technically free (or will be processed as free)
# proceed to move into it
# All checks passed, perform move
rotate_towards_target(grid_position)
# Play walk animation (synced across network)
if player.is_multiplayer_authority() and player.has_method("sync_walk_animation"):
player.rpc("sync_walk_animation")
@@ -101,7 +87,6 @@ func simple_move_to(grid_position: Vector2i) -> bool:
current_move_direction = grid_position - player.current_position
# Use the existing RPC to move
player.rpc("start_movement_along_path", path, not (player.is_bot or player.is_in_group("Bots")))
return true
@@ -119,15 +104,21 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
# Check if pushed destination is valid
if not enhanced_gridmap.is_position_valid(pushed_to_pos):
# Blocked by world bounds -> Double Push!
other_player.rpc("apply_stagger", 1.5)
return false
# Check walkability of pushed destination
var cell_item = enhanced_gridmap.get_cell_item(Vector3i(pushed_to_pos.x, 0, pushed_to_pos.y))
if cell_item == -1 or cell_item in enhanced_gridmap.non_walkable_items:
# Blocked by obstacle -> Double Push!
other_player.rpc("apply_stagger", 1.5)
return false
# Check if pushed destination is ALREADY occupied (no daisy chaining)
# Check if pushed destination is ALREADY occupied (Double Push / Crush)
if player.is_position_occupied(pushed_to_pos):
# Blocked by another player -> Double Push!
other_player.rpc("apply_stagger", 1.5)
return false
# Check if other player is currently moving (don't push moving players to avoid sync issues)
+11
View File
@@ -58,11 +58,22 @@ func _add_bar():
# Type 1 = POWERUP message for special styling
player.rpc("display_message", "Power-up bar filled!", 1)
print("[PowerUp] Player %s gained 1 bar! Total: %d/%d points" % [player.name, current_points, MAX_POINTS])
if player.is_multiplayer_authority():
player.get_node("PowerUpManager").rpc("sync_points", current_points)
# =============================================================================
# Goal Completion Reward
# =============================================================================
func acquire_smash_bonus():
"""Called when player is smashed. Grants 1 bar up to a max of 2 bars."""
if get_bars() < 2:
_add_bar()
print("[PowerUp] Player %s gained smash bonus bar! Total: %d/%d" % [player.name, current_points, MAX_POINTS])
else:
print("[PowerUp] Player %s smash bonus capped (already has >= 2 bars)" % player.name)
func add_goal_completion_reward():
"""Called when player completes a goal pattern. Awards 1 bar."""
_add_bar()
+4 -1
View File
@@ -205,7 +205,8 @@ func set_local_player(player):
func _connect_powerup_manager_deferred(player):
"""Wait for PowerUpManager to be initialized before connecting."""
await player.get_tree().create_timer(0.3).timeout
# player._ready waits 0.5s before creating managers, so wait longer
await player.get_tree().create_timer(0.8).timeout
var powerup_manager = player.get_node_or_null("PowerUpManager")
if powerup_manager:
@@ -213,6 +214,8 @@ func _connect_powerup_manager_deferred(player):
powerup_manager.points_changed.connect(_on_powerup_points_changed)
# Initialize bar with current values
update_powerup_bar(powerup_manager.get_points(), powerup_manager.get_max_points())
else:
push_warning("[UIManager] PowerUpManager not found on player after 0.8s wait")
# =============================================================================
# Power-Up Bar UI (Battery Style)