Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added code to detect player jump movements #91

Merged
merged 1 commit into from
Mar 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions addons/godot-xr-tools/VERSIONS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# 2.4.0
- Added configuration setting for head height in player body.
- Added Function_JumpDetect_movement to detect jumping via the players body and/or arms

# 2.3.0
- Added vignette
Expand Down
37 changes: 37 additions & 0 deletions addons/godot-xr-tools/assets/PlayerBody.gd
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ extends Node
## track any movement to the PlayerBody.
##


## Signal emitted when the player jumps
signal player_jumped()


## PlayerBody enabled flag
export var enabled := true setget set_enabled

Expand Down Expand Up @@ -83,6 +88,9 @@ var ground_control_velocity := Vector2.ZERO
# Movement providers
var _movement_providers := Array()

# Jump cool-down counter
var _jump_cooldown := 0

# Collision node
onready var _collision_node: CollisionShape = $KinematicBody/CollisionShape

Expand Down Expand Up @@ -162,6 +170,10 @@ func _physics_process(delta):
set_physics_process(false)
return

# Decrement the jump cool-down on each physics update
if _jump_cooldown:
_jump_cooldown -= 1

# Update the kinematic body to be under the camera
_update_body_under_camera()

Expand All @@ -177,6 +189,7 @@ func _physics_process(delta):
# - Read and modify the player velocity
# - Read and modify the ground-control velocity
# - Perform exclusive updating of the player (bypassing other movement providers)
# - Request a jump
ground_control_velocity = Vector2.ZERO
var exclusive := false
for p in _movement_providers:
Expand All @@ -195,6 +208,30 @@ func _physics_process(delta):
var movement := kinematic_node.global_transform.origin - position_before_movement
origin_node.global_transform.origin += movement

# Request a jump
func request_jump(var skip_jump_velocity := false):
# Skip if cooling down from a previous jump
if _jump_cooldown:
return;

# Skip if not on ground
if !on_ground:
return

# Skip if the ground is too steep to jump
var current_max_slope := GroundPhysicsSettings.get_jump_max_slope(ground_physics, default_physics)
if ground_angle > current_max_slope:
return

# Perform the jump
if !skip_jump_velocity:
var current_jump_velocity := GroundPhysicsSettings.get_jump_velocity(ground_physics, default_physics)
velocity.y = current_jump_velocity * ARVRServer.world_scale

# Report the jump
emit_signal("player_jumped")
_jump_cooldown = 4

# Perform a move_and_slide on the kinematic node
func move_and_slide(var velocity: Vector3) -> Vector3:
return kinematic_node.move_and_slide(velocity, Vector3.UP, false, 4, 0.785398, push_rigid_bodies)
Expand Down
157 changes: 157 additions & 0 deletions addons/godot-xr-tools/functions/Function_JumpDetect_movement.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
tool
class_name Function_JumpDetect
extends MovementProvider


##
## Movement Provider for Player Jump Detection
##
## @desc:
## This script can detect jumping based on either the players body jumping,
## or by the player swinging their arms up.
##
## The player body jumping is detected by putting the cameras instantaneous
## Y velocity (in the tracking space) into a sliding-window averager. If the
## average Y velocity exceeds a threshold parameter then the player has
## jumped.
##
## The player arms jumping is detected by putting both controllers instantaneous
## Y velocity (in the tracking space) into a sliding-window averager. If both
## average Y velocities exceed a threshold parameter then the player has
## jumped.
##


## Movement provider order
export var order := 20

## Enable detecting of jump via body (through the camera)
export var body_jump_enable := true

## Only jump as high as the player (no ground physics)
export var body_jump_player_only := false

## Body jump detection threshold (M/S^2)
export var body_jump_threshold := 2.5

## Enable detectionm of jump via arms (through the controllers)
export var arms_jump_enable := false

## Arms jump detection threshold (M/S^2)
export var arms_jump_threshold := 10.0


# Sliding Average class
class SlidingAverage:
# Sliding window size
var _size: int

# Sum of items in the window
var _sum := 0.0

# Position
var _pos := 0

# Data window
var _data := Array()

# Constructor
func _init(var size: int):
# Set the size and fill the array
_size = size
for i in size:
_data.push_back(0.0)

# Update the average
func update(var entry: float) -> float:
# Add the new entry and subtract the old
_sum += entry
_sum -= _data[_pos]

# Store the new entry in the array and circularly advance the index
_data[_pos] = entry;
_pos = (_pos + 1) % _size

# Return the average
return _sum / _size


# Node Positions
var _camera_position := 0.0
var _controller_left_position := 0.0
var _controller_right_position := 0.0

# Node Velocities
var _camera_velocity := SlidingAverage.new(5)
var _controller_left_velocity := SlidingAverage.new(5)
var _controller_right_velocity := SlidingAverage.new(5)

