Godot Version
v4.3.stable.official [77dcf97d8]
Question
Hello,
I’m trying to make a 3D turn-based game and I’m getting strange behaviour when I swap turns. Here’s how I intended to implement it, along with the code:
- In _ready(), the world script adds everything that has a turn to an array, sorts them by speed, starts counting turns and sets the first node state to “active” - this seems to work okay.
func _ready() -> void:
for N in get_tree().get_nodes_in_group("takes_turn"):
turn_counter.append(N)
sort_turns(turn_counter)
active_turn = 0
turn_number = 1
actor_count = turn_counter.size()
turn_counter[active_turn].state = turn_state.ACTIVE
- In its _process() function, each node checks to see if it’s active, prints “0” to let me know, then emits an “end turn” signal.
func _process(delta: float) -> void:
if state == turn_state.ACTIVE: #checks if turn state is active
print(str(self) + "0")
end_turn.emit() # emits end turn signal
- Then the world script uses its own _process() function to await an “end turn” signal from the active node, sets the active node to “idle”, increments through the turn order array and sets the next node to “active”.
func _process(delta: float) -> void:
change_turn()
func change_turn():
await turn_counter[active_turn].end_turn #waits for actor's end turn signal
print(str(turn_counter[active_turn]) + ": ending turn") #prints whose turn is ending
turn_counter[active_turn].state = turn_state.IDLE #sets current actor to IDLE state
if active_turn < actor_count - 1: #checks to see if at end of turn order;
active_turn += 1 #increments turn order if not
else:
active_turn = 0 #if it is, returns turn number to 0
turn_number += 1 #and increments the turn number
turn_counter[active_turn].state = turn_state.ACTIVE #changes the current turn number's state to ACTIVE
print(str(turn_counter[active_turn])+ ": starting turn") #prints whose turn is starting
- When it’s the player’s turn I can press the spacebar to end it - that’s all I need to do for now.
func _physics_process(delta: float) -> void:
if state == turn_state.ACTIVE:
if Input.is_action_just_pressed("end_turn"):
end_turn.emit()
To test it, I have two identical plain Nodes (called watcher and watcher2) and a CharacterBody3D for the player. The first watcher starts its turn, prints 0 and ends its turn. The world script tells me that the first watcher has ended its turn and passes the turn to the second. The second one starts its turn, prints 0, prints 0 again, then ends its turn. The turn passes to the player.
watcher:<Node#29410460979>0
watcher:<Node#29410460979>: ending turn
watcher2:<Node#29427238196>: starting turn
watcher2:<Node#29427238196>0
watcher2:<Node#29427238196>0
watcher2:<Node#29427238196>: ending turn
player:<CharacterBody3D29242688796>: starting turn
When I press the spacebar, the turns pass about 20 times, with no output until the final one, when it waits for player input again.
player:<CharacterBody3D#29242688796>: ending turn
watcher:<Node#29410460979>: starting turn
watcher:<Node#29410460979>: ending turn
watcher2:<Node#29427238196>: starting turn
watcher2:<Node#29427238196>: ending turn
player:<CharacterBody3D#29242688796>: starting turn
player:<CharacterBody3D#29242688796>: ending turn
watcher:<Node#29410460979>: starting turn
watcher:<Node#29410460979>: ending turn
[repeat many times]
watcher2:<Node#29427238196>: starting turn
watcher2:<Node#29427238196>: ending turn
player:<CharacterBody3D#29242688796>: starting turn
player:<CharacterBody3D#29242688796>: ending turn
watcher:<Node#29410460979>: starting turn
watcher:<Node#29410460979>0
watcher:<Node#29410460979>: ending turn
watcher2:<Node#29427238196>: starting turn
watcher2:<Node#29427238196>0
watcher2:<Node#29427238196>0
watcher2:<Node#29427238196>: ending turn
player:<CharacterBody3D#29242688796>: starting turn
I suspect this is an issue with the framerate being too high for the nodes to do anything. They’re clearly emitting the “end turn” signal, or else they wouldn’t change turns at all, but I’m not sure how they’re skipping the “print 0” line. I’ve tried forcing the nodes to wait for a signal from the world script to start but it doesn’t seem to have helped.
Any thoughts on why this is happening, what I can do to solve it, or a better implementation would be greatly appreciated - this is my first real project in Godot and things were going very smoothly until this happened!