From 6bf50d1bab7863a045b3860dd9e8dee229b6233e Mon Sep 17 00:00:00 2001 From: Jakob Feldmann Date: Sat, 28 May 2022 16:10:33 +0200 Subject: [PATCH] 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. --- src/Actors/Blobby/Blobby.gd | 57 +++++++++++++++++++-------- src/Actors/Player.gd | 11 +++--- src/Actors/PlayerStateMachine.gd | 2 +- src/Contraptions/Platform/Spring.gd | 39 ++++++++++-------- src/Contraptions/Platform/Spring.tscn | 6 ++- 5 files changed, 75 insertions(+), 40 deletions(-) diff --git a/src/Actors/Blobby/Blobby.gd b/src/Actors/Blobby/Blobby.gd index 4942095..c7ec9bd 100644 --- a/src/Actors/Blobby/Blobby.gd +++ b/src/Actors/Blobby/Blobby.gd @@ -61,7 +61,7 @@ func calculate_grounded_velocity( velocity_direction = -1.0 # Stopping movement - if direction.x == 0.0: + if is_equal_approx(direction.x, 0): var deceleration_force = calculate_deceleration_force( _gravity, mass, delta ) @@ -147,10 +147,10 @@ func is_touching_wall_completely() -> bool: # TODO Player gets stuck to a wall easily +# Attached to wall state is in the PlayerStateMachine func is_correct_walljump_input(direction: Vector2) -> bool: return ( - is_touching_wall_completely() - && Input.is_action_just_pressed("jump") + Input.is_action_pressed("jump") && abs(direction.x + wall_touch_direction) < 1 && abs(direction.x + wall_touch_direction) >= 0 ) @@ -190,17 +190,13 @@ func calculate_jump_velocity( ) linear_velocity.y = ( ((acceleration_force[state].y + additive_jump_force) / mass) + * delta * -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"): # TODO This is so good not gonna lie + # Smooth transition from jumping to falling if velocity.y > _gravity * delta * 10: linear_velocity.y += _gravity * delta * 10 else: @@ -213,11 +209,15 @@ func calculate_jump_velocity( linear_velocity.y += _gravity * delta # TODO Dis shizzle buggy - if velocity.x == 0: + if is_equal_approx(velocity.x, 0): linear_velocity.x += inair_velocity * direction.x 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 return linear_velocity @@ -229,16 +229,24 @@ func calculate_fall_velocity( linear_velocity: Vector2, delta: float, direction: Vector2 ) -> Vector2: 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: linear_velocity.y = max_velocity["fall"] - if velocity.x == 0: + if is_equal_approx(velocity.x, 0): # TODO this is weird linear_velocity.x += inair_velocity * direction.x if Input.is_action_just_pressed("jump"): jump_buffer_filled = true 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 return linear_velocity @@ -248,14 +256,31 @@ func calculate_wallslide_velocity( ) -> Vector2: # Walljump mechanics if is_correct_walljump_input(direction): + print("should walljump") # 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 += ( (acceleration_force["walljump"].y / mass) * -1 + * delta * 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: linear_velocity.y += _gravity * delta * 0.4 # linear_velocity.x += inair_velocity * direction.x diff --git a/src/Actors/Player.gd b/src/Actors/Player.gd index 418d85f..8be3534 100644 --- a/src/Actors/Player.gd +++ b/src/Actors/Player.gd @@ -16,13 +16,14 @@ var velocity_jump_boost_ratio := 0.1967 var init_acceleration_force := { "idle_walk": 4181, "idle_run": 5765, "walk_run": 1000 } +# Oriented around deltas of 0.0166666...s # newtonmeters is the unit var acceleration_force := { - "walk": Vector2(2000, 1800), - "idle": Vector2(2000, 1800), - "run": Vector2(2000, 1800), - "walljump": Vector2(130, 1800), - "air_strafe": Vector2(60, 0) + "walk": Vector2(2000, 108000), + "idle": Vector2(2000, 108000), + "run": Vector2(2000, 108000), + "walljump": Vector2(7800, 108000), + "air_strafe": Vector2(4800, 0) } var _gravity: float = PhysicsConst.gravity # Kilograms diff --git a/src/Actors/PlayerStateMachine.gd b/src/Actors/PlayerStateMachine.gd index 1b93c52..b596cd8 100644 --- a/src/Actors/PlayerStateMachine.gd +++ b/src/Actors/PlayerStateMachine.gd @@ -98,7 +98,7 @@ func get_horizontal_direction() -> Vector2: # Determines which state should be active at the moment -func _get_transition(delta): +func _get_transition(_delta): parent.get_node("StateLabel").text = ( self.state + " x vel:" diff --git a/src/Contraptions/Platform/Spring.gd b/src/Contraptions/Platform/Spring.gd index 04fda9b..704008d 100644 --- a/src/Contraptions/Platform/Spring.gd +++ b/src/Contraptions/Platform/Spring.gd @@ -2,36 +2,43 @@ extends Node2D const PhysicsFunc = preload("res://src/Utilities/Physic/PhysicsFunc.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 spring_k = -500 +var spring_k = -1000 var start_y = 0 var y_velocity = 0 var friction = 0.91 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: start_y = self.position.y # Called every frame. 'delta' is the elapsed time since the previous frame. 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 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 y_velocity += PhysicsFunc.convert_force_to_velocity( - result_force, mass, delta + result_force, total_mass, delta ) y_velocity *= friction self.position.y += y_velocity * delta - if !_if_do_bounce(): - _store_incoming_velocity() # TODO this works against the physics process @@ -39,27 +46,27 @@ func _store_incoming_velocity(): var areas: Array = $EnteringVelocityDetector.get_overlapping_areas() for i in range(0, areas.size()): if areas[i].name == "BlobbySkin": - print_debug(stored_incoming_velocity) if areas[i].get_parent().velocity.y != 0: 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() for i in range(0, areas.size()): if areas[i].name == "BlobbySkin": - _Kinematic_Body_on_Spring(areas[i]) + coupled_body = areas[i].get_parent() return true + coupled_body = null return false -func _Kinematic_Body_on_Spring(area: Area2D) -> void: - var area_parent = area.get_parent() +func _Kinematic_Body_on_Spring() -> void: 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_mass = mass y_velocity += PhysicsFunc.complete_unelastic_shock( 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 diff --git a/src/Contraptions/Platform/Spring.tscn b/src/Contraptions/Platform/Spring.tscn index d811e95..f172625 100644 --- a/src/Contraptions/Platform/Spring.tscn +++ b/src/Contraptions/Platform/Spring.tscn @@ -4,13 +4,13 @@ [ext_resource path="res://assets/environment/blocks/Basic stone block.png" type="Texture" 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] extents = Vector2( 11.9386, 1.57982 ) [sub_resource type="RectangleShape2D" id=3] -extents = Vector2( 11.4, 1.42384 ) +extents = Vector2( 11.4, 0.878017 ) [node name="Spring" type="Node2D"] script = ExtResource( 1 ) @@ -24,6 +24,7 @@ collision_layer = 32 collision_mask = 3 [node name="CollisionShape2D" type="CollisionShape2D" parent="SpringSkin"] +position = Vector2( 0, -0.25779 ) shape = SubResource( 2 ) [node name="SpringBody" type="KinematicBody2D" parent="."] @@ -39,4 +40,5 @@ collision_layer = 32 collision_mask = 41 [node name="CollisionShape2D" type="CollisionShape2D" parent="EnteringVelocityDetector"] +position = Vector2( 0, 0.629961 ) shape = SubResource( 3 )