Skip to content
bozar42 edited this page Apr 22, 2020 · 5 revisions

05: Add A Scheduling System

Source code.

At the end of Chapter 5, the game looks almost the same as Chapter 4, therefore I do not provide a screenshot for this chapter. The only difference lies in the output messages triggered by Schedule.gd.

The Functions Of A Scheduling System

A scheduling system should provide these methods:

  • add_to_schedule(): Add actors to the system.
  • get_current(): Get the currently active actor.
  • goto_next(): Update the return value of get_current().
  • end_turn(), start_turn(): Notify other game components the flow of time.

Beware that not all of them shall appear as public methods in our code. They might be private functions, fields or signals.

Add Actors To The System

Check out commit: 07a46db.

Add Schedule (Node2D node) to MainScene. Attach Schedule.gd to the node. Let it subscribe sprite_created (signal) and add sprites to _actors: Array. Here is a trick to ensure that pc is always the first element in the array.

# Schedule.gd

var _actors: Array = [null]


func _on_InitWorld_sprite_created(new_sprite: Sprite) -> void:
    if new_sprite.is_in_group(_new_GroupName.PC):
        _actors[0] = new_sprite
    elif new_sprite.is_in_group(_new_GroupName.DWARF):
        _actors.append(new_sprite)

Let The System Affect PC

Check out commit: 7322990.

After PC moves, his turn ends. Besides, PCMove.gd should no longer respond to inputs. When PC's turn starts, let PCMove.gd start listening inputs. The analysis shows that we need to modify both Schedule.gd and PCMove.gd. First, add end_turn() (public method), _goto_next() (private method) and turn_ended (signal) to Schedule.gd.

# Schedule.gd

signal turn_started(current_sprite)

var _pointer: int = 0


func end_turn() -> void:
    print("{0}: End turn.".format([_get_current().name]))
    _goto_next()
    emit_signal("turn_started", _get_current())


func _get_current() -> Sprite:
    return _actors[_pointer] as Sprite


func _goto_next() -> void:
    _pointer += 1

    if _pointer > len(_actors) - 1:
        _pointer = 0

PCMove.gd calls Schedule.end_turn() and receives turn_ended.

# PCMove.gd

func _unhandled_input(event: InputEvent) -> void:
    var source: Array = _new_ConvertCoord.vector_to_array(_pc.position)
    var target: Array

    if _is_move_input(event):
        target = _get_new_position(event, source)
        _pc.position = _new_ConvertCoord.index_to_vector(
                target[0], target[1])

        set_process_unhandled_input(false)
        get_node("../Schedule").end_turn()


func _on_Schedule_turn_started(current_sprite: Sprite) -> void:
    if current_sprite.is_in_group(_new_GroupName.PC):
        set_process_unhandled_input(true)
    else:
        print(current_sprite.name)

If you run code at current stage, you will find that the game stops responding after pressing an arrow key. This is the intended behavior. We will fix it in the next part.

Let The System Affect NPC

Check out commit: 45449fd.

When an NPC's turn starts, immediately call Schedule.end_turn(). We will implement NPC's behavior in Chapter 7. Add EnemyAI to MainScene and attach a script to it.

# EnemyAI.gd

func _on_Schedule_turn_started(current_sprite: Sprite) -> void:
    if not current_sprite.is_in_group(_new_GroupName.DWARF):
        return

    get_node("../Schedule").end_turn()

Let Parent Set Node References

At the end of Chapter 4, we use parent node to connect signals. Similarly, instead of writing get_node("../Schedule"), we'd better set references in MainScene node.

# MainScene.gd

func _ready():
    get_node("PCMove")._ref_Schedule = get_node("Schedule")
    get_node("EnemyAI")._ref_Schedule = get_node("Schedule")


# PCMove.gd

const Schedule := preload("res://scene/main/Schedule.gd")

var _ref_Schedule: Schedule


func _unhandled_input(event: InputEvent) -> void:
    if _is_move_input(event):
        # Others remain unchanged.
        _ref_Schedule.end_turn()

MainScene.gd becomes kinda messy now. We will introduce a new way to make connections in Chapter 10. Also note that we use _ref prefix to refer to node references, and _new prefix to refer to script resources from the library/ folder.

Clone this wiki locally