-
Notifications
You must be signed in to change notification settings - Fork 16
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.
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 ofget_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.
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)
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.
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()
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.