# Node references
onready var _origin_node := ARVRHelpers.get_arvr_origin(self)
onready var _camera_node := ARVRHelpers.get_arvr_camera(self)
onready var _controller_left_node := ARVRHelpers.get_left_controller(self)
onready var _controller_right_node := ARVRHelpers.get_right_controller(self)


# Perform jump detection
func physics_movement(delta: float, player_body: PlayerBody):
# Handle detecting body jump
if body_jump_enable:
_detect_body_jump(delta, player_body)

# Handle detecting arms jump
if arms_jump_enable:
_detect_arms_jump(delta, player_body)


# Detect the player jumping with their body (using the headset camera)
func _detect_body_jump(delta: float, player_body: PlayerBody) -> void:
# Get the camera instantaneous velocity
var new_camera_pos := _camera_node.transform.origin.y
var camera_vel := (new_camera_pos - _camera_position) / delta
_camera_position = new_camera_pos

# Ignore zero moves (either not tracking, or no update since last physics)
if abs(camera_vel) < 0.001:
return;

# Clamp the camera instantaneous velocity to +/- 2x the jump threshold
camera_vel = clamp(camera_vel, -2.0 * body_jump_threshold, 2.0 * body_jump_threshold)

# Get the averaged velocity
camera_vel = _camera_velocity.update(camera_vel)

# Detect a jump
if camera_vel >= body_jump_threshold:
player_body.request_jump(body_jump_player_only)


# Detect the player jumping with their arms (using the controllers)
func _detect_arms_jump(delta: float, player_body: PlayerBody) -> void:
# Skip if either of the controllers is disabled
if !_controller_left_node.get_is_active() or !_controller_right_node.get_is_active():
return

# Get the controllers instantaneous velocity
var new_controller_left_pos := _controller_left_node.transform.origin.y
var new_controller_right_pos := _controller_right_node.transform.origin.y
var controller_left_vel := (new_controller_left_pos - _controller_left_position) / delta
var controller_right_vel := (new_controller_right_pos - _controller_right_position) / delta
_controller_left_position = new_controller_left_pos
_controller_right_position = new_controller_right_pos

# Ignore zero moves (either not tracking, or no update since last physics)
if abs(controller_left_vel) <= 0.001 and abs(controller_right_vel) <= 0.001:
return

# Clamp the controller instantaneous velocity to +/- 2x the jump threshold
controller_left_vel = clamp(controller_left_vel, -2.0 * arms_jump_threshold, 2.0 * arms_jump_threshold)
controller_right_vel = clamp(controller_right_vel, -2.0 * arms_jump_threshold, 2.0 * arms_jump_threshold)

# Get the averaged velocity
controller_left_vel = _controller_left_velocity.update(controller_left_vel)
controller_right_vel = _controller_right_velocity.update(controller_right_vel)

# Detect a jump
if controller_left_vel >= arms_jump_threshold and controller_right_vel >= arms_jump_threshold:
player_body.request_jump()
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=2]

[ext_resource path="res://addons/godot-xr-tools/functions/Function_JumpDetect_movement.gd" type="Script" id=1]

[node name="Function_JumpDetect_Movement" type="Node" groups=["movement_providers"]]
script = ExtResource( 1 )
arms_jump_enable = true
23 changes: 3 additions & 20 deletions addons/godot-xr-tools/functions/Function_Jump_movement.gd
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ enum Buttons {
VR_TRIGGER = 15
}

## Player jumped signal
signal player_jumped

## Movement provider order
export var order := 20

Expand All @@ -48,27 +45,13 @@ onready var _controller: ARVRController = get_parent()

# Perform jump movement
func physics_movement(delta: float, player_body: PlayerBody):
# Skip if the player isn't on the ground
if !player_body.on_ground:
return

# Skip if the jump controller isn't active
if !_controller.get_is_active():
return

# Skip if the jump button isn't pressed
if !_controller.is_button_pressed(jump_button_id):
return

# Skip if the ground is too steep to jump
var current_max_slope := GroundPhysicsSettings.get_jump_max_slope(player_body.ground_physics, player_body.default_physics)
if player_body.ground_angle > current_max_slope:
return

# Perform the jump
emit_signal("player_jumped")
var current_jump_velocity := GroundPhysicsSettings.get_jump_velocity(player_body.ground_physics, player_body.default_physics)
player_body.velocity.y = current_jump_velocity * ARVRServer.world_scale
# Request jump if the button is pressed
if _controller.is_button_pressed(jump_button_id):
player_body.request_jump()

# This method verifies the MovementProvider has a valid configuration.
func _get_configuration_warning():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@
[node name="Function_Jump_movement" type="Node" groups=["movement_providers"]]
script = ExtResource( 1 )
jump_button_id = null
controller = null