Godot Version
4.3
Question
i followed this tutorial and made a state machine. now however, i want to change the state from a parent node. I’ve tried state.Transition.emit(true, “follow”) and all that but nothing is working
4.3
i followed this tutorial and made a state machine. now however, i want to change the state from a parent node. I’ve tried state.Transition.emit(true, “follow”) and all that but nothing is working
Can you paste your script? Videos are really bad for sifting through. For example scrubbing through that video I do not see signal Transition
defined, though they use Transition.emit(self, "idle")
this is set up to either follow the player or have free cam
state machine node
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(on_child_transition)
if initial_state:
initial_state.Enter()
current_state = initial_state
func _process(delta: float):
print(current_state)
if current_state:
current_state.Update(delta)
func _physics_process(delta: float):
if current_state:
current_state.Update(delta)
func on_child_transition(state, new_state_name):
if state != current_state:
return
var new_state = states.get(new_state_name.to_lower())
if !new_state:
return
if current_state:
current_state.Exit()
new_state.Enter()
current_state = new_state
follow state
extends State
class_name cameraFollow
@export var camera: Camera2D
func Enter():
follow()
camera.targetZoom = Vector2(2, 2)
func follow():
if camera.target != "":
var targetPos = Global.NODE_WORLD.get_node(camera.target).position
camera.position += (targetPos - camera.position) / camera.smooth
func Update(delta):
follow()
free state
class_name cameraFree
@export var camera: Camera2D
var dragVel = Vector2(0, 0)
var oldMousePos = Vector2(0, 0)
var termDragVel = Vector2(10, 10)
func Enter():
camera.targetZoom = Vector2(4, 4)
func Update(delta: float) -> void:
var mousePos = camera.get_viewport().get_mouse_position()
if Input.is_action_pressed("lClick"):
dragVel -= dragVel / 10
if oldMousePos != mousePos:
dragVel = (oldMousePos - mousePos)/2
camera.position += (oldMousePos - mousePos)/camera.zoom
else:
camera.position += dragVel
dragVel -= dragVel / 10
if abs(dragVel.x) > termDragVel.x:
dragVel.x = termDragVel.x * sign(dragVel.x)
if abs(dragVel.y) > termDragVel.y:
dragVel.y = termDragVel.y * sign(dragVel.y)
oldMousePos = mousePos
Again I don’t see a signal Transition
defined, I would bet it’s part of your base State script. Eitherway This line is probably what prevents you from changing states and does nothing.
Your first argument true
is not a state or node, so it will return early, doing nothing. I believe you do not want this check at all so it may be better to remove the state
argument and the if statement that follows.
i forgot to meantion there is a state script that has
extends Node
class_name State
signal Transitioned
func Enter():
pass
func Exit():
pass
func Update(_delta: float):
pass
func Physics_Update(_delta: float):
pass
inside it. however I think this problem might be too specific for anyone to answer, i gave the code to chat gpt and it told me to put
func change_state(new_state: State):
if current_state:
current_state.Exit()
current_state = new_state
if current_state:
current_state.Enter()
inside of the state machine node and then call
var new_state = $StateMachineNode.states["camera_follow"]
$StateMachineNode.change_state(new_state)
in another node. sorry to waste your time but ill give you the solution mark anyway
You do already have that code in your script.
Is in the state machine script here:
The latter just has more checks, and the functional part is simpler. You could use
$StateMachineNode.on_child_transition($StateMachineNode.current_state, "camera_follow")
But that’s why I’m saying the function is made with too many silly checks. I would remove all these commented lines
func on_child_transition(new_state_name: String): # removed 'state' argument.
#if state != current_state:
#return
var new_state = states.get(new_state_name.to_lower())
#if !new_state: # allow it to error or use an assert
#return
if current_state:
current_state.Exit()
new_state.Enter()
current_state = new_state
And now you can use
$StateMachineNode.on_child_transition("camera_follow")