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=[ { _global_script_classes=[ {
"base": "KinematicBody2D", "base": "KinematicBody2D",
"class": "Actor", "class": "Player",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Actor/Actor.gd" "path": "res://src/Actor/Player.gd"
}, { }, {
"base": "Line2D", "base": "Line2D",
"class": "RayCastDebugLines", "class": "RayCastDebugLines",
@ -30,7 +30,7 @@ _global_script_classes=[ {
"path": "res://src/StateMachines/StateMachine.gd" "path": "res://src/StateMachines/StateMachine.gd"
} ] } ]
_global_script_class_icons={ _global_script_class_icons={
"Actor": "", "Player": "",
"RayCastDebugLines": "", "RayCastDebugLines": "",
"RayCaster": "", "RayCaster": "",
"StateMachine": "" "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) , 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] [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 extends Player
export var stomp_impulse := 1000.0
func _on_EnemyDetector_area_entered(area: Area2D) -> void: 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: func _on_EnemyDetector_body_entered(body: Node) -> void:
die() die()
func handle_grounded_movement(delta: float, direction: Vector2) -> Vector2: func handle_grounded_movement(delta: float, direction: Vector2, state: String) -> Vector2:
return calculate_grounded_velocity(_velocity, delta, speed, direction) return calculate_grounded_velocity(_velocity, delta, direction, state)
func handle_jump_movement(delta: float, direction: Vector2) -> Vector2: 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: func handle_fall_movement(delta: float, direction: Vector2) -> Vector2:
return calculate_fall_velocity(_velocity, delta, speed, direction) return calculate_fall_velocity(_velocity, delta, direction)
func apply_gravity(delta, velocity: Vector2):
velocity.y += gravity * delta
return velocity
func calculate_grounded_velocity( func calculate_grounded_velocity(
linear_velocity: Vector2, delta: float, speed: Vector2, direction: Vector2 linear_velocity: Vector2, delta: float, direction: Vector2, state: String
) -> Vector2: ) -> Vector2:
var out_vel := linear_velocity var out_vel := linear_velocity
var velocity_direction = 1.0 var velocity_direction = 1.0
if _velocity.x < 0: if _velocity.x < 0:
velocity_direction = -1.0 velocity_direction = -1.0
# Stopping movement
if direction.x == 0.0: 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 # Translates velocity back to force and subtracts deceleration force
var result_force = ( var result_force = (
abs(convert_velocity_to_force(_velocity.x, mass, delta)) abs(convert_velocity_to_force(_velocity.x, mass, delta))
@ -46,49 +42,96 @@ func calculate_grounded_velocity(
if result_force <= 0: if result_force <= 0:
out_vel.x = 0 out_vel.x = 0
else: 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: else:
# Reversing movement
# When turning the opposite direction, friction is added to the opposite acceleration movement # When turning the opposite direction, friction is added to the opposite acceleration movement
if is_reverse_horizontal_direction(direction): var reverse_move = is_reversing_horizontal_movement(direction)
out_vel.x -= convert_force_to_velocity(calculate_deceleration_force(gravity, mass, delta), mass, delta) * velocity_direction if reverse_move:
out_vel.x += (delta * ((acceleration_force.x / mass) * direction.x)) 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? # TODO Is this the right place to determine this?
if is_on_floor(): # Jumping when grounded
var additive_jump_force = 0.2 * abs(_velocity.x) * mass if is_on_floor() && Input.is_action_pressed("jump"):
var additive_jump_force = 0.2383 * abs(_velocity.x) * mass
out_vel.y = ( out_vel.y = (
((acceleration_force.y + additive_jump_force) / mass) ((acceleration_force[state].y + additive_jump_force) / mass)
* direction.y * -1
) )
else:
out_vel.y = gravity * delta
return out_vel 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: 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: func convert_force_to_velocity(force, mass, delta) -> float:
return (force/mass)*delta return (force / mass) * delta
func get_ground_friction() -> float: func get_ground_friction() -> float:
return 30.5 return 25.0
# TODO Comments for parameters # TODO Comments for parameters
func calculate_deceleration_force(gravity: float, mass: float, delta: float) -> float: func calculate_deceleration_force(gravity: float, mass: float, delta: float) -> float:
return get_ground_friction() * gravity * mass * delta return get_ground_friction() * gravity * mass * delta
func calculate_jump_velocity( func calculate_jump_velocity(
linear_velocity: Vector2, delta: float, speed: Vector2, direction: Vector2 linear_velocity: Vector2, delta: float, direction: Vector2
) -> Vector2: ) -> Vector2:
linear_velocity.y += gravity * delta linear_velocity.y += gravity * delta
if _velocity.x == 0:
linear_velocity.x += inair_velocity * direction.x
return linear_velocity return linear_velocity
# Only applicable to downwards gravity
func calculate_fall_velocity( func calculate_fall_velocity(
linear_velocity: Vector2, delta: float, speed: Vector2, direction: Vector2 linear_velocity: Vector2, delta: float, direction: Vector2
) -> 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 return linear_velocity

View File

@ -1,16 +1,18 @@
extends Actor extends Player
export var score := 100
export var score: = 100
func _ready() -> void: func _ready() -> void:
set_physics_process(false) set_physics_process(false)
_velocity.x = -speed.x _velocity.x = -300
func _on_StompDetector_body_entered(body: Node) -> void: func _on_StompDetector_body_entered(body: Node) -> void:
if body.global_position.y > get_node("StompDetector").global_position.y: if body.global_position.y > get_node("StompDetector").global_position.y:
return return
get_node("CollisionShape2D").disabled = true get_node("CollisionShape2D").disabled = true
die() die()
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
@ -19,6 +21,7 @@ func _physics_process(delta: float) -> void:
_velocity.x *= -1.0 _velocity.x *= -1.0
_velocity.y = move_and_slide(_velocity, FLOOR_NORMAL).y _velocity.y = move_and_slide(_velocity, FLOOR_NORMAL).y
func die() -> void: func die() -> void:
queue_free() queue_free()
PlayerData.score += score 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(): func _ready():
add_state("idle") add_state("idle")
add_state("run") add_state("run")
add_state("walk")
add_state("jump") add_state("jump")
add_state("fall") add_state("fall")
print_debug(states) print_debug(states)
@ -27,6 +28,8 @@ func _state_logic(delta):
match self.state: match self.state:
"idle": "idle":
handle_input_ref = funcref(self, 'handle_idle_input') handle_input_ref = funcref(self, 'handle_idle_input')
"walk":
handle_input_ref = funcref(self, 'handle_walk_input')
"run": "run":
handle_input_ref = funcref(self, 'handle_run_input') handle_input_ref = funcref(self, 'handle_run_input')
"jump": "jump":
@ -40,56 +43,74 @@ func _state_logic(delta):
parent.execute_movement() parent.execute_movement()
func handle_idle_input(delta, direction := get_direction()) -> Vector2: func handle_idle_input(delta, direction := get_horizontal_direction()) -> Vector2:
return parent.handle_grounded_movement(delta, direction) 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: func handle_walk_input(delta, direction := get_horizontal_direction()) -> Vector2:
return parent.handle_grounded_movement(delta, direction) 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) 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) return parent.handle_fall_movement(delta, direction)
func get_direction() -> Vector2: func get_horizontal_direction() -> Vector2:
return Vector2( return Vector2(
( (
Input.get_action_strength("move_right") Input.get_action_strength("move_right")
- Input.get_action_strength("move_left") - 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 # Determines which state should be active at the moment
func _get_transition(delta): 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 var new_state
# TODO Can get stuck in Fall on ledges # TODO Can get stuck in Fall on ledges
if !parent.is_on_floor(): if ! parent.is_on_floor():
if parent._velocity.y < 0: if parent._velocity.y < 0:
new_state = states.jump new_state = states.jump
if parent._velocity.y >= 0: if parent._velocity.y >= 0:
# if self.state == states.run: # if self.state == states.run:
# parent._velocity.y = 0 # parent._velocity.y = 0
new_state = states.fall new_state = states.fall
elif parent._velocity.x != 0: 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: else:
# TODO How does this apply to enviornment induced movement? # TODO How does this apply to enviornment induced movement?
new_state = states.idle new_state = states.idle
if new_state != self.state: if new_state != self.state:
return new_state return new_state
parent.init_boost = false
return null return null
func _enter_state(new_state, old_state): 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): 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 extends Node
class_name StateMachine class_name StateMachine
var state = null setget set_state var state = null setget set_state
var previous_state = null var previous_state = null
var states = {} var states = {}
# Parent Node that uses these states # Parent Node that uses these states
onready var parent = get_parent() onready var parent = get_parent()
# Basic process flow for every SM # Basic process flow for every SM
func _physics_process(delta): func _physics_process(delta):
if state != null: if state != null:
@ -16,19 +17,24 @@ func _physics_process(delta):
if transition != null: if transition != null:
set_state(transition) set_state(transition)
# Game logic consequences of state # Game logic consequences of state
func _state_logic(_delta): func _state_logic(_delta):
pass pass
func _get_transition(_delta): func _get_transition(_delta):
return null return null
func _enter_state(_new_state, _previous_state): func _enter_state(_new_state, _previous_state):
pass pass
func _exit_state(_previous_state, _new_state): func _exit_state(_previous_state, _new_state):
pass pass
func set_state(new_state): func set_state(new_state):
previous_state = state previous_state = state
state = new_state state = new_state
@ -38,5 +44,6 @@ func set_state(new_state):
if new_state != null: if new_state != null:
_enter_state(new_state, previous_state) _enter_state(new_state, previous_state)
func add_state(state_name): func add_state(state_name):
states[state_name] = state_name states[state_name] = state_name