stair stepping !
This commit is contained in:
parent
14d2399163
commit
a02c118ced
@ -85,6 +85,8 @@ func _physics_process(delta: float) -> void:
|
|||||||
velocity.x = move_toward(velocity.x, 0, SPEED)
|
velocity.x = move_toward(velocity.x, 0, SPEED)
|
||||||
velocity.z = move_toward(velocity.z, 0, SPEED)
|
velocity.z = move_toward(velocity.z, 0, SPEED)
|
||||||
|
|
||||||
|
call("stair_step_up", direction)
|
||||||
|
|
||||||
if move_and_slide() and is_on_floor():
|
if move_and_slide() and is_on_floor():
|
||||||
for idx in range(get_slide_collision_count()):
|
for idx in range(get_slide_collision_count()):
|
||||||
var collision := get_slide_collision(idx)
|
var collision := get_slide_collision(idx)
|
||||||
@ -94,6 +96,8 @@ func _physics_process(delta: float) -> void:
|
|||||||
global_position = spawn_point.global_position
|
global_position = spawn_point.global_position
|
||||||
reset_physics_interpolation()
|
reset_physics_interpolation()
|
||||||
|
|
||||||
|
call("stair_step_down")
|
||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "call_local", "reliable")
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
func hold_thing() -> void:
|
func hold_thing() -> void:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=12 format=3 uid="uid://cs8c570bxh6u"]
|
[gd_scene load_steps=12 format=3 uid="uid://cs8c570bxh6u"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/ingame/player.gd" id="1_isrmf"]
|
[ext_resource type="Script" path="res://src/lib/player_character.gd" id="1_sba4x"]
|
||||||
[ext_resource type="PackedScene" uid="uid://tdsbo3e5ic86" path="res://src/ingame/water_bomb.tscn" id="2_naek4"]
|
[ext_resource type="PackedScene" uid="uid://tdsbo3e5ic86" path="res://src/ingame/water_bomb.tscn" id="2_naek4"]
|
||||||
[ext_resource type="AudioStream" uid="uid://3dlhs18w1fa2" path="res://assets/sfx/boom.wav" id="3_u2hxa"]
|
[ext_resource type="AudioStream" uid="uid://3dlhs18w1fa2" path="res://assets/sfx/boom.wav" id="3_u2hxa"]
|
||||||
[ext_resource type="Shader" path="res://scenes/interactivity_outline.gdshader" id="4_a2qfj"]
|
[ext_resource type="Shader" path="res://scenes/interactivity_outline.gdshader" id="4_a2qfj"]
|
||||||
@ -49,7 +49,7 @@ roughness = 0.4
|
|||||||
|
|
||||||
[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("_projectile_holder", "_projectile_point", "_camera_pivot", "_camera", "_line_of_sight", "_shot_sound")]
|
[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("_projectile_holder", "_projectile_point", "_camera_pivot", "_camera", "_line_of_sight", "_shot_sound")]
|
||||||
collision_layer = 2
|
collision_layer = 2
|
||||||
script = ExtResource("1_isrmf")
|
script = ExtResource("1_sba4x")
|
||||||
_projectile_scene = ExtResource("2_naek4")
|
_projectile_scene = ExtResource("2_naek4")
|
||||||
_projectile_holder = NodePath("ProjectileHolder")
|
_projectile_holder = NodePath("ProjectileHolder")
|
||||||
_projectile_point = NodePath("ProjectilePoint")
|
_projectile_point = NodePath("ProjectilePoint")
|
||||||
|
134
src/lib/player_character.gd
Normal file
134
src/lib/player_character.gd
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
class_name StairStepper extends Player
|
||||||
|
## Credits:
|
||||||
|
# Special thanks to Majikayo Games for original solution to stair_step_down!
|
||||||
|
# (https://youtu.be/-WjM1uksPIk)
|
||||||
|
#
|
||||||
|
# Special thanks to Myria666 for their paper on Quake movement mechanics (used for stair_step_up)!
|
||||||
|
# (https://github.com/myria666/qMovementDoc)
|
||||||
|
#
|
||||||
|
# Special thanks to Andicraft for their help with implementation stair_step_up!
|
||||||
|
# (https://github.com/Andicraft)
|
||||||
|
|
||||||
|
## Notes:
|
||||||
|
# 0. All shape colliders are supported. Although, I would recommend Capsule colliders for enemies
|
||||||
|
# as it works better with the Navigation Meshes. Its up to you what shape you want to use
|
||||||
|
# for players.
|
||||||
|
#
|
||||||
|
# 1. To adjust the step-up/down height, just change the MAX_STEP_UP/MAX_STEP_DOWN values below.
|
||||||
|
#
|
||||||
|
# 2. This uses Jolt Physics as the default Godot Physics has a few bugs:
|
||||||
|
# 1: Small gaps that you should be able to fit through both ways will block you in Godot Physics.
|
||||||
|
# You can see this demonstrated with the floating boxes in front of the big stairs.
|
||||||
|
# 2: Walking into some objects may push the player downward by a small amount which causes
|
||||||
|
# jittering and causes the floor to be detected as a step.
|
||||||
|
# TLDR: This still works with default Godot Physics, although it feels a lot better in Jolt Physics.
|
||||||
|
|
||||||
|
@export var MAX_STEP_UP := 0.5 # Maximum height in meters the player can step up.
|
||||||
|
@export var MAX_STEP_DOWN := -0.5 # Maximum height in meters the player can step down.
|
||||||
|
|
||||||
|
var was_grounded: bool = true
|
||||||
|
var is_grounded: bool = true
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
was_grounded = is_grounded
|
||||||
|
is_grounded = is_on_floor()
|
||||||
|
super._physics_process(delta)
|
||||||
|
|
||||||
|
|
||||||
|
# Function: Handle walking down stairs
|
||||||
|
func stair_step_down():
|
||||||
|
if is_on_floor():
|
||||||
|
return
|
||||||
|
|
||||||
|
# If we're falling from a step
|
||||||
|
if velocity.y <= 0 and was_grounded:
|
||||||
|
# Initialize body test variables
|
||||||
|
var body_test_result = PhysicsTestMotionResult3D.new()
|
||||||
|
var body_test_params = PhysicsTestMotionParameters3D.new()
|
||||||
|
|
||||||
|
body_test_params.from = self.global_transform ## We get the player's current global_transform
|
||||||
|
body_test_params.motion = Vector3(0, MAX_STEP_DOWN, 0) ## We project the player downward
|
||||||
|
|
||||||
|
if PhysicsServer3D.body_test_motion(self.get_rid(), body_test_params, body_test_result):
|
||||||
|
# Enters if a collision is detected by body_test_motion
|
||||||
|
# Get distance to step and move player downward by that much
|
||||||
|
position.y += body_test_result.get_travel().y
|
||||||
|
apply_floor_snap()
|
||||||
|
is_grounded = true
|
||||||
|
|
||||||
|
|
||||||
|
# Function: Handle walking up stairs
|
||||||
|
func stair_step_up(wish_dir: Vector3):
|
||||||
|
if wish_dir == Vector3.ZERO:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 0. Initialize testing variables
|
||||||
|
var body_test_params = PhysicsTestMotionParameters3D.new()
|
||||||
|
var body_test_result = PhysicsTestMotionResult3D.new()
|
||||||
|
|
||||||
|
var test_transform = global_transform ## Storing current global_transform for testing
|
||||||
|
var distance = wish_dir * 0.1 ## Distance forward we want to check
|
||||||
|
body_test_params.from = self.global_transform ## Self as origin point
|
||||||
|
body_test_params.motion = distance ## Go forward by current distance
|
||||||
|
|
||||||
|
# Pre-check: Are we colliding?
|
||||||
|
if !PhysicsServer3D.body_test_motion(self.get_rid(), body_test_params, body_test_result):
|
||||||
|
## If we don't collide, return
|
||||||
|
return
|
||||||
|
|
||||||
|
# 1. Move test_transform to collision location
|
||||||
|
var remainder = body_test_result.get_remainder() ## Get remainder from collision
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel()) ## Move test_transform by distance traveled before collision
|
||||||
|
|
||||||
|
# 2. Move test_transform up to ceiling (if any)
|
||||||
|
var step_up = MAX_STEP_UP * Vector3.UP
|
||||||
|
body_test_params.from = test_transform
|
||||||
|
body_test_params.motion = step_up
|
||||||
|
PhysicsServer3D.body_test_motion(self.get_rid(), body_test_params, body_test_result)
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel())
|
||||||
|
|
||||||
|
# 3. Move test_transform forward by remaining distance
|
||||||
|
body_test_params.from = test_transform
|
||||||
|
body_test_params.motion = remainder
|
||||||
|
PhysicsServer3D.body_test_motion(self.get_rid(), body_test_params, body_test_result)
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel())
|
||||||
|
|
||||||
|
# 3.5 Project remaining along wall normal (if any)
|
||||||
|
## So you can walk into wall and up a step
|
||||||
|
if body_test_result.get_collision_count() != 0:
|
||||||
|
remainder = body_test_result.get_remainder().length()
|
||||||
|
|
||||||
|
### Uh, there may be a better way to calculate this in Godot.
|
||||||
|
var wall_normal = body_test_result.get_collision_normal()
|
||||||
|
var dot_div_mag = wish_dir.dot(wall_normal) / (wall_normal * wall_normal).length()
|
||||||
|
var projected_vector = (wish_dir - dot_div_mag * wall_normal).normalized()
|
||||||
|
|
||||||
|
body_test_params.from = test_transform
|
||||||
|
body_test_params.motion = remainder * projected_vector
|
||||||
|
PhysicsServer3D.body_test_motion(self.get_rid(), body_test_params, body_test_result)
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel())
|
||||||
|
|
||||||
|
# 4. Move test_transform down onto step
|
||||||
|
body_test_params.from = test_transform
|
||||||
|
body_test_params.motion = MAX_STEP_UP * -Vector3.UP
|
||||||
|
|
||||||
|
# Return if no collision
|
||||||
|
if !PhysicsServer3D.body_test_motion(self.get_rid(), body_test_params, body_test_result):
|
||||||
|
return
|
||||||
|
|
||||||
|
test_transform = test_transform.translated(body_test_result.get_travel())
|
||||||
|
|
||||||
|
# 5. Check floor normal for un-walkable slope
|
||||||
|
var surface_normal = body_test_result.get_collision_normal()
|
||||||
|
var temp_floor_max_angle = floor_max_angle + deg_to_rad(20)
|
||||||
|
if (snappedf(surface_normal.angle_to(Vector3.UP), 0.001) > temp_floor_max_angle):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# 6. Move player up
|
||||||
|
var global_pos = global_position
|
||||||
|
var step_up_dist = test_transform.origin.y - global_pos.y
|
||||||
|
|
||||||
|
global_pos.y = test_transform.origin.y
|
||||||
|
global_position = global_pos
|
Loading…
Reference in New Issue
Block a user