Godot Version
Question
<!- I’m trying to implement a character with three states so far, one for idle, one for movement, and one called launching
For launching, I want it so that once the player enters this state, they cannot move. However, no matter that state, I am always able to move the character. With the print statement in the State Machine, I know that I transition into the launching state but I can still move.
State Machine:
extends Node
@export var initial_state : State
var current_state : State
var states: Dictionary = {}
func _ready():
for child in get_children():
if child is State:
states[child.name.to_lower()] = child
child.Transitioned.connect(change_state)
if initial_state:
initial_state.Enter()
current_state = initial_state
func _process(delta):
if current_state:
current_state.Update(delta)
func _physics_process(delta):
if current_state:
current_state.Physics_Update(delta)
func change_state(source_state: State, new_state_name: String): #https://www.youtube.com/watch?v=i0Y6anqiJ-g min 4:06, same as this one, just different name with comments
if source_state != current_state:
print("Invalid change_state trying from" + source_state.name + " but currently in: " + current_state.name)
return
var new_state = states.get(new_state_name.to_lower())
if !new_state:
print("New State is empty")
return
if current_state:
current_state.Exit()
new_state.Enter()
current_state = new_state
print(current_state)
Idle State:
extends State
class_name Idle
@export var player : CharacterBody2D
@export var playerSprite : AnimatedSprite2D
func Enter():
print("isIdle")
playerSprite.play("idle")
pass
func Update(_delta : float):
#if Input.is_action_just_pressed("move_left") or Input.is_action_just_pressed("move_right"):
if Input.is_action_pressed("move_left") or Input.is_action_pressed("move_right"):
Transitioned.emit(self, "active")
pass
if Input.is_action_just_pressed("roll"):
pass
if Input.is_action_just_pressed("launch"):
Transitioned.emit(self, "launching")
func Exit():
pass
Active State:
extends State
class_name Active
@export var playerSprite : AnimatedSprite2D
@export var player : CharacterBody2D
const SPEED = 150.0
const JUMP_VELOCITY = -300.0
const PUNCH_SPEED = 200.0
const LONG_JUMP_SPEED = 250.0
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
var jump_Avialable: bool = true
var crouching: bool = false
var rolling: bool = false
var can_roll: bool = true
#
#@onready var animated_sprite = $AnimatedSprite2D
@onready var coyote_timer = $"../../coyote_timer"
@onready var roll_timer = $"../../rollTimer"
@onready var long_jump_timer = $"../../longJumpTimer"
@onready var jumped_timer = $"../../jumpedTimer"
@export var coyote_time: float = 0.5
func _physics_process(delta): #process can be variable to the actual framerate, while physics_process is at a fixed interal (default of 60 per second) which makes it great for character physics
# Add the gravity.
if not player.is_on_floor():
if jump_Avialable == true and coyote_timer.is_stopped():
coyote_timer.start(coyote_time)
#get_tree().create_timer(coyote_time).timeout.connect(coyoteTimeOut)
player.velocity.y += gravity * delta
else:
jump_Avialable = true
coyote_timer.stop()
# Handle jump.
if Input.is_action_just_pressed("jump") and jump_Avialable:
player.velocity.y = JUMP_VELOCITY
jump_Avialable = false
jumped_timer.start()
# direction gets input direction: -1, 0, 1
var direction = Input.get_axis("move_left", "move_right")
# Flip the Sprite:
if direction > 0:
playerSprite.flip_h = false
elif direction < 0:
playerSprite.flip_h = true
# Play animations
if player.is_on_floor():
if crouching == true:
playerSprite.play("crouch")
if player.velocity.x != 0:
print("crouching while moving")
elif rolling == true:
playerSprite.play("roll")
elif direction == 0:
playerSprite.play("idle")
else:
playerSprite.play("run")
else:
playerSprite.play("jump")
if Input.is_action_just_pressed("roll"):
if player.velocity.x == 0:
#if Input.is_action_just_pressed("move_left"):
print("crouched")
crouching = true
else:
print("rolled")
rolling = true
print("roll_timer time_left: ", roll_timer.time_left)
print("roll_timer is_stopped: ", roll_timer.is_stopped())
roll_timer.start()
# Apply movement
if Input.is_action_just_released("roll") and crouching == true:
crouching = false
if direction:
if long_jump_timer.time_left > 0 and not player.is_on_floor():
player.velocity.x = direction * LONG_JUMP_SPEED
print(player.velocity.x)
print("longjump")
elif rolling:
player.velocity.x = direction * PUNCH_SPEED
else:
player.velocity.x = direction * SPEED
else:
player.velocity.x = move_toward(player.velocity.x, 0, SPEED)
player.move_and_slide()
func coyoteTimeOut():
jump_Avialable = false
func _on_roll_timer_timeout():
rolling = false
can_roll = true
if not jumped_timer.time_left > 0:
long_jump_timer.start()
func _on_long_jump_timer_timeout():
pass
func _on_jumped_timer_timeout():
pass
func _on_coyote_timer_timeout():
pass # Replace with function body.
func Enter():
print(roll_timer)
func Update(_delta : float):
if Input.is_action_just_pressed("launch"):
print("launches")
Transitioned.emit(self, "launching")
pass
if Input.is_action_just_pressed("roll"):
pass
func Exit():
pass
extends State
class_name Launching
@export var playerSprite : AnimatedSprite2D
@export var player : CharacterBody2D
func Enter():
print("isLaunching")
playerSprite.play("idle")
pass
func Update(_delta : float):
if Input.is_action_just_pressed("launch"):
print("launches")
Transitioned.emit(self, "active")
pass
func Exit():
pass