I’m making a game where the player gets “Dynamically Loaded” into the scene, basically it does:
Saves the player’s last map(scene) and his last position.
Then once opening the game again the game loads the map and instatiates the player on the position and map he was before.
I’m currently implementing a state machine for the player and in order to update the player i’m using the Global variable that i made for him instead of just referencing the node in the code.
But, the Idle state doesn’t seem to be able to access it, because every time i print Global.Player it returns null while The walk state prints the player, and i don’t see anything wrong at all with the code.
So i’m asking help
class_name StateMachine
extends Node
@export var CURRENT_STATE: State
var states: Dictionary = {}
func _ready():
for child in get_children():
if child is State:
states[child.name] = child
child.transition.connect(on_child_transition)
else:
push_warning("State Machine contains a node that isn't a state.")
CURRENT_STATE.enter()
func _process(delta: float) -> void:
CURRENT_STATE.update(delta)
func _physics_process(delta: float) -> void:
pass
#CURRENT_STATE.physics_update(delta)
func on_child_transition(new_state_name: StringName):
var new_state = states.get(new_state_name)
if new_state != null:
if new_state != CURRENT_STATE:
CURRENT_STATE.exit()
new_state.enter()
CURRENT_STATE = new_state
print(CURRENT_STATE)
else:
push_warning("Invalid state")
Idle state:
class_name PlayerIdleState
extends State
func enter():
print(Global.Player)
func update(delta):
if Global.Player.velocity.length() > 0.0:
transition.emit("Walking")
else:
pass
Player:
class_name Player extends CharacterBody2D
@onready var sprite: AnimatedSprite2D = $Sprite
@export var SPEED: float = 100.0
var is_moving: bool = false
var _is_moving: bool = false
var is_on_menu: bool = false
var direction: String = "down"
var can_move: bool = true
func _ready() -> void:
Global.Player
This statement has no effect, it does not set Global.Player you need an equals sign to assign a value
func _ready() -> void:
Global.Player = self
Still, if your statemachine is ready before the player is then it will fail to load. You could wait for a frame to help guarentee the player exists
func _ready():
for child in get_children():
if child is State:
states[child.name] = child
child.transition.connect(on_child_transition)
else:
push_warning("State Machine contains a node that isn't a state.")
await get_tree().process_frame # wait for one frame
CURRENT_STATE.enter()
It will take one frame longer to load. If anything relies on the state machine entering a state then that will have to be two frames delayed, this could spiral out of control if you have highly interlocked/sequential scripts.
owner may not be what you are looking for, it’s for packing scenes and the editor. It may work in your case if the owner happens to create the player on it’s ready, or one of it’s children, but that’s not always going to be the case, and the owner can be deceptive, usually it’s the root of a scene.
Could you share your scene tree? Maybe you mean to use get_parent()?
Seems like you could use await get_parent().ready.
Considering the state machine is a child of the player, why did it need to use a global reference? Do you get errors with that grand-parent path $"../.."? If you do not need any on-ready values from the player then you do not need to wait for the player to be ready either.