feat: Add PlayerMovementManager for grid-based movement, rotation, and player-to-player push mechanics.

This commit is contained in:
Yogi Wiguna
2026-02-26 17:46:14 +08:00
parent 145a1a53dc
commit 38a7c06311
+43 -6
View File
@@ -176,11 +176,27 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
# 3. Knockback / Stagger
# Push them away
var pushed_to_pos = target_pos + direction
if not _is_position_in_static_stand_area(pushed_to_pos) and \
enhanced_gridmap.is_position_valid(pushed_to_pos) and \
enhanced_gridmap.get_cell_item(Vector3i(pushed_to_pos.x, 0, pushed_to_pos.y)) != -1 and \
not player.is_position_occupied(pushed_to_pos) and \
not _is_position_blocked_by_physics(pushed_to_pos):
# IMPROVED: Check if destination is valid and walkable to prevent being stuck on 'blocks'
var is_dest_valid = _can_push_to(pushed_to_pos)
# DEFLECTION LOGIC: If direct path is blocked, try diagonal deflection
if not is_dest_valid:
var alts = []
if direction.x != 0 and direction.y == 0: # Horizontal push -> try diagonal North/South
alts = [pushed_to_pos + Vector2i(0, 1), pushed_to_pos + Vector2i(0, -1)]
elif direction.y != 0 and direction.x == 0: # Vertical push -> try diagonal East/West
alts = [pushed_to_pos + Vector2i(1, 0), pushed_to_pos + Vector2i(-1, 0)]
elif direction.x != 0 and direction.y != 0: # Diagonal push -> try horizontal/vertical components
alts = [pushed_to_pos - Vector2i(direction.x, 0), pushed_to_pos - Vector2i(0, direction.y)]
for alt in alts:
if _can_push_to(alt):
pushed_to_pos = alt
is_dest_valid = true
break
if is_dest_valid:
# Valid push
var push_path = [Vector2(pushed_to_pos.x, pushed_to_pos.y)]
if _can_rpc():
@@ -192,7 +208,7 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
other_player.rpc("apply_stagger", 1.5)
else:
# Wall/Blocked -> Stagger in place
# Wall/Blocked -> Stagger in place (Only if no alternatives found)
if _can_rpc():
other_player.rpc("apply_stagger", 1.5)
@@ -460,6 +476,27 @@ func _is_position_in_static_stand_area(pos: Vector2i) -> bool:
return false
func _can_push_to(pos: Vector2i) -> bool:
"""Helper to validate if a grid position is a safe landing spot for a push."""
if not enhanced_gridmap or not enhanced_gridmap.is_position_valid(pos):
return false
var cell_item = enhanced_gridmap.get_cell_item(Vector3i(pos.x, 0, pos.y))
# Must be walkable and NOT in non_walkable_items (to prevent getting stuck on walls/blocks)
if cell_item == -1 or cell_item in enhanced_gridmap.non_walkable_items:
return false
if player.is_position_occupied(pos):
return false
if _is_position_in_static_stand_area(pos):
return false
if _is_position_blocked_by_physics(pos):
return false
return true
func _is_position_blocked_by_physics(target_pos: Vector2i) -> bool:
if not player.is_inside_tree(): return false