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

07: PC Attacks NPC

Source code.

In this chapter, we will add two nodes, PCAttack and RemoveObject, to handle attacking and object removing respectively. We will also expand EnemyAI to make NPCs more responsive. Below is the screenshot for Chapter 7.

IMAGE: Chapter 7 screenshot

Attack NPC

Check out commit: 387caa2.

Add PCAttack as a child node to PCMove. Attach PCAttack.gd to it. PCAttack.gd has a public method attack() and it will be called by PCMove._try_move().

# PCAttack.gd

func attack(group_name: String, x: int, y: int) -> void:
    if not _ref_DungeonBoard.has_sprite(group_name, x, y):
        return
    print("Attack.")
    _ref_Schedule.end_turn()


# PCMove.gd

const PC_ATTACK: String = "PCAttack"


func _try_move(x: int, y: int) -> void:
    # The reset remains the same.
    elif _ref_DungeonBoard.has_sprite(_new_GroupName.DWARF, x, y):
        set_process_unhandled_input(false)
        get_node(PC_ATTACK).attack(_new_GroupName.DWARF, x, y)

Remove NPC

Check out commit: 2eff140.

Removing is triggered inside PCAttack.attack(). The unnamed method then emits a signal. Any potential receiver removes a reference to the NPC from the game. As you can see, the removing job involves three steps. Define a method. Connect the signal. Remove references. First, add RemoveObject to MainScene and attach RemoveObject.gd to it. Then let PCAttack.attack() call RemoveObject.remove().

# RemoveObject.gd

signal sprite_removed(remove_sprite, group_name, x, y)


func remove(group_name: String, x: int, y: int) -> void:
    var sprite: Sprite = _ref_DungeonBoard.get_sprite(group_name, x, y)

    emit_signal("sprite_removed", sprite, group_name, x, y)
    sprite.queue_free()


# PCAttack.gd

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()
    print("Attack.")

The signal sprite_removed should be connected to DungeonBoard and Schedule.

# DungeonBoard.gd

func _on_RemoveObject_sprite_removed(_sprite: Sprite, group_name: String,
        x: int, y: int) -> void:
    _sprite_dict[group_name][x][y] = null


# Schedule.gd

func _on_RemoveObject_sprite_removed(reomve_sprite: Sprite,
    _group_name: String, _x: int, _y: int) -> void:

    var current_sprite: Sprite = _get_current()

    _actors.erase(reomve_sprite)
    _pointer = _actors.find(current_sprite)

Enemy AI

By adding a few lines of code to EnemyAI.gd, NPCs now print a message in the output panel when PC is nearby.

# EnemyAI.gd

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):
        print("Too close!")
    _ref_Schedule.end_turn()


func _pc_is_close(source: Sprite, target: Sprite) -> bool:
    var source_pos: Array = _new_ConvertCoord.vector_to_array(source.position)
    var target_pos: Array = _new_ConvertCoord.vector_to_array(target.position)
    var delta_x: int = abs(source_pos[0] - target_pos[0]) as int
    var delta_y: int = abs(source_pos[1] - target_pos[1]) as int

    return delta_x + delta_y < 2

Clone this wiki locally