Jump forces, smoother falling, ez walljumps

The jump velocity is not calculated on a one second basis anymore.
Instead the 60hz physics ticks are
the new reference for the jump force constants.
This is to unify the calculation of velocities in the blobby class.

Walljumps are now easier.
A just pressed jump event was changed to a pressed jump event.
This means the player can walljump,
with pressing a direction while sliding down a wall and keeping jump pressed.

Falling was smoothed out with a slightly and naivly improved euler method.

Also the spring is being experimented on.
This commit is contained in:
Jakob Feldmann 2022-05-28 16:10:33 +02:00
parent 1b7b6acd09
commit 6bf50d1bab
5 changed files with 75 additions and 40 deletions

View File

@ -61,7 +61,7 @@ func calculate_grounded_velocity(
velocity_direction = -1.0 velocity_direction = -1.0
# Stopping movement # Stopping movement
if direction.x == 0.0: if is_equal_approx(direction.x, 0):
var deceleration_force = calculate_deceleration_force( var deceleration_force = calculate_deceleration_force(
_gravity, mass, delta _gravity, mass, delta
) )
@ -147,10 +147,10 @@ func is_touching_wall_completely() -> bool:
# TODO Player gets stuck to a wall easily # TODO Player gets stuck to a wall easily
# Attached to wall state is in the PlayerStateMachine
func is_correct_walljump_input(direction: Vector2) -> bool: func is_correct_walljump_input(direction: Vector2) -> bool:
return ( return (
is_touching_wall_completely() Input.is_action_pressed("jump")
&& Input.is_action_just_pressed("jump")
&& abs(direction.x + wall_touch_direction) < 1 && abs(direction.x + wall_touch_direction) < 1
&& abs(direction.x + wall_touch_direction) >= 0 && abs(direction.x + wall_touch_direction) >= 0
) )
@ -190,17 +190,13 @@ func calculate_jump_velocity(
) )
linear_velocity.y = ( linear_velocity.y = (
((acceleration_force[state].y + additive_jump_force) / mass) ((acceleration_force[state].y + additive_jump_force) / mass)
* delta
* -1 * -1
) )
# TODO Das eskaliert ab und an komplett
if walljumping && !is_on_floor():
# The faster you are moving up the farther the walljump goes
linear_velocity.y = (acceleration_force["walljump"].y / mass) * -1
linear_velocity.x += acceleration_force["walljump"].x * direction.x
if !Input.is_action_pressed("jump"): if !Input.is_action_pressed("jump"):
# TODO This is so good not gonna lie # TODO This is so good not gonna lie
# Smooth transition from jumping to falling
if velocity.y > _gravity * delta * 10: if velocity.y > _gravity * delta * 10:
linear_velocity.y += _gravity * delta * 10 linear_velocity.y += _gravity * delta * 10
else: else:
@ -213,11 +209,15 @@ func calculate_jump_velocity(
linear_velocity.y += _gravity * delta linear_velocity.y += _gravity * delta
# TODO Dis shizzle buggy # TODO Dis shizzle buggy
if velocity.x == 0: if is_equal_approx(velocity.x, 0):
linear_velocity.x += inair_velocity * direction.x linear_velocity.x += inair_velocity * direction.x
if is_correct_airstrafe_input() && !walljumping: if is_correct_airstrafe_input() && !walljumping:
linear_velocity.x += (direction.x * acceleration_force["air_strafe"].x) linear_velocity.x += (
direction.x
* acceleration_force["air_strafe"].x
* delta
)
air_strafe_charges -= 1 air_strafe_charges -= 1
return linear_velocity return linear_velocity
@ -229,16 +229,24 @@ func calculate_fall_velocity(
linear_velocity: Vector2, delta: float, direction: Vector2 linear_velocity: Vector2, delta: float, direction: Vector2
) -> Vector2: ) -> Vector2:
if velocity.y < max_velocity["fall"]: if velocity.y < max_velocity["fall"]:
linear_velocity.y += _gravity * delta # linear_velocity.y += _gravity * delta
# Better explicit euler step
var step1vel = linear_velocity.y + _gravity * 0.5 * delta
var step2vel = step1vel + _gravity * 0.5 * delta
linear_velocity.y = step2vel
else: else:
linear_velocity.y = max_velocity["fall"] linear_velocity.y = max_velocity["fall"]
if velocity.x == 0: if is_equal_approx(velocity.x, 0):
# TODO this is weird # TODO this is weird
linear_velocity.x += inair_velocity * direction.x linear_velocity.x += inair_velocity * direction.x
if Input.is_action_just_pressed("jump"): if Input.is_action_just_pressed("jump"):
jump_buffer_filled = true jump_buffer_filled = true
if is_correct_airstrafe_input(): if is_correct_airstrafe_input():
linear_velocity.x += (direction.x * acceleration_force["air_strafe"].x) linear_velocity.x += (
direction.x
* acceleration_force["air_strafe"].x
* delta
)
air_strafe_charges -= 1 air_strafe_charges -= 1
return linear_velocity return linear_velocity
@ -248,14 +256,31 @@ func calculate_wallslide_velocity(
) -> Vector2: ) -> Vector2:
# Walljump mechanics # Walljump mechanics
if is_correct_walljump_input(direction): if is_correct_walljump_input(direction):
print("should walljump")
# TODO This +0.01 indicates a larger problem with division through possible 0 values!! # TODO This +0.01 indicates a larger problem with division through possible 0 values!!
var multiplicator = max(min(1, 1000 / (velocity.y + 0.01)), 0.9) var multiplicator = max(
min(
1,
(
acceleration_force["walljump"].y
/ (((velocity.y / delta) / mass) + 0.01)
)
),
0.7
)
print_debug(multiplicator)
linear_velocity.y += ( linear_velocity.y += (
(acceleration_force["walljump"].y / mass) (acceleration_force["walljump"].y / mass)
* -1 * -1
* delta
* multiplicator * multiplicator
) )
linear_velocity.x += acceleration_force["walljump"].x * direction.x linear_velocity.x += (
acceleration_force["walljump"].x
* delta
* direction.x
)
print_debug(linear_velocity)
else: else:
linear_velocity.y += _gravity * delta * 0.4 linear_velocity.y += _gravity * delta * 0.4
# linear_velocity.x += inair_velocity * direction.x # linear_velocity.x += inair_velocity * direction.x

