Limited Space
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
ld54/nodes/player/player.gd

233 lines
5.7 KiB

extends CharacterBody2D
class_name Player
const SPEED = 100.0
const JUMP_VELOCITY = 200.0
const APNEA_DURATION = 10
const STATES= [
"climb",
"die",
"idle",
"jump",
"spawn",
"walk",
"swim"
]
var use_gravity = {
"climb": false,
"die": true,
"idle": true,
"jump": true,
"spawn": true,
"walk": true,
"swim": true
}
var can_grab_obstacles = {
"climb": false,
"die": false,
"idle": true,
"jump": false,
"spawn": false,
"walk": true,
"swim": true
}
@onready var grab_ray = get_node('oriented_container/grab_ray')
@onready var sprite = get_node('oriented_container/sprite')
# Get the gravity from the project settings to be synced with RigidBody nodes.
var WORLD_GRAVITY = ProjectSettings.get_setting("physics/2d/default_gravity")
var gravity = WORLD_GRAVITY
var grabbed_obstacle = null
func _ready():
$fsm.set_states(STATES)
add_to_group("player")
func on_enter_spawn_state():
$fsm.set_next_state("idle")
func on_enter_idle_state():
pass
func idle_state(_delta):
var direction = Input.get_axis("player_left", "player_right")
if is_on_floor():
velocity.x = 0
if direction:
$fsm.set_next_state("walk")
elif Input.is_action_just_pressed("player_jump") and is_on_floor():
$fsm.set_next_state("jump")
func walk_state(_delta):
var direction = Input.get_axis("player_left", "player_right")
if direction != 0:
velocity.x = direction * SPEED
else:
velocity.x = 0
$fsm.set_next_state("idle")
if Input.is_action_just_pressed("player_jump") and is_on_floor():
$fsm.set_next_state("jump")
if is_on_wall() or (Input.is_action_pressed('player_up') && is_on_ceiling()):
velocity.y = 0
$fsm.set_next_state("climb")
func on_enter_jump_state():
if is_on_floor():
velocity.y = -JUMP_VELOCITY
func jump_state(_delta):
var direction = Input.get_axis("player_left", "player_right")
if(direction):
velocity.x = move_toward(velocity.x, direction * SPEED, SPEED)
if velocity.y > 0:
if is_on_floor():
if direction:
$fsm.set_next_state("walk")
else:
velocity.x = 0
$fsm.set_next_state("idle")
if is_on_wall() || (is_on_ceiling() and Input.is_action_pressed("player_up")):
$fsm.set_next_state("climb")
func on_enter_climb_state():
sprite.modulate = Color(1, 0, 0)
velocity = Vector2(0, 0)
func on_exit_climb_state():
sprite.modulate = Color(1, 1, 1)
func climb_state(_delta):
if is_on_wall():
var direction = Input.get_axis("player_up", "player_down")
velocity = Vector2(0, direction * SPEED)
if is_on_ceiling():
var direction = Input.get_axis("player_left", "player_right")
velocity = Vector2(direction * SPEED, 0)
if Input.is_action_just_pressed("player_jump") and is_on_wall():
var wall_position = get_slide_collision(0).get_normal().x
var jump_normal = Vector2(wall_position, -0.5).normalized()
velocity = jump_normal * JUMP_VELOCITY
$fsm.set_next_state("jump")
if is_on_ceiling() && Input.is_action_just_pressed("player_down"):
velocity.y = 0
$fsm.set_next_state("idle")
if !is_on_wall() && !is_on_ceiling():
$fsm.set_next_state("idle")
func after_state(delta):
move_and_slide()
if use_gravity[$fsm.current_state] == true:
handle_gravity(delta)
if can_grab_obstacles[$fsm.current_state] == true:
handle_grab()
handle_sprite_orientation()
func handle_gravity(delta):
var gravity_delta = gravity
if velocity.y > 0:
if Input.is_action_pressed('player_jump'):
gravity_delta = WORLD_GRAVITY / 10
else:
gravity_delta = WORLD_GRAVITY
velocity.y += gravity_delta * delta
func handle_grab():
if Input.is_action_just_pressed('player_action'):
if grabbed_obstacle == null:
var collision = grab_ray.get_collider()
print('collision', collision)
if collision:
var obstacle = collision
print('obstacle', obstacle)
if obstacle.is_in_group("obstacle"):
do_grab(obstacle)
else:
drop_obstacle()
func do_grab(obstacle):
grabbed_obstacle = obstacle
obstacle.grabbed($oriented_container)
func drop_obstacle():
grabbed_obstacle.dropped()
grabbed_obstacle = null
func handle_sprite_orientation():
# rotates oriented_container to face
# the direction of the velocity
# if is_on_wall, rotated regarding velocity.y, with up by default
# if is_on_ceiling, rotated regarding velocity.x, with right by default
if is_on_wall_only():
if velocity.y != 0:
$oriented_container.rotation = PI/2 if (velocity.y > 0) else - PI / 2
var wall_position = get_slide_collision(0).get_position().x
var player_position = $oriented_container.get_global_position().x
var should_flip_with_wall_left = (wall_position > player_position) && (velocity.y > 0)
var should_flip_with_wall_right = (wall_position < player_position) && (velocity.y < 0)
sprite.flip_v = should_flip_with_wall_left || should_flip_with_wall_right
elif is_on_ceiling():
if velocity.x != 0:
$oriented_container.rotation = PI if (velocity.x > 0) else -PI
else:
if velocity.x != 0:
$oriented_container.rotation = 0 if (velocity.x > 0) else PI
sprite.flip_v = velocity.x < 0
func on_enter_swim_state():
gravity = WORLD_GRAVITY / 2
func swim_state(_delta):
var direction_x = Input.get_axis("player_left", "player_right")
var direction_y = Input.get_axis("player_up", "player_down")
velocity = Vector2(direction_x, direction_y).normalized() * SPEED
var progress_to_black = 1 - clamp($fsm.state_duration / APNEA_DURATION, 0, 1)
sprite.modulate = Color(progress_to_black, progress_to_black, progress_to_black )
if $fsm.state_duration >= APNEA_DURATION:
die()
func on_exit_swim_state():
gravity = WORLD_GRAVITY
sprite.modulate = Color(1,1,1)
func swim():
$fsm.set_next_state("swim")
func unswim():
$fsm.set_next_state("idle")
func die():
$fsm.set_next_state("die")
func on_enter_die_state():
velocity = Vector2(0, -500)
$shape.disabled = true
# $AnimationPlayer.play("die")