implement slope sliding
This commit is contained in:
@@ -12,7 +12,7 @@ size = Vector2(18, 26)
|
||||
|
||||
[node name="Player" type="CharacterBody2D" node_paths=PackedStringArray("_trajectory")]
|
||||
collision_layer = 16
|
||||
floor_max_angle = 0.767945
|
||||
floor_max_angle = 1.55334
|
||||
floor_snap_length = 0.0
|
||||
script = ExtResource("1_g2els")
|
||||
_trajectory = NodePath("Trajectory")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=138 format=3 uid="uid://cfvb33kf48sga"]
|
||||
[gd_scene load_steps=140 format=3 uid="uid://cfvb33kf48sga"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://db7d5pwp4gds" path="res://scenes/player.tscn" id="1_bl13t"]
|
||||
[ext_resource type="Texture2D" uid="uid://j3xt1tbjcu2r" path="res://assets/textures/reference/jumpking_0.png" id="1_iyx0m"]
|
||||
@@ -315,6 +315,12 @@ size = Vector2(104, 50)
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_5205d"]
|
||||
size = Vector2(56, 150)
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_hj8ru"]
|
||||
size = Vector2(48, 168)
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_wf13j"]
|
||||
size = Vector2(47, 32)
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_32c8b"]
|
||||
size = Vector2(78.489, 37.4766)
|
||||
|
||||
@@ -928,13 +934,21 @@ shape = SubResource("RectangleShape2D_2npwi")
|
||||
position = Vector2(-212, -3161)
|
||||
shape = SubResource("RectangleShape2D_5205d")
|
||||
|
||||
[node name="CollisionShape2D96" type="CollisionShape2D" parent="Geometry"]
|
||||
position = Vector2(-64, -3456)
|
||||
shape = SubResource("RectangleShape2D_hj8ru")
|
||||
|
||||
[node name="CollisionShape2D97" type="CollisionShape2D" parent="Geometry"]
|
||||
position = Vector2(-64.5, -3300)
|
||||
shape = SubResource("RectangleShape2D_wf13j")
|
||||
|
||||
[node name="CollisionShape2D95" type="CollisionShape2D" parent="Geometry"]
|
||||
position = Vector2(-177, -3107.5)
|
||||
rotation = 0.785397
|
||||
shape = SubResource("RectangleShape2D_32c8b")
|
||||
|
||||
[node name="Player" parent="." instance=ExtResource("1_bl13t")]
|
||||
position = Vector2(240, 328)
|
||||
position = Vector2(271, -2253)
|
||||
|
||||
[node name="MainCamera" type="Camera2D" parent="."]
|
||||
position = Vector2(240, 180)
|
||||
@@ -1053,8 +1067,9 @@ _steps = 79
|
||||
metadata/_custom_type_script = "uid://ceyu5der8j8gq"
|
||||
|
||||
[node name="Trajectory16" type="Marker2D" parent="Trajectories"]
|
||||
position = Vector2(464, -2296)
|
||||
position = Vector2(271, -2253)
|
||||
script = ExtResource("4_74lek")
|
||||
flip = true
|
||||
_steps = 79
|
||||
_steps = 104
|
||||
_jump = false
|
||||
metadata/_custom_type_script = "uid://ceyu5der8j8gq"
|
||||
|
||||
@@ -23,6 +23,7 @@ var _is_charging_jump: bool = false
|
||||
var _jump_charge_frames: float = 0
|
||||
var _charge_strength: float = 0
|
||||
var _jump_released: bool = false
|
||||
var _floor_angle: float = 0
|
||||
|
||||
var _freemove_enabled: bool = false
|
||||
|
||||
@@ -33,6 +34,7 @@ static func process_movement(
|
||||
new_velocity: Vector2,
|
||||
delta: float,
|
||||
on_floor: bool,
|
||||
floor_angle: float,
|
||||
direction: float,
|
||||
is_charging_jump: bool,
|
||||
charge_strength: float,
|
||||
@@ -45,15 +47,19 @@ static func process_movement(
|
||||
) -> Vector2:
|
||||
# falling
|
||||
new_velocity.y = (
|
||||
move_toward(new_velocity.y, fall_speed, delta * fall_acceleration)
|
||||
if not on_floor
|
||||
else 0.0
|
||||
0.0
|
||||
if on_floor and is_zero_approx(floor_angle)
|
||||
else move_toward(new_velocity.y, fall_speed, delta * fall_acceleration)
|
||||
)
|
||||
|
||||
# moving
|
||||
if on_floor:
|
||||
if on_floor and is_zero_approx(floor_angle):
|
||||
new_velocity.x = direction * move_speed if not is_charging_jump else 0.0
|
||||
|
||||
# sliding
|
||||
if on_floor and not is_zero_approx(floor_angle):
|
||||
new_velocity.x = new_velocity.y * signf(floor_angle)
|
||||
|
||||
# jump charge release
|
||||
if jump_released:
|
||||
new_velocity.y = -jump_force * charge_strength
|
||||
@@ -65,16 +71,21 @@ static func process_movement(
|
||||
static func process_collision(
|
||||
prev_velocity: Vector2,
|
||||
new_velocity: Vector2,
|
||||
on_floor: bool,
|
||||
on_ceiling: bool,
|
||||
on_wall: bool,
|
||||
hit_floor: bool,
|
||||
hit_slope: bool,
|
||||
hit_ceiling: bool,
|
||||
hit_wall: bool,
|
||||
floor_angle: float,
|
||||
wall_bounce_velocity_loss: float,
|
||||
) -> Vector2:
|
||||
if on_floor:
|
||||
if hit_floor:
|
||||
new_velocity = Vector2.ZERO
|
||||
if on_ceiling:
|
||||
if hit_slope:
|
||||
new_velocity.x = new_velocity.y * signf(floor_angle)
|
||||
if hit_ceiling:
|
||||
new_velocity.y = 0
|
||||
new_velocity.x *= wall_bounce_velocity_loss
|
||||
if on_wall:
|
||||
if hit_wall:
|
||||
new_velocity.x = -prev_velocity.x * wall_bounce_velocity_loss
|
||||
return new_velocity
|
||||
|
||||
@@ -104,7 +115,7 @@ func _physics_process(delta: float) -> void:
|
||||
move_and_slide()
|
||||
return
|
||||
|
||||
var is_on_floor_prev := is_on_floor()
|
||||
var is_on_floor_prev := is_on_floor_only()
|
||||
var is_on_ceiling_prev := is_on_ceiling()
|
||||
var is_on_wall_prev := is_on_wall()
|
||||
|
||||
@@ -114,6 +125,7 @@ func _physics_process(delta: float) -> void:
|
||||
velocity,
|
||||
delta,
|
||||
is_on_floor_prev,
|
||||
_floor_angle,
|
||||
_direction,
|
||||
_is_charging_jump,
|
||||
_charge_strength,
|
||||
@@ -132,9 +144,15 @@ func _physics_process(delta: float) -> void:
|
||||
move_and_slide()
|
||||
|
||||
# collisions
|
||||
var on_floor := not is_on_floor_prev and is_on_floor()
|
||||
var on_ceiling := not is_on_ceiling_prev and is_on_ceiling()
|
||||
var on_wall := (
|
||||
if is_on_floor() and not is_zero_approx(_floor_angle):
|
||||
velocity = new_velocity
|
||||
var is_on_floor_changed := not is_on_floor_prev and is_on_floor()
|
||||
if is_on_floor_changed and is_on_floor():
|
||||
_floor_angle = -get_floor_normal().angle_to(Vector2.UP)
|
||||
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)
|
||||
var hit_ceiling := not is_on_ceiling_prev and is_on_ceiling()
|
||||
var hit_wall := (
|
||||
not is_on_wall_prev
|
||||
and is_on_wall()
|
||||
and not is_on_floor()
|
||||
@@ -143,17 +161,19 @@ func _physics_process(delta: float) -> void:
|
||||
velocity = process_collision(
|
||||
new_velocity,
|
||||
velocity,
|
||||
on_floor,
|
||||
on_ceiling,
|
||||
on_wall,
|
||||
hit_floor,
|
||||
hit_slope,
|
||||
hit_ceiling,
|
||||
hit_wall,
|
||||
_floor_angle,
|
||||
_wall_bounce_velocity_loss,
|
||||
)
|
||||
if on_floor:
|
||||
if hit_floor:
|
||||
_trajectory.visible = false
|
||||
collided.emit(SIDE_BOTTOM, new_velocity)
|
||||
if on_ceiling:
|
||||
if hit_ceiling:
|
||||
collided.emit(SIDE_TOP, new_velocity)
|
||||
if on_wall:
|
||||
if hit_wall:
|
||||
collided.emit(SIDE_LEFT if velocity.x > 0 else SIDE_RIGHT, new_velocity)
|
||||
|
||||
queue_redraw()
|
||||
@@ -170,7 +190,7 @@ func _physics_process(delta: float) -> void:
|
||||
Debugger.text("is_on_floor_only", is_on_floor_only())
|
||||
Debugger.text("is_on_wall", is_on_wall())
|
||||
Debugger.text("is_on_wall_only", is_on_wall_only())
|
||||
Debugger.text("get_slide_collision_count", get_slide_collision_count())
|
||||
Debugger.text("floor_angle", _floor_angle)
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
@@ -180,6 +200,7 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
_saved_state = global_position
|
||||
if event.is_action_pressed("load_state"):
|
||||
global_position = _saved_state
|
||||
velocity = Vector2.ZERO
|
||||
if event.is_action_pressed("toggle_freemove"):
|
||||
_freemove_enabled = not _freemove_enabled
|
||||
|
||||
@@ -188,7 +209,11 @@ func _gather_input(delta: float, on_floor: bool) -> void:
|
||||
_direction = signf(Input.get_axis("move_left", "move_right"))
|
||||
|
||||
# jump charge start
|
||||
if Input.is_action_just_pressed("jump") and on_floor:
|
||||
if (
|
||||
Input.is_action_just_pressed("jump")
|
||||
and on_floor
|
||||
and is_zero_approx(_floor_angle)
|
||||
):
|
||||
_is_charging_jump = true
|
||||
_jump_charge_frames = 0
|
||||
|
||||
@@ -208,6 +233,7 @@ func _gather_input(delta: float, on_floor: bool) -> void:
|
||||
_jump_released = (
|
||||
_is_charging_jump
|
||||
and on_floor
|
||||
and is_zero_approx(_floor_angle)
|
||||
and (
|
||||
Input.is_action_just_released("jump")
|
||||
or _jump_charge_frames >= _jump_full_charge_frames
|
||||
|
||||
@@ -197,10 +197,11 @@ func _draw() -> void:
|
||||
var velocity: Vector2
|
||||
var is_on_floor: bool = false
|
||||
var direction: float = -1.0 if flip else 1.0
|
||||
var floor_angle: float = 0
|
||||
|
||||
for i in range(_steps):
|
||||
pos += velocity * delta
|
||||
if is_on_floor and _stop_on_landing:
|
||||
if is_on_floor and is_zero_approx(floor_angle) and _stop_on_landing:
|
||||
break
|
||||
|
||||
velocity = (
|
||||
@@ -209,10 +210,11 @@ func _draw() -> void:
|
||||
velocity,
|
||||
delta,
|
||||
is_on_floor,
|
||||
floor_angle,
|
||||
direction,
|
||||
false,
|
||||
charge_strength,
|
||||
i == 0,
|
||||
i == 0 and _jump,
|
||||
_move_speed,
|
||||
_jump_speed,
|
||||
_jump_force,
|
||||
@@ -226,40 +228,50 @@ func _draw() -> void:
|
||||
if not is_equal_approx(motion_proportion, 1.0):
|
||||
var motion := (pos - pos_prev) * motion_proportion
|
||||
pos = pos_prev + motion
|
||||
var is_hitting_floor: bool = false
|
||||
var is_hitting_ceiling: bool = false
|
||||
var hit_slope: bool = false
|
||||
var hit_floor: bool = false
|
||||
var hit_ceiling: bool = false
|
||||
|
||||
# hitting floor
|
||||
if velocity.y > 0 and not is_on_floor:
|
||||
if velocity.y >= 0:
|
||||
var result := _shapecast(pos + Vector2.UP, pos + Vector2.DOWN)
|
||||
if result:
|
||||
is_hitting_floor = true
|
||||
var raycast_result := _raycast(
|
||||
pos + Vector2.UP * 10, pos + Vector2.DOWN * 10
|
||||
)
|
||||
if raycast_result:
|
||||
var normal := raycast_result["normal"] as Vector2
|
||||
floor_angle = -normal.angle_to(Vector2.UP)
|
||||
hit_floor = is_zero_approx(floor_angle)
|
||||
hit_slope = not is_zero_approx(floor_angle)
|
||||
else:
|
||||
is_on_floor = false
|
||||
# hitting ceiling
|
||||
if velocity.y < 0:
|
||||
var raycast_result := _shapecast(
|
||||
var result := _shapecast(
|
||||
pos - Vector2(0, _player_size.y) + Vector2.DOWN,
|
||||
pos - Vector2(0, _player_size.y) + Vector2.UP
|
||||
)
|
||||
if raycast_result:
|
||||
is_hitting_ceiling = true
|
||||
if result:
|
||||
hit_ceiling = true
|
||||
|
||||
var is_hitting_wall: bool = (
|
||||
not is_hitting_floor and not is_hitting_ceiling
|
||||
)
|
||||
var hit_wall: bool = not hit_floor and not hit_slope and not hit_ceiling
|
||||
|
||||
velocity = (
|
||||
Player
|
||||
. process_collision(
|
||||
velocity,
|
||||
velocity,
|
||||
is_hitting_floor,
|
||||
is_hitting_ceiling,
|
||||
is_hitting_wall,
|
||||
hit_floor,
|
||||
hit_slope,
|
||||
hit_ceiling,
|
||||
hit_wall,
|
||||
floor_angle,
|
||||
_wall_bounce_velocity_loss,
|
||||
)
|
||||
)
|
||||
|
||||
if is_hitting_floor:
|
||||
if hit_floor or hit_slope:
|
||||
is_on_floor = true
|
||||
_draw_collision_hit(pos, SIDE_BOTTOM, _floor_hit_color)
|
||||
draw_dashed_line(
|
||||
@@ -267,14 +279,13 @@ func _draw() -> void:
|
||||
pos + Vector2.RIGHT * _player_size.x / 2,
|
||||
_floor_hit_color
|
||||
)
|
||||
if is_hitting_ceiling:
|
||||
velocity.y = 0
|
||||
if hit_ceiling:
|
||||
draw_rect(
|
||||
Rect2(_get_hitbox_pos(pos), _player_size),
|
||||
Color(_ceiling_hit_color, 0.25)
|
||||
)
|
||||
_draw_collision_hit(pos, SIDE_TOP, _ceiling_hit_color)
|
||||
if is_hitting_wall:
|
||||
if hit_wall:
|
||||
draw_rect(
|
||||
Rect2(_get_hitbox_pos(pos), _player_size),
|
||||
Color(_wall_hit_color, 0.25)
|
||||
@@ -313,6 +324,25 @@ func _shapecast(from: Vector2, to: Vector2) -> Array[Dictionary]:
|
||||
return space_state.intersect_shape(query)
|
||||
|
||||
|
||||
func _raycast(from: Vector2, to: Vector2) -> Dictionary:
|
||||
var space_state := get_world_2d().direct_space_state
|
||||
var query_left := PhysicsRayQueryParameters2D.create(
|
||||
to_global(from) + Vector2.LEFT * _player_size.x / 2,
|
||||
to_global(to) + Vector2.LEFT * _player_size.x / 2
|
||||
)
|
||||
var result_left := space_state.intersect_ray(query_left)
|
||||
if result_left:
|
||||
return result_left
|
||||
var query_right := PhysicsRayQueryParameters2D.create(
|
||||
to_global(from) + Vector2.RIGHT * _player_size.x / 2,
|
||||
to_global(to) + Vector2.RIGHT * _player_size.x / 2
|
||||
)
|
||||
var result_right := space_state.intersect_ray(query_right)
|
||||
if result_right:
|
||||
return result_right
|
||||
return {}
|
||||
|
||||
|
||||
func _cast_motion(from: Vector2, to: Vector2) -> float:
|
||||
var space_state := get_world_2d().direct_space_state
|
||||
var query := PhysicsShapeQueryParameters2D.new()
|
||||
|
||||
Reference in New Issue
Block a user