walk/run states, in-air movement, gravity fix

This commit is contained in:
Jakob Feldmann 2021-04-13 23:46:07 +02:00
parent 7d3a99b284
commit ce04af9332
9 changed files with 160 additions and 71 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"godot_tools.scene_file_config": "c:\\Users\\Jakob\\Documents\\Godot\\Wumper\\src\\Levels\\ApproxLevel.tscn.tmp"
}

View File

@ -10,9 +10,9 @@ config_version=4
_global_script_classes=[ {
"base": "KinematicBody2D",
"class": "Actor",
"class": "Player",
"language": "GDScript",
"path": "res://src/Actor/Actor.gd"
"path": "res://src/Actor/Player.gd"
}, {
"base": "Line2D",
"class": "RayCastDebugLines",
@ -30,7 +30,7 @@ _global_script_classes=[ {
"path": "res://src/StateMachines/StateMachine.gd"
} ]
_global_script_class_icons={
"Actor": "",
"Player": "",
"RayCastDebugLines": "",
"RayCaster": "",
"StateMachine": ""
@ -84,6 +84,12 @@ pause={
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
]
}
boost_move={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777237,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"pressure":0.0,"pressed":false,"script":null)
]
}
[layer_names]

View File

@ -1,14 +0,0 @@
extends KinematicBody2D
class_name Actor
const FLOOR_NORMAL := Vector2.UP
# TODO Round everyone up whoever still uses this variable and fucking kill them
export var speed := Vector2(300, 1000)
# newtonmeters is the unit
export var acceleration_force := Vector2(3050, 4575)
export var gravity := 4000.0
# Kilograms
export var mass := 6
var _velocity := Vector2.ZERO

View File

