0 votes

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!

in Engine by (21 points)

1 Answer

0 votes

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 movementcompleted()") and then switch your yield call in playturn to "yield(activecharacter, "movementcompleted")". Then emit this new signal as the "else" part of your "if !ray.is_colliding():" if statement.

Hope this helps!

by (210 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.