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

08: Add GUI

Source code.

At the end of this chapter, your game will look like the image below. We will reach this target in two steps. First, add GUI containers to design a static UI layout. You should be familiar with size flags before continue. Second, whenever we used to call print(), now we emit a signal. Let GUI containers receive these signals and update their content.

IMAGE: Chapter 8 screenshot

Add GUI Containers

Open MainGUI.tscn. Remove existing nodes. Add new nodes as shown below. Also remember to change the type of the root node.

MainGUI (MarginContainer)
- MainHBox (HBoxContainer)
-- Modeline (Label)
-- SidebarVBox (VBoxContainer)
--- Turn (Label)
--- Help (Label)

IMAGE: Main GUI margin

Open MainScene.tscn. Set MainGUI node's margin so that it leaves 20 pixel on four sides.

IMAGE: Label nodes

Since there are three label nodes and we intend to apply the same style to them, we'd better create these nodes from a scene. Select MainHBox/Modeline. Change its font to FiraCode-Regular.ttf and font color to ABB2BF. Save the branch as scene: res://sprite/GUIText.tscn. Replace all label nodes.

IMAGE: Set containers

The last step in this part is to set containers so as to align text automatically.

Modeline:

  • Size Flags/Horizontal: Fill, Expand.
  • Size Flags/Vertical: Shrink End.

SidebarVBox:

  • Rect/Min Size: x: 180.

Turn:

  • Size Flags/Vertical: Fill, Expand.

Use Signals To Update UI Content

There are three labels under MainGUI node. Help prints a static text. Turn prints a number which starts from 0 and updates by 1 whenever PC's turn begins. Modeline prints one of four texts when: (1) PC tries to leave the dungeon; (2) PC bumps into a wall; (3) PC is close to an NPC; (4) PC kills an NPC.

Let's take care of Help and Turn first. Attach SidebarVBox.gd to SidebarVBox.

# SidebarVBox.gd

var _turn_counter: int = 0
var _turn_text: String = "Turn: {0}"

onready var _label_help: Label = get_node("Help")
onready var _label_turn: Label = get_node("Turn")


func _ready() -> void:
    _label_help.text = "RL Demo"
    _update_turn()


func _on_Schedule_turn_started(current_sprite: Sprite) -> void:
    if current_sprite.is_in_group(_new_GroupName.PC):
        _turn_counter += 1
        _update_turn()


func _update_turn() -> void:
    _label_turn.text = _turn_text.format([_turn_counter])

Let PCMove.gd, PCAttack.gd and EnemyAI.gd emit three signals instead of print messages in output panel.

# PCMove.gd

signal pc_moved(message)


func _try_move(x: int, y: int) -> void:
    if not _ref_DungeonBoard.is_inside_dungeon(x, y):
        emit_signal("pc_moved", "You cannot leave the map.")
    elif _ref_DungeonBoard.has_sprite(_new_GroupName.WALL, x, y):
        emit_signal("pc_moved", "You bump into wall.")


# PCAttack.gd

signal pc_attacked(message)


func attack(group_name: String, x: int, y: int) -> void:
    if not _ref_DungeonBoard.has_sprite(group_name, x, y):
        return
    _ref_RemoveObject.remove(group_name, x, y)
    _ref_Schedule.end_turn()
    emit_signal("pc_attacked", "You kill Urist McRogueliker! :(")


# EnemyAI.gd

signal enemy_warned(message)


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

    if _pc_is_close(_pc, current_sprite):
        emit_signal("enemy_warned", "Urist McRogueliker is scared!")
    _ref_Schedule.end_turn()

The last step is attaching Modeline.gd to Modeline. The script receives the three signals above. It also receives turn_ended from Schedule.gd to clear text every turn.

# Schedule.gd

signal turn_ended(current_sprite)


func end_turn() -> void:
    emit_signal("turn_ended", _get_current())
    _goto_next()
    emit_signal("turn_started", _get_current())


# Modeline.gd

func _ready() -> void:
    text = "Press Space to start game."


func _on_Schedule_turn_ended(current_sprite: Sprite) -> void:
    if current_sprite.is_in_group(_new_GroupName.PC):
        text = ""


func _on_EnemyAI_enemy_warned(message: String) -> void:
    text = message


func _on_PCMove_pc_moved(message: String) -> void:
    text = message


func _on_PCAttack_pc_attacked(message: String) -> void:
    text = message
Clone this wiki locally