@ -1,43 +1,39 @@
extends Actor
export var stomp_impulse := 1000.0
extends Player
func _on_EnemyDetector_area_entered(area: Area2D) -> void:
_velocity = calculate_stomp_velocity(_velocity, stomp_impulse)
_velocity = calculate_stomp_velocity(_velocity, stomp_feedback)
func _on_EnemyDetector_body_entered(body: Node) -> void:
die()
func handle_grounded_movement(delta: float, direction: Vector2) -> Vector2:
return calculate_grounded_velocity(_velocity, delta, speed, direction)
func handle_grounded_movement(delta: float, direction: Vector2, state: String) -> Vector2:
return calculate_grounded_velocity(_velocity, delta, direction, state)
func handle_jump_movement(delta: float, direction: Vector2) -> Vector2:
return calculate_jump_velocity(_velocity, delta, speed, direction)
return calculate_jump_velocity(_velocity, delta, direction)
func handle_fall_movement(delta: float, direction: Vector2) -> Vector2:
return calculate_fall_velocity(_velocity, delta, speed, direction)
func apply_gravity(delta, velocity: Vector2):
velocity.y += gravity * delta
return velocity
return calculate_fall_velocity(_velocity, delta, direction)
func calculate_grounded_velocity(
linear_velocity: Vector2, delta: float, speed: Vector2, direction: Vector2
linear_velocity: Vector2, delta: float, direction: Vector2, state: String
) -> Vector2:
var out_vel := linear_velocity
var velocity_direction = 1.0
if _velocity.x < 0:
velocity_direction = -1.0
# Stopping movement
if direction.x == 0.0:
var deceleration_force = calculate_deceleration_force(gravity, mass, delta)
var deceleration_force = calculate_deceleration_force(
gravity, mass, delta
)
# Translates velocity back to force and subtracts deceleration force
var result_force = (
abs(convert_velocity_to_force(_velocity.x, mass, delta))
@ -46,49 +42,96 @@ func calculate_grounded_velocity(
if result_force <= 0:
out_vel.x = 0
else:
out_vel.x = convert_force_to_velocity(result_force, mass, delta) * velocity_direction
out_vel.x = (
convert_force_to_velocity(result_force, mass, delta)
* velocity_direction
)
else:
# Reversing movement
# When turning the opposite direction, friction is added to the opposite acceleration movement
if is_reverse_horizontal_direction(direction):
out_vel.x -= convert_force_to_velocity(calculate_deceleration_force(gravity, mass, delta), mass, delta) * velocity_direction
out_vel.x += (delta * ((acceleration_force.x / mass) * direction.x))
var reverse_move = is_reversing_horizontal_movement(direction)
if reverse_move:
out_vel.x -= (
convert_force_to_velocity(
calculate_deceleration_force(gravity, mass, delta),
mass,
delta
)
* velocity_direction
)
# Normal movement
if abs(_velocity.x) < max_velocity[state]:
out_vel.x += (
delta
* (
(
(
acceleration_force[state].x
+ init_acceleration_force[state] * int(init_boost)
)
/ mass
)
* direction.x
)
)
elif ! reverse_move:
out_vel.x = max_velocity[state] * direction.x
# TODO Is this the right place to determine this?
if is_on_floor():
var additive_jump_force = 0.2 * abs(_velocity.x) * mass
# Jumping when grounded
if is_on_floor() && Input.is_action_pressed("jump"):
var additive_jump_force = 0.2383 * abs(_velocity.x) * mass
out_vel.y = (
((acceleration_force.y + additive_jump_force) / mass)
* direction.y
((acceleration_force[state].y + additive_jump_force) / mass)
* -1
)
else:
out_vel.y = gravity * delta
return out_vel
func is_reverse_horizontal_direction(direction: Vector2) -> bool:
return (direction.x > 0 && _velocity.x < 0) || (direction.x < 0 && _velocity.x > 0)
func is_reversing_horizontal_movement(direction: Vector2) -> bool:
return (
(direction.x > 0 && _velocity.x < 0)
|| (direction.x < 0 && _velocity.x >= 0)
)
func convert_velocity_to_force(velocity, mass, delta) -> float:
return (velocity*mass)/delta
return (velocity * mass) / delta
func convert_force_to_velocity(force, mass, delta) -> float:
return (force/mass)*delta
return (force / mass) * delta
func get_ground_friction() -> float:
return 30.5
return 25.0
# TODO Comments for parameters
func calculate_deceleration_force(gravity: float, mass: float, delta: float) -> float:
return get_ground_friction() * gravity * mass * delta
func calculate_jump_velocity(
linear_velocity: Vector2, delta: float, speed: Vector2, direction: Vector2
linear_velocity: Vector2, delta: float, direction: Vector2
) -> Vector2:
linear_velocity.y += gravity * delta
if _velocity.x == 0:
linear_velocity.x += inair_velocity * direction.x
return linear_velocity
# Only applicable to downwards gravity
func calculate_fall_velocity(
linear_velocity: Vector2, delta: float, speed: Vector2, direction: Vector2
linear_velocity: Vector2, delta: float, direction: Vector2
) -> Vector2:
linear_velocity.y += gravity * delta
if _velocity.y < max_velocity["fall"]:
linear_velocity.y += gravity * delta
else:
linear_velocity.y = max_velocity["fall"]
if _velocity.x == 0:
linear_velocity.x += inair_velocity * direction.x
return linear_velocity

View File

@ -1,16 +1,18 @@
extends Actor
extends Player
export var score := 100
export var score: = 100
func _ready() -> void:
set_physics_process(false)
_velocity.x = -speed.x
_velocity.x = -300
func _on_StompDetector_body_entered(body: Node) -> void:
if body.global_position.y > get_node("StompDetector").global_position.y:
return
get_node("CollisionShape2D").disabled = true
die()
die()
func _physics_process(delta: float) -> void:
@ -19,6 +21,7 @@ func _physics_process(delta: float) -> void:
_velocity.x *= -1.0
_velocity.y = move_and_slide(_velocity, FLOOR_NORMAL).y
func die() -> void:
queue_free()
PlayerData.score += score

20
src/Actor/Player.gd Normal file
View File

@ -0,0 +1,20 @@
extends KinematicBody2D
class_name Player
const FLOOR_NORMAL := Vector2.UP
export var stomp_feedback := 1000.0
export var init_boost := false
export var inair_velocity := 18.3
export var max_velocity := {"walk": 183, "run": 305, "fall": 832}
# This is added to the acceleration force initially
export var init_acceleration_force := {"walk": 3904, "run": 6506.67}
# newtonmeters is the unit
export var acceleration_force := {
"walk": Vector2(2928, 4575), "run": Vector2(2928, 4575)
}
export var gravity := 3904.0
# Kilograms
export var mass := 6
var _velocity := Vector2.ZERO

View File

@ -5,6 +5,7 @@ extends StateMachine
func _ready():
add_state("idle")
add_state("run")
add_state("walk")
add_state("jump")
add_state("fall")
print_debug(states)
@ -27,6 +28,8 @@ func _state_logic(delta):
match self.state:
"idle":
handle_input_ref = funcref(self, 'handle_idle_input')
"walk":
handle_input_ref = funcref(self, 'handle_walk_input')
"run":
handle_input_ref = funcref(self, 'handle_run_input')
"jump":
@ -40,56 +43,74 @@ func _state_logic(delta):
parent.execute_movement()
func handle_idle_input(delta, direction := get_direction()) -> Vector2:
return parent.handle_grounded_movement(delta, direction)
func handle_idle_input(delta, direction := get_horizontal_direction()) -> Vector2:
if Input.is_action_pressed("boost_move"):
return parent.handle_grounded_movement(delta, direction, "run")
else:
return parent.handle_grounded_movement(delta, direction, "walk")
func handle_run_input(delta, direction := get_direction()) -> Vector2:
return parent.handle_grounded_movement(delta, direction)
func handle_walk_input(delta, direction := get_horizontal_direction()) -> Vector2:
return parent.handle_grounded_movement(delta, direction, state)
func handle_jump_input(delta, direction := get_direction()) -> Vector2:
func handle_run_input(delta, direction := get_horizontal_direction()) -> Vector2:
return parent.handle_grounded_movement(delta, direction, state)
func handle_jump_input(delta, direction := get_horizontal_direction()) -> Vector2:
return parent.handle_jump_movement(delta, direction)
func handle_fall_input(delta, direction := get_direction()) -> Vector2:
func handle_fall_input(delta, direction := get_horizontal_direction()) -> Vector2:
return parent.handle_fall_movement(delta, direction)
func get_direction() -> Vector2:
func get_horizontal_direction() -> Vector2:
return Vector2(
(
Input.get_action_strength("move_right")
- Input.get_action_strength("move_left")
),
-1.0 if Input.is_action_pressed("jump") else 1.0
0
)
# Determines which state should be active at the moment
func _get_transition(delta):
parent.get_node("StateLable").text = self.state
parent.get_node("StateLable").text = (
self.state
+ " x vel:"
+ String(round(parent._velocity.x))
)
var new_state
# TODO Can get stuck in Fall on ledges
if !parent.is_on_floor():
if ! parent.is_on_floor():
if parent._velocity.y < 0:
new_state = states.jump
new_state = states.jump
if parent._velocity.y >= 0:
# if self.state == states.run:
# parent._velocity.y = 0
new_state = states.fall
elif parent._velocity.x != 0:
new_state = states.run
if Input.is_action_pressed("boost_move"):
new_state = states.run
else:
new_state = states.walk
else:
# TODO How does this apply to enviornment induced movement?
new_state = states.idle
if new_state != self.state:
return new_state
parent.init_boost = false
return null
func _enter_state(new_state, old_state):
pass
if new_state == "run" || "walk":
parent.init_boost = true
if old_state == "run" && new_state == "walk":
parent.init_boost = false
func _exit_state(old_state, new_state):

File diff suppressed because one or more lines are too long

View File

@ -1,13 +1,14 @@
extends Node
class_name StateMachine
class_name StateMachine
var state = null setget set_state
var previous_state = null
var previous_state = null
var states = {}
# Parent Node that uses these states
onready var parent = get_parent()
# Basic process flow for every SM
func _physics_process(delta):
if state != null:
@ -16,19 +17,24 @@ func _physics_process(delta):
if transition != null:
set_state(transition)
# Game logic consequences of state
func _state_logic(_delta):
pass
func _get_transition(_delta):
return null
func _enter_state(_new_state, _previous_state):
pass
func _exit_state(_previous_state, _new_state):
pass
func set_state(new_state):
previous_state = state
state = new_state
@ -38,5 +44,6 @@ func set_state(new_state):
if new_state != null:
_enter_state(new_state, previous_state)
func add_state(state_name):
states[state_name] = state_name