278 lines
8.3 KiB
GDScript
278 lines
8.3 KiB
GDScript
# An example of a script that could be on an enemy/player (in this case enemy).
|
|
# Controls state changes and state input such as direction, could use
|
|
# area detectors then change the state for example.
|
|
extends CharacterBody2D
|
|
|
|
func current_state():
|
|
return stm.state
|
|
|
|
@onready var stm = $StateMachine
|
|
@onready var animation_player = $AnimationPlayer
|
|
@onready var player_character_sprite = $PlayerCharacterSprite
|
|
@onready var camera = $Camera
|
|
@onready var air = $StateMachine/Air
|
|
@onready var run = $StateMachine/Run
|
|
@onready var dash = $StateMachine/Dash
|
|
@onready var wallslide = $StateMachine/Wallslide
|
|
|
|
@onready var hitbox_up = $Hitboxes/Up
|
|
@onready var hitbox_down = $Hitboxes/Down
|
|
@onready var hitbox_side = $Hitboxes/Side
|
|
|
|
@export var buffer_jump := 0.0
|
|
var buffer_jump_tmp := 0.0
|
|
|
|
@export var coyote_jump := 0.0
|
|
var coyote_jump_tmp := coyote_jump
|
|
|
|
@export var double_jump_delay := 0.0
|
|
var double_jump_delay_tmp := 0.0
|
|
var double_jump_delay_initiated := false
|
|
|
|
@export var dash_time: float
|
|
var dash_time_tmp := dash_time
|
|
|
|
@export var hit_time: float
|
|
var hit_time_tmp: float
|
|
var hit_active := false
|
|
|
|
@export var pogo_jump: float
|
|
@export var wavedash_velocity: Vector2
|
|
@export var camera_look_aside := 0.0
|
|
@export var camera_look_aside_transition_speed := 0.0
|
|
|
|
var lives := 5
|
|
|
|
var double_jump_used := false
|
|
var dash_used := false
|
|
# Not an animation variable
|
|
var looking_right := true
|
|
# Animation variables 😀
|
|
var previous_input_dir := get_dir()
|
|
var previous_velocity := Vector2.ZERO
|
|
|
|
func _ready():
|
|
camera
|
|
stm.state_debug_stat = { "key": "player state" }
|
|
stm.state_debug_log = { "description": "player state" }
|
|
air.jump_debug_stat = { "key": "player jump curve" }
|
|
air.air_run_debug_stat = { "key": "player run curve" }
|
|
run.run_debug_stat = { "key": "player run curve" }
|
|
|
|
func update_looking_right():
|
|
var dir = get_dir()
|
|
if dir.x < 0:
|
|
looking_right = false
|
|
if dir.x > 0:
|
|
looking_right = true
|
|
|
|
func play_anim(anim_name):
|
|
var full_name = anim_name + "_" + ("r" if looking_right else "l")
|
|
# Play the AnimatedSprite2D
|
|
if player_character_sprite.sprite_frames.has_animation(full_name):
|
|
player_character_sprite.play(full_name)
|
|
elif player_character_sprite.sprite_frames.has_animation(anim_name):
|
|
player_character_sprite.play(anim_name)
|
|
else:
|
|
printerr("No animation: " + anim_name + ", or: " + full_name)
|
|
# Play AnimationPlayer
|
|
if animation_player.has_animation(full_name):
|
|
animation_player.play(full_name)
|
|
elif animation_player.has_animation(anim_name):
|
|
animation_player.play(anim_name)
|
|
|
|
# General structue: mimics querries of state, than acts apon that
|
|
func _physics_process(delta):
|
|
# Looking right (both animation and logic)
|
|
update_looking_right()
|
|
# Update camera position
|
|
var camera_pos_target = camera_look_aside if looking_right else - camera_look_aside
|
|
camera.position.x = lerp(
|
|
camera.position.x,
|
|
camera_pos_target,
|
|
delta * camera_look_aside_transition_speed
|
|
)
|
|
# Flip player nodes that want to be flipped
|
|
for child in self.find_children("*"):
|
|
if child.is_in_group("flip_me"):
|
|
child.scale.x = 1 if looking_right else -1
|
|
# Animations!
|
|
if current_state() in [run]:
|
|
if previous_input_dir.sign().x - get_dir().sign().x == 0:
|
|
if velocity.is_zero_approx():
|
|
play_anim("idle")
|
|
else:
|
|
play_anim("run")
|
|
if current_state() in [air]:
|
|
if previous_velocity.y <= 0 && velocity.y > 0:
|
|
play_anim("fall")
|
|
previous_input_dir = get_dir()
|
|
previous_velocity = velocity
|
|
# Jump buffering
|
|
if Input.is_action_just_pressed("jump"):
|
|
buffer_jump_tmp = buffer_jump
|
|
else:
|
|
buffer_jump_tmp -= delta
|
|
# Start falling
|
|
if current_state() in [run] && not is_on_floor():
|
|
if coyote_jump_tmp <= 0:
|
|
# Fall
|
|
coyote_jump_tmp = coyote_jump
|
|
play_anim("fall")
|
|
stm.transition(air)
|
|
else:
|
|
coyote_jump_tmp -= delta
|
|
if Input.is_action_just_pressed("jump"):
|
|
do_jump()
|
|
StatHub.stat_set({ "key": "player did coyote jump", "indicate": true })
|
|
return
|
|
else:
|
|
coyote_jump_tmp = coyote_jump
|
|
# Land
|
|
if current_state() in [air, wallslide] && is_on_floor():
|
|
double_jump_used = false
|
|
dash_used = false
|
|
if buffer_jump_tmp > 0:
|
|
buffer_jump_tmp = 0
|
|
double_jump_delay_initiated = false
|
|
play_anim("jump")
|
|
stm.transition(air, { "jump_stats" : run.jump() })
|
|
StatHub.stat_set({ "key": "player jumped buffered jump", "indicate": true })
|
|
else:
|
|
if velocity.is_zero_approx():
|
|
play_anim("idle")
|
|
else:
|
|
play_anim("run")
|
|
stm.transition(run)
|
|
# Wallslide
|
|
if current_state() in [air, dash] && is_on_wall():
|
|
if (looking_right && get_dir().x > 0) || (!looking_right && get_dir().x < 0):
|
|
if velocity.y > 0 || current_state() in [dash]:
|
|
play_anim("wallslide")
|
|
stm.transition(wallslide)
|
|
double_jump_used = false
|
|
dash_used = false
|
|
else:
|
|
if Input.is_action_just_pressed("jump"):
|
|
stm.transition(air, { "jump_stats" : current_state().wall_jump() })
|
|
return
|
|
# Stop wallslide
|
|
if current_state() in [wallslide]:
|
|
var test_vector := Vector2.ZERO
|
|
if looking_right:
|
|
test_vector.x = 1
|
|
else:
|
|
test_vector.x = -1
|
|
if move_and_collide(test_vector, true) == null:
|
|
stm.transition(air)
|
|
# Jump
|
|
if current_state() in [run] && Input.is_action_just_pressed("jump"):
|
|
do_jump()
|
|
return
|
|
# Double Jump
|
|
if current_state() in [air]:
|
|
if double_jump_delay_initiated:
|
|
if double_jump_delay_tmp <= 0 && !double_jump_used:
|
|
double_jump_delay_initiated = false
|
|
double_jump_used = true
|
|
do_jump()
|
|
StatHub.stat_set({ "key": "player did double jump", "indicate": true })
|
|
else:
|
|
double_jump_delay_tmp -= delta
|
|
elif Input.is_action_just_pressed("jump"):
|
|
double_jump_delay_initiated = true
|
|
double_jump_delay_tmp = double_jump_delay
|
|
else:
|
|
double_jump_delay_initiated = false
|
|
# Wall Jump
|
|
if current_state() in [wallslide] && Input.is_action_just_pressed("jump"):
|
|
do_jump()
|
|
# Continue jumping
|
|
if current_state() in [air]:
|
|
current_state().continue_jump(Input.is_action_pressed("jump"))
|
|
# Walk left/right
|
|
if current_state() in [run, air]:
|
|
current_state().direction = get_dir().x
|
|
# Do dash
|
|
if current_state() in [run, air] && Input.is_action_just_pressed("dash") && !dash_used:
|
|
dash_used = true
|
|
dash_time_tmp = dash_time
|
|
var dir := get_dir()
|
|
if dir == Vector2.ZERO:
|
|
if looking_right: dir.x = 1
|
|
else: dir.x = -1
|
|
play_anim("dash")
|
|
stm.transition(dash)
|
|
current_state().direction = dir
|
|
# Done with dash
|
|
if current_state() in [dash]:
|
|
if dash_time_tmp <= 0:
|
|
play_anim("fall")
|
|
stm.transition(air) # TODO: maybe ground?
|
|
else:
|
|
dash_time_tmp -= delta
|
|
current_state().progression = (dash_time - dash_time_tmp) / dash_time
|
|
# Wavedash
|
|
if current_state() in [dash]:
|
|
if is_on_floor() && Input.is_action_just_pressed("jump") && \
|
|
abs(get_dir().x) - abs(get_dir().y) == 0:
|
|
stm.transition(air)
|
|
velocity = wavedash_velocity * get_dir()
|
|
# Hitboxes
|
|
if current_state() in [run, air]:
|
|
if hit_active:
|
|
if hit_time_tmp <= 0:
|
|
hit_active = false
|
|
disable_hitboxes()
|
|
else:
|
|
hit_time_tmp -= delta
|
|
else:
|
|
if looking_right: hitbox_side.get_parent().scale.x = 1
|
|
else: hitbox_side.get_parent().scale.x = -1
|
|
if Input.is_action_just_pressed("attack"):
|
|
hit_active = true
|
|
hit_time_tmp = hit_time
|
|
var dir = get_dir()
|
|
if dir.y < 0:
|
|
hitbox_up.set_active(true)
|
|
elif dir.y > 0:
|
|
hitbox_down.set_active(true)
|
|
else:
|
|
hitbox_side.set_active(true)
|
|
else:
|
|
disable_hitboxes()
|
|
|
|
current_state().update(delta)
|
|
StatHub.stat_set({ "key": "player velocity", "value": str(velocity) })
|
|
|
|
func disable_hitboxes():
|
|
for hitbox in [hitbox_up, hitbox_down, hitbox_side]:
|
|
hitbox.set_active(false)
|
|
|
|
func do_jump():
|
|
play_anim("jump")
|
|
stm.transition(air, { "jump_stats" : current_state().jump() })
|
|
|
|
func get_dir() -> Vector2:
|
|
var analog := Vector2.ZERO
|
|
if Input.is_action_pressed("walk_left_analog"):
|
|
analog.x += -1
|
|
if Input.is_action_pressed("walk_right_analog"):
|
|
analog.x += 1
|
|
if Input.is_action_pressed("walk_up_analog"):
|
|
analog.y += -1
|
|
if Input.is_action_pressed("walk_down_analog"):
|
|
analog.y += 1
|
|
var digital = Vector2(Input.get_axis("walk_left", "walk_right"), Input.get_axis("walk_up", "walk_down"))
|
|
if analog != Vector2.ZERO: return analog
|
|
else: return digital
|
|
|
|
func _on_down_hit(_data):
|
|
dash_used = false
|
|
double_jump_used = false
|
|
velocity.y = - pogo_jump
|
|
|
|
func _on_hurt_box_hurt(_data):
|
|
lives -= 1
|
|
StatHub.stat_set({"key": "player health", "value": str(lives), "indicate": true})
|