Using a turn-based queue to switch between game pieces

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By turbostack

I am creating a game where one player will control multiple cars movements, one at a time. The player will move the first car, then second, third, and fourth, and restart the process.

Each car should only move once before going to the next car. I have created a turn queue script that looks like this. It gets the first car node from the children of this main 2D node. Then, the play_turn() function waits for the move() function to be completed in the car node itself. Then it moves to the next car node.

extends Node2D

class_name TurnQueue

var active_character

func initialize():
	active_character = get_child(0)

func play_turn():
	yield(active_character.move(), "completed")
	var new_index : int = (active_character.get_index() + 1) % get_child_count()
	active_character = get_child(new_index)

My script for the car node is below. The other car nodes have the same code but with different sprite textures.

extends KinematicBody2D
 
onready var ray = $RayCast2D
var grid_size = 25

### MOVEMENT VECTORS OF CARS ###

var inputs = {
	'ui_up': Vector2.UP + 2*Vector2.RIGHT,
	'ui_down': Vector2.DOWN + 2*Vector2.LEFT,
	'ui_left': 2*Vector2.LEFT + Vector2.UP,
	'ui_right': 2*Vector2.RIGHT + Vector2.DOWN
}

### SET VARIABLES FOR SPRITE TEXTURE CHANGES ###

onready var mysprite = get_node("Red Sedan")
var carTestNW = preload("res://Assets/Test Set/carTestNW.png")
var carTestSE = preload("res://Assets/Test Set/carTestSE.png")
var carTestSW = preload("res://Assets/Test Set/carTestSW.png")
var carTest = preload("res://Assets/Test Set/carTest.png")

### SET VARIABLES ###

func _unhandled_input(event):
	for dir in inputs.keys():
		if event.is_action_pressed(dir):
			move(dir)

func move(dir):
	var vector_pos = inputs[dir] * grid_size
	ray.cast_to = vector_pos # update position
	ray.force_raycast_update() # raycast looks where we want
	if !ray.is_colliding(): # ! = is not, if no collision, move
		position += vector_pos
		if Input.is_action_pressed("ui_up"):
			mysprite.set_texture(carTestSE)
		if Input.is_action_pressed("ui_down"):
			mysprite.set_texture(carTestSW)
		if Input.is_action_pressed("ui_left"):
			mysprite.set_texture(carTestNW)
		if Input.is_action_pressed("ui_right"):
			mysprite.set_texture(carTest)

Yet, I still have both cars moving at the same time and not within a turn queue. I am very new to Godot and many of this was learned from different tutorials. Apologies for the messy code. I am happy to answer any other questions, your help is appreciated!

:bust_in_silhouette: Reply From: tuon

You need to have a yield call in your move function or use a different signal from your car node that would be emitted when the movement is done. The way you have it coded now will call each car’s move function on subsequent frames.

I think you want the car to move till the ray is colliding with something. If that is the case, add a signal to the car node (something like “signal movement_completed()”) and then switch your yield call in play_turn to “yield(active_character, “movement_completed”)”. Then emit this new signal as the “else” part of your “if !ray.is_colliding():” if statement.

Hope this helps!