View File

@ -16,13 +16,14 @@ var velocity_jump_boost_ratio := 0.1967
var init_acceleration_force := { var init_acceleration_force := {
"idle_walk": 4181, "idle_run": 5765, "walk_run": 1000 "idle_walk": 4181, "idle_run": 5765, "walk_run": 1000
} }
# Oriented around deltas of 0.0166666...s
# newtonmeters is the unit # newtonmeters is the unit
var acceleration_force := { var acceleration_force := {
"walk": Vector2(2000, 1800), "walk": Vector2(2000, 108000),
"idle": Vector2(2000, 1800), "idle": Vector2(2000, 108000),
"run": Vector2(2000, 1800), "run": Vector2(2000, 108000),
"walljump": Vector2(130, 1800), "walljump": Vector2(7800, 108000),
"air_strafe": Vector2(60, 0) "air_strafe": Vector2(4800, 0)
} }
var _gravity: float = PhysicsConst.gravity var _gravity: float = PhysicsConst.gravity
# Kilograms # Kilograms

View File

@ -98,7 +98,7 @@ func get_horizontal_direction() -> Vector2:
# Determines which state should be active at the moment # Determines which state should be active at the moment
func _get_transition(delta): func _get_transition(_delta):
parent.get_node("StateLabel").text = ( parent.get_node("StateLabel").text = (
self.state self.state
+ " x vel:" + " x vel:"

View File

@ -2,36 +2,43 @@ extends Node2D
const PhysicsFunc = preload("res://src/Utilities/Physic/PhysicsFunc.gd") const PhysicsFunc = preload("res://src/Utilities/Physic/PhysicsFunc.gd")
const PhysicsConst = preload("res://src/Utilities/Physic/PhysicsConst.gd") const PhysicsConst = preload("res://src/Utilities/Physic/PhysicsConst.gd")
# Declare member variables here. Examples:
# var a: int = 2
# var b: Strin = "text"
var mass = 1 var mass = 1
var spring_k = -500 var spring_k = -1000
var start_y = 0 var start_y = 0
var y_velocity = 0 var y_velocity = 0
var friction = 0.91 var friction = 0.91
var stored_incoming_velocity = 0 var stored_incoming_velocity = 0
var coupled_body = null
var shock_ready = true
# Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
start_y = self.position.y start_y = self.position.y
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if !_body_contact():
_store_incoming_velocity()
shock_ready = true
if _body_contact() && shock_ready:
_Kinematic_Body_on_Spring()
shock_ready = false
var spring_force = spring_k * (self.position.y - self.start_y) var spring_force = spring_k * (self.position.y - self.start_y)
var weight_force = PhysicsConst.gravity * mass var total_mass = mass
if coupled_body != null:
total_mass = mass + coupled_body.mass
var weight_force = total_mass * PhysicsConst.gravity
var result_force = weight_force + spring_force var result_force = weight_force + spring_force
y_velocity += PhysicsFunc.convert_force_to_velocity( y_velocity += PhysicsFunc.convert_force_to_velocity(
result_force, mass, delta result_force, total_mass, delta
) )
y_velocity *= friction y_velocity *= friction
self.position.y += y_velocity * delta self.position.y += y_velocity * delta
if !_if_do_bounce():
_store_incoming_velocity()
# TODO this works against the physics process # TODO this works against the physics process
@ -39,27 +46,27 @@ func _store_incoming_velocity():
var areas: Array = $EnteringVelocityDetector.get_overlapping_areas() var areas: Array = $EnteringVelocityDetector.get_overlapping_areas()
for i in range(0, areas.size()): for i in range(0, areas.size()):
if areas[i].name == "BlobbySkin": if areas[i].name == "BlobbySkin":
print_debug(stored_incoming_velocity)
if areas[i].get_parent().velocity.y != 0: if areas[i].get_parent().velocity.y != 0:
stored_incoming_velocity = areas[i].get_parent().velocity.y stored_incoming_velocity = areas[i].get_parent().velocity.y
func _if_do_bounce() -> bool: func _body_contact() -> bool:
var areas: Array = $SpringSkin.get_overlapping_areas() var areas: Array = $SpringSkin.get_overlapping_areas()
for i in range(0, areas.size()): for i in range(0, areas.size()):
if areas[i].name == "BlobbySkin": if areas[i].name == "BlobbySkin":
_Kinematic_Body_on_Spring(areas[i]) coupled_body = areas[i].get_parent()
return true return true
coupled_body = null
return false return false
func _Kinematic_Body_on_Spring(area: Area2D) -> void: func _Kinematic_Body_on_Spring() -> void:
var area_parent = area.get_parent()
var a_velocity = stored_incoming_velocity var a_velocity = stored_incoming_velocity
var a_mass = area_parent.mass var a_mass = coupled_body.mass
var b_velocity = y_velocity var b_velocity = y_velocity
var b_mass = mass var b_mass = mass
y_velocity += PhysicsFunc.complete_unelastic_shock( y_velocity += PhysicsFunc.complete_unelastic_shock(
a_velocity, b_velocity, a_mass, b_mass a_velocity, b_velocity, a_mass, b_mass
) )
stored_incoming_velocity = area_parent.velocity.y coupled_body.velocity.y = y_velocity
stored_incoming_velocity = 0

View File

@ -4,13 +4,13 @@
[ext_resource path="res://assets/environment/blocks/Basic stone block.png" type="Texture" id=2] [ext_resource path="res://assets/environment/blocks/Basic stone block.png" type="Texture" id=2]
[sub_resource type="RectangleShape2D" id=2] [sub_resource type="RectangleShape2D" id=2]
extents = Vector2( 11.4526, 1.7975 ) extents = Vector2( 11.4526, 1.75208 )
[sub_resource type="RectangleShape2D" id=1] [sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 11.9386, 1.57982 ) extents = Vector2( 11.9386, 1.57982 )
[sub_resource type="RectangleShape2D" id=3] [sub_resource type="RectangleShape2D" id=3]
extents = Vector2( 11.4, 1.42384 ) extents = Vector2( 11.4, 0.878017 )
[node name="Spring" type="Node2D"] [node name="Spring" type="Node2D"]
script = ExtResource( 1 ) script = ExtResource( 1 )
@ -24,6 +24,7 @@ collision_layer = 32
collision_mask = 3 collision_mask = 3
[node name="CollisionShape2D" type="CollisionShape2D" parent="SpringSkin"] [node name="CollisionShape2D" type="CollisionShape2D" parent="SpringSkin"]
position = Vector2( 0, -0.25779 )
shape = SubResource( 2 ) shape = SubResource( 2 )
[node name="SpringBody" type="KinematicBody2D" parent="."] [node name="SpringBody" type="KinematicBody2D" parent="."]
@ -39,4 +40,5 @@ collision_layer = 32
collision_mask = 41 collision_mask = 41
[node name="CollisionShape2D" type="CollisionShape2D" parent="EnteringVelocityDetector"] [node name="CollisionShape2D" type="CollisionShape2D" parent="EnteringVelocityDetector"]
position = Vector2( 0, 0.629961 )
shape = SubResource( 3 ) shape = SubResource( 3 )