Now that the level is complete, attach a script to create the level behavior. This script will first scan the Items map to spawn any enemies and collectibles. It will also serve to monitor for events that occur during gameplay, such as picking up a key or running into an enemy:
extends Node2D
export (PackedScene) var Enemy
export (PackedScene) var Pickup
onready var items = $Items
var doors = []
The first two variables contain references to the scenes that will need to be instanced from the Items map. Since that particular map node will be referenced frequently, you can cache the $Items lookup in a variable to save some time. Finally, an array called doors will contain the door location(s) found on the map.
Save the script and drag the Enemy.tscn and Pickup.tscn files into their respective properties in the Inspector.
Now, add the following code for _ready():
func _ready():
randomize()
$Items.hide()
set_camera_limits()
var door_id = $Walls.tile_set.find_tile_by_name('door_red')
for cell in $Walls.get_used_cells_by_id(door_id):
doors.append(cell)
spawn_items()
$Player.connect('dead', self, 'game_over')
$Player.connect('grabbed_key', self, '_on_Player_grabbed_key')
$Player.connect('win', self, '_on_Player_win')
The function starts by ensuring that the Items tilemap is hidden. You don't want the player to see those tiles; they exist so the script can detect where to spawn items.
Next, the camera limits must be set, ensuring that it can't scroll past the edges of the map. You'll create a function to handle that (see the following code).
When the player finds a key, the door(s) need to be opened, so the next part searches the Walls map for any door_red tiles and stores them in an array. Note that you must first find the tile's id from the TileSet, because the cells of the TileMap only contain ID numbers that refer to the tile set.
More on the spawn_items() function follows.
Finally, the Player signals are all connected to functions that will process their results.
Here's how to set the camera limits to match the size of the map:
func set_camera_limits():
var map_size = $Ground.get_used_rect()
var cell_size = $Ground.cell_size
$Player/Camera2D.limit_left = map_size.position.x * cell_size.x
$Player/Camera2D.limit_top = map_size.position.y * cell_size.y
$Player/Camera2D.limit_right = map_size.end.x * cell_size.x
$Player/Camera2D.limit_bottom = map_size.end.y * cell_size.y
get_used_rect() returns a Vector2 containing the size of the Ground layer in cells. Multiplying this by the cell_size gives the total map size in pixels, which is used to set the four limit values on the Camera node. Setting these limits ensures you won't see any dead space outside the map when you move near the edge.
Now, add the spawn_items() function:
func spawn_items():
for cell in items.get_used_cells():
var id = items.get_cellv(cell)
var type = items.tile_set.tile_get_name(id)
var pos = items.map_to_world(cell) + items.cell_size/2
match type:
'slime_spawn':
var s = Enemy.instance()
s.position = pos
s.tile_size = items.cell_size
add_child(s)
'player_spawn':
$Player.position = pos
$Player.tile_size = items.cell_size
'coin', 'key_red', 'star':
var p = Pickup.instance()
p.init(type, pos)
add_child(p)
This function looks for the tiles in the Items layer, returned by get_used_cells(). Each cell has an id that maps to a name in the TileSet (the names that were assigned to each tile when the TileSet was made). If you made your own tile set, make sure you use the names that match your tiles in this function. The names used in the preceding code match the tile set that was included in the asset download.
map_to_world() converts the tile map position to pixel coordinates. This gives you the upper-left corner of the tile, so then you must add one half-size tile to find the center of the tile. Then, depending on what tile was found, the matching item object is instanced.
Finally, add the three functions for the player signals:
func game_over():
pass
func _on_Player_win():
pass
func _on_Player_grabbed_key():
for cell in doors:
$Walls.set_cellv(cell, -1)
The player signals dead and win should end the game and go to a Game Over screen (which you haven't created yet). Since you can't write the code for those functions yet, use pass for the time being. The key pickup signal should remove any door tiles (by setting their tile index to -1, which means an empty tile).