improve floor normal checks even more

This commit is contained in:
2025-08-23 15:04:38 +10:00
parent 737ffd89f7
commit cf3710c8c2
3 changed files with 61 additions and 77 deletions

View File

@@ -1080,8 +1080,9 @@ _stop_on_landing = false
metadata/_custom_type_script = "uid://ceyu5der8j8gq"
[node name="Trajectory17" type="Marker2D" parent="Trajectories"]
position = Vector2(114, -2672)
position = Vector2(58, -2024)
script = ExtResource("4_74lek")
flip_direction = true
_steps = 190
_jump = false
metadata/_custom_type_script = "uid://ceyu5der8j8gq"

View File

@@ -95,56 +95,37 @@ static func process_collision(
return new_velocity
static func shapecast(
static func collide_shape(
pos: Vector2,
direction: Vector2,
shape: Shape2D,
space_state: PhysicsDirectSpaceState2D
) -> bool:
space_state: PhysicsDirectSpaceState2D,
max_results: int = 1
) -> Array[Vector2]:
var floor_query := PhysicsShapeQueryParameters2D.new()
floor_query.collision_mask = 1
floor_query.transform = Transform2D(0, pos)
floor_query.motion = direction
floor_query.shape = shape
floor_query.margin = -0.08
return space_state.intersect_shape(floor_query).size() > 0
return space_state.collide_shape(floor_query, max_results)
static func raycast_down(
pos: Vector2, shape: RectangleShape2D, space_state: PhysicsDirectSpaceState2D
) -> Dictionary:
var half_width := shape.size.x / 2.0
var from := pos + Vector2.UP * (shape.size.x + 1)
var to := pos + Vector2.DOWN * (shape.size.x + 1)
var result: Dictionary = {}
var query_center := PhysicsRayQueryParameters2D.create(from, to)
var result_center := space_state.intersect_ray(query_center)
if result_center and result_center["normal"] != Vector2.ZERO:
if result_center["normal"] == Vector2.UP:
return result_center
result = result_center
var query_left := PhysicsRayQueryParameters2D.create(
from + Vector2.LEFT * half_width, to + Vector2.LEFT * half_width
)
var result_left := space_state.intersect_ray(query_left)
if result_left and result_left["normal"] != Vector2.ZERO:
if result_left["normal"] == Vector2.UP:
return result_left
result = result_left
var query_right := PhysicsRayQueryParameters2D.create(
from + Vector2.RIGHT * half_width, to + Vector2.RIGHT * half_width
)
var result_right := space_state.intersect_ray(query_right)
if result_right and result_right["normal"] != Vector2.ZERO:
if result_right["normal"] == Vector2.UP:
return result_right
result = result_right
return result
static func raycast_floor_angle(
collisions: Array[Vector2], space_state: PhysicsDirectSpaceState2D
) -> float:
var floor_angle: float = 0
for i in range(1, collisions.size(), 2):
var from := collisions[i] + Vector2.UP
var to := collisions[i] + Vector2.DOWN
var query := PhysicsRayQueryParameters2D.create(from, to)
var result := space_state.intersect_ray(query)
if result["normal"] != Vector2.ZERO:
var normal := result["normal"] as Vector2
floor_angle = -normal.angle_to(Vector2.UP)
if is_zero_approx(floor_angle):
return floor_angle
return floor_angle
func _ready() -> void:
@@ -261,27 +242,27 @@ func _handle_collision() -> void:
var is_on_wall_prev := _is_on_wall
var space_state := get_world_2d().direct_space_state
_is_on_floor = shapecast(
_shape.global_position, Vector2.DOWN, _shape.shape, space_state
var floor_collisions := collide_shape(
_shape.global_position, Vector2.DOWN, _shape.shape, space_state, 3
)
_is_on_wall = (
shapecast(_shape.global_position, Vector2.LEFT, _shape.shape, space_state)
or shapecast(_shape.global_position, Vector2.RIGHT, _shape.shape, space_state)
)
_is_on_ceiling = shapecast(
var ceiling_collisions := collide_shape(
_shape.global_position, Vector2.UP, _shape.shape, space_state
)
var wall_collisions := collide_shape(
_shape.global_position, Vector2.LEFT, _shape.shape, space_state
)
if not wall_collisions:
wall_collisions = collide_shape(
_shape.global_position, Vector2.RIGHT, _shape.shape, space_state
)
_is_on_floor = floor_collisions.size() > 0
_is_on_ceiling = ceiling_collisions.size() > 0
_is_on_wall = wall_collisions.size() > 0
var is_on_floor_changed := not is_on_floor_prev and _is_on_floor
if is_on_floor_changed and _is_on_floor:
var raycast_result := raycast_down(
global_position, _shape.shape as RectangleShape2D, space_state
)
if raycast_result:
var normal := raycast_result["normal"] as Vector2
_floor_angle = -normal.angle_to(Vector2.UP)
else:
_floor_angle = 0
if is_on_floor_changed:
_floor_angle = raycast_floor_angle(floor_collisions, space_state)
var hit_floor := is_on_floor_changed and is_zero_approx(_floor_angle)
var hit_slope := is_on_floor_changed and not is_zero_approx(_floor_angle)

View File

@@ -250,29 +250,27 @@ func _draw() -> void:
var shape_pos := to_global(pos) + Vector2.UP * (_player_size.y / 2.0)
is_on_floor = Player.shapecast(
shape_pos, Vector2.DOWN, _player_shape, space_state
var floor_collisions := Player.collide_shape(
shape_pos, Vector2.DOWN, _player_shape, space_state, 3
)
is_on_wall = (
Player.shapecast(shape_pos, Vector2.LEFT, _player_shape, space_state)
or Player.shapecast(
shape_pos, Vector2.RIGHT, _player_shape, space_state
)
)
is_on_ceiling = Player.shapecast(
var ceiling_collisions := Player.collide_shape(
shape_pos, Vector2.UP, _player_shape, space_state
)
var wall_collisions := Player.collide_shape(
shape_pos, Vector2.LEFT, _player_shape, space_state
)
if not wall_collisions:
wall_collisions = Player.collide_shape(
shape_pos, Vector2.RIGHT, _player_shape, space_state
)
is_on_floor = floor_collisions.size() > 0
is_on_ceiling = ceiling_collisions.size() > 0
is_on_wall = wall_collisions.size() > 0
var is_on_floor_changed := not is_on_floor_prev and is_on_floor
if is_on_floor_changed and is_on_floor:
var raycast_result := Player.raycast_down(
to_global(pos), _player_shape, space_state
)
if raycast_result:
var normal := raycast_result["normal"] as Vector2
floor_angle = -normal.angle_to(Vector2.UP)
else:
floor_angle = 0
if is_on_floor_changed:
floor_angle = Player.raycast_floor_angle(floor_collisions, space_state)
var hit_floor := is_on_floor_changed and is_zero_approx(floor_angle)
var hit_slope := is_on_floor_changed and not is_zero_approx(floor_angle)
@@ -359,12 +357,16 @@ func _draw_collision_hit(pos: Vector2, side: Side, color: Color) -> void:
var is_left_or_right := side == SIDE_LEFT or side == SIDE_RIGHT
var line_from := (
(Vector2.UP if is_left_or_right else Vector2.LEFT) * _player_size.y / 2
(Vector2.UP * _player_size.y)
if is_left_or_right
else (Vector2.LEFT * _player_size.x)
)
var line_to := (
(Vector2.DOWN if is_left_or_right else Vector2.RIGHT) * _player_size.y / 2
(Vector2.DOWN * _player_size.y)
if is_left_or_right
else (Vector2.RIGHT * _player_size.x)
)
draw_dashed_line(pos + line_from, pos + line_to, color)
draw_dashed_line(pos + line_from / 2, pos + line_to / 2, color)
func _draw_arrowhead(from: Vector2, to: Vector2, color: Color) -> void: