I am making a 2D horror game where you move right to left and am using a clamp function to avoid having to make simple collision for each map. I have two concurrent state machines handling player states (idle, walk, run) and stamina meter states (empty, charging, full with a slower recovery when emptying). All my scripts are working and the debugger's not throwing any errors but for some reason when i hit my clamp limits when running, the variable for stamina starts doing strange things (going back up, not recharging fully, etc). Any help appreciated.
extends KinematicBody2D
const spdDefault = 150
const maxStamina = 300
export var speed = 150
export var runSpeed = 300
export var stamina = 300
export var burnRate = 2
export var chargeRate = 1
export var breatherTime = 2
export var deepBreath = 5
export var marg = 50
var direction = Vector2.ZERO
onready var sprite = $AnimatedSprite
var screen_size
enum STATE {IDLE, WALKING, RUNNING}
enum CHARGESTATE {EMPTY, CHARGING, FULL}
var playerState
var staminaState
func _ready():
stamina = maxStamina
playerState = STATE.IDLE
staminaState = CHARGESTATE.FULL
screen_size = get_viewport_rect().size
func _input(_event):
if Input.is_action_pressed("ui_left") or Input.is_action_pressed("ui_right"):
playerState = STATE.WALKING
if Input.is_action_pressed("run") and staminaState != CHARGESTATE.EMPTY:
playerState = STATE.RUNNING
if staminaState == CHARGESTATE.EMPTY:
playerState = STATE.WALKING
else:
playerState = STATE.IDLE
if Input.is_action_just_released("run"):
playerState = STATE.WALKING
if Input.is_action_just_pressed("debug"):
debugCommand()
func _process(delta):
match playerState:
STATE.IDLE:
sprite.play('idle')
STATE.WALKING:
walking(delta)
speed = spdDefault
STATE.RUNNING:
running(delta)
match staminaState:
CHARGESTATE.EMPTY:
recharging()
CHARGESTATE.CHARGING:
idle_charging()
CHARGESTATE.FULL:
pass
stamDebug()
func walking(delta):
direction.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
anim_controller()
if direction.x == 0:
playerState = STATE.IDLE
var movement = direction * speed * delta
move_and_collide(movement)
var x_limit_l = (0 - ((screen_size.x/2)-marg))
var x_limit_r = ((screen_size.x/2)-marg)
position.x = clamp(position.x, x_limit_l, x_limit_r)
func running(delta):
walking(delta)
speed = runSpeed
while stamina > 0 and staminaState != CHARGESTATE.EMPTY and Input.is_action_pressed("run"):
stamina = stamina-burnRate
var burn = Timer.new()
add_child(burn)
burn.set_wait_time(burnRate)
burn.start()
yield(burn,"timeout")
if stamina < 1:
playerState = STATE.WALKING
break
func stamDebug():
match stamina:
maxStamina:
staminaState = CHARGESTATE.FULL
0:
staminaState = CHARGESTATE.EMPTY
if stamina != maxStamina and staminaState != CHARGESTATE.EMPTY:
staminaState = CHARGESTATE.CHARGING
if stamina >= maxStamina:
stamina = maxStamina
if stamina < 1:
stamina = 0
func anim_controller():
match playerState:
STATE.WALKING:
sprite.play('walk')
STATE.RUNNING:
sprite.play('run')
STATE.IDLE:
sprite.play('idle')
if direction.x < 0:
sprite.flip_h = true
if direction.x > 0:
sprite.flip_h = false
func recharging():
var breather = Timer.new()
add_child(breather)
breather.set_wait_time(deepBreath)
breather.start()
yield(breather,"timeout")
staminaUp()
breather.queue_free()
func idle_charging():
var idleT = Timer.new()
add_child(idleT)
idleT.set_wait_time(breatherTime)
idleT.start()
yield(idleT,"timeout")
staminaUp()
idleT.queue_free()
func staminaUp():
var sT = Timer.new()
add_child(sT)
sT.set_wait_time(chargeRate)
while stamina < maxStamina:
sT.start()
stamina = stamina+chargeRate
yield(sT,"timeout")
if stamina >= maxStamina:
staminaState = CHARGESTATE.FULL
sT.queue_free()
break
func chargeCheck():
if stamina >= maxStamina:
staminaState = CHARGESTATE.FULL
stamina = maxStamina
if stamina != maxStamina:
staminaState = CHARGESTATE.CHARGING
if stamina < 1:
stamina = 0
staminaState = CHARGESTATE.EMPTY
func debugCommand():
print("Player state: " + str(playerState))
print("Charge state: " + str(staminaState))
print("Stamina level: " + str(stamina))