States and Movement issue

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

Well… Your Active state has a _physics_process function which appears to handle input and movement. If you don’t do anything to disable physics processing for the node that script is on, then it’s going to run that code regardless of what the state machine says. So the solution would be to move that code into the Update function.

That fixed it! Thanks so much!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.