-
Notifications
You must be signed in to change notification settings - Fork 16
Detecting and handling collision is the most complicated part in the demo. Thus we divide it into two chapters. In this chapter, we restrict PC's movement inside the dungeon and outside walls. An invalid movement does not end PC's current turn. In Chapter 7, PC will be able to bump attack NPCs. PC's turn ends after attacking. We also need to remove dead NPCs. Below is the screenshot for Chapter 6.
Check out commit: 54dc879.
First, comment print()
lines in PCMove.gd
and Schedule.gd
so as not to fill the output board with unwanted text. Add DungeonBoard
(Node2D
node) to MainScene
and attach DungeonBoard.gd
to it.
# DungeonBoard.gd
func is_inside_dungeon(x: int, y: int) -> bool:
return (x > -1) and (x < _new_DungeonSize.MAX_X) \
and (y > -1) and (y < _new_DungeonSize.MAX_Y)
Let PCMove._try_move()
call DungeonBoard.is_inside_dungeon()
to forbid invalid movement.
# 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)
_try_move(target[0], target[1])
func _try_move(x: int, y: int) -> void:
if not _ref_DungeonBoard.is_inside_dungeon(x, y):
print("Cannot leave dungeon.")
else:
set_process_unhandled_input(false)
_pc.position = _new_ConvertCoord.index_to_vector(x, y)
_ref_Schedule.end_turn()
DungeonBoard.gd
does more things than analyzing coordinates. Just like a chess board records the position of every chess piece, DungeonBoard
records every dungeon sprite's position. We use a dictionary to mimic a 2D array. The dictionary's key is an integer representing the row, and its value is an array filled with sprites. Since we need to record two types of sprites, Wall
and Dwarf
, there should be two such boards. In conclusion, the data structure of DungeonBoard._sprite_dict
is like this:
_sprite_dict: Dictionary<group_name: String,
Dictionary<row: int, sprites: Array>>
In DungeonBoard.gd
, first we initialize the dictionary. Then fill it with sprites by receiving sprite_created
. The last step is to add two public methods, has_sprite()
and get_sprite()
, to inspect its content.
# DungeonBoard.gd
var _sprite_dict: Dictionary
func _ready() -> void:
_init_dict()
func has_sprite(group_name: String, x: int, y: int) -> bool:
return get_sprite(group_name, x, y) != null
func get_sprite(group_name: String, x: int, y: int) -> Sprite:
if not is_inside_dungeon(x, y):
return null
return _sprite_dict[group_name][x][y]
func _on_InitWorld_sprite_created(new_sprite: Sprite) -> void:
var pos: Array
var group: String
if new_sprite.is_in_group(_new_GroupName.DWARF):
group = _new_GroupName.DWARF
elif new_sprite.is_in_group(_new_GroupName.WALL):
group = _new_GroupName.WALL
else:
return
pos = _new_ConvertCoord.vector_to_array(new_sprite.position)
_sprite_dict[group][pos[0]][pos[1]] = new_sprite
func _init_dict() -> void:
var groups = [_new_GroupName.DWARF, _new_GroupName.WALL]
for g in groups:
_sprite_dict[g] = {}
for x in range(_new_DungeonSize.MAX_X):
_sprite_dict[g][x] = []
_sprite_dict[g][x].resize(_new_DungeonSize.MAX_Y)
Let PCMove._try_move()
to detect wall sprites.
# PCMove.gd
func _try_move(x: int, y: int) -> void:
if not _ref_DungeonBoard.is_inside_dungeon(x, y):
print("Cannot leave dungeon.")
elif _ref_DungeonBoard.has_sprite(_new_GroupName.WALL, x, y):
print("Cannot pass wall.")
else:
# The rest remains unchanged.
Printing text to the output panel is convenient for developers, while not so obvious to players. We will change this in Chapter 8.