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

03: Create A Static Dungeon

Source code.

At the end of this chapter, your dungeon will be filled with floors, walls and actors.

IMAGE: A static dungeon

Create Sprites From A Tilemap

First of all, add a font and a tilemap to resource folder. The GUI font, Fira Code, is created by Nikita Prokopov. The tileset, curses_vector, is created by DragonDePlatino for Dwarf Fortress. Create a new folder sprite which will be used to store sprite scenes.

IMAGE: Load a tilemap

Remove icon node from previous chapter. Add a Sprite node and name it as PC. Follow these steps to cut a sprite off the tilemap. (1) Select PC node. (2) In the Inspector tab, click Sprite -> Texture -> [empty]. In the dropdown menu, select New AtlasTexture. (3) Click Sprite -> Texture -> AtlasTexture. Click Atlas -> [empty]. In the dropdown menu, select Load. (4) Load res://resource/curses_vector_24x36.png.

IMAGE: Select a sprite

(5) Click TextureRegion on the Bottom Panel. (6) Click the up arrows on the lower right corner or press Shift+F12 to expand the panel. (7) Set Snap Mode to Grid Snap. The offsets and steps are 24x36, which corrsepond to the size of each tile (24px wide and 36px high). (8) Drag and drop a rectangular to select @ symbol.

There are two more post-processing steps. Change PC's color to ABB2BF. Save the node as a scene (PC.tscn) in sprite folder. Repeat these steps until your demo looks like the image below. Note that Floor sprite has a greyish color: 495162.

IMAGE: All sprites in the demo

Create Sprites From Scripts

Remove all nodes except the root. Add a new Node2D node to MainScene and name it as InitWorld. Attach a script (InitWorld.gd) to it. Before writing the first line of code, here is a reminder. I use static typing and stick to the style guide as much as possible. However, when my mind fails me and my fingers betray me, you shall not pass the wide gate. <('o')=|~~~B

It is faily simple to instance a PC sprite (actually it is a packed scene), place it at (100, 100) and add it to group pc.

# InitWorld.gd

func _ready() -> void:
    var new_sprite := preload("res://sprite/PC.tscn").instance() as Sprite
    new_sprite.position = Vector2(100, 100)
    new_sprite.add_to_group("pc")

    add_child(new_sprite)

In order to create many more sprites, put them at different positions and add them to various groups, we need to satisify three requirements.

  • Add a private function to InitWorld.gd for creating sprites.
  • Find a way to convert 0, 0 (a pair of integers that represent the top left grid in the dungeon) to Vector2(100, 100) (the Vector position used by sprites).
  • Find a way to avoid typing or copying the string pc.

Start from the last requirement. Since GDScripts can be loaded as resources just as you load an image or a packed scene, a possible solution is to store the string pc as a constant in a script and load the script inside InitWorld.gd.

Make a new folder library to store helper scripts. Add a GDScript resource GroupName.gd to the folder.

# GroupName.gd

const PC: String = "pc"


# InitWorld.gd

const Player := preload("res://sprite/PC.tscn")

var _new_GroupName := preload("res://library/GroupName.gd").new()


func _ready() -> void:
    var new_sprite := Player.instance() as Sprite
    new_sprite.position = Vector2(100, 100)
    new_sprite.add_to_group(_new_GroupName.PC)

    add_child(new_sprite)

As for the second requirement, add another GDScript resource ConvertCoord.gd to library.

# ConvertCoord.gd

const START_X: int = 50
const START_Y: int = 54
const STEP_X: int = 26
const STEP_Y: int = 34


func vector_to_array(vector_coord: Vector2) -> Array:
    pass


func index_to_vector(x: int, y: int,
        x_offset: int = 0, y_offset: int = 0) -> Vector2:

    pass

Try to implement these functions yourself. The constants define the top left grid in the dungeon and the width and height of each grid. You might have noticed that in the first image, two arrows appear outside the dungeon. That's why we need x_offset and y_offset.

The helper script enables us to generate pc in the corner of the dungeon like this.

# InitWorld.gd

new_sprite.position = _new_ConvertCoord.index_to_vector(0, 0)

The first requirement should be easy to meet. Implement _create_sprite() yourself.

# InitWorld.gd

const Player := preload("res://sprite/PC.tscn")

var _new_GroupName := preload("res://library/GroupName.gd").new()
var _new_ConvertCoord := preload("res://library/ConvertCoord.gd").new()


func _ready() -> void:
    _create_sprite(Player, _new_GroupName.PC, 0, 0)


func _create_sprite(prefab: PackedScene, group: String, x: int, y: int,
        x_offset: int = 0, y_offset: int = 0) -> void:

    pass

Now that you know how to instance one sprite, with the help of res://library/DungeonSize.gd, you should be able to expand InitWorld.gd to generate the full dungeon as shown in the first image.

# DungeonSize.gd

const MAX_X: int = 21
const MAX_Y: int = 15

const CENTER_X: int = 10
const CENTER_Y: int = 7

const ARROW_MARGIN: int = 32

One more thing. If you happen to create wall sprites before floor, the grey dot appears in front of the wall sign #. To solve this problem, simply set the Z Index of wall, dwarf and pc to 1. Let floor's Z Index remain to be 0.

Clone this wiki locally