Welcome to part 1 of this tutorial! This series will help you create your very first roguelike game, written in Python!
The 2021 tutorial is largely based off the 2020 tutorial, and is primarily a smaller update rather than a larger rewrite that the previous versions were.
This part assumes that you have either checked Part 0 or are already familiar with Python and Python-tcod. If not, be sure to check that page, and make sure that you’ve got Python and TCOD installed, as well as having an IDE or editor ready.
Assuming that you’ve done all that, let’s get started.
We will start by setting up the following directory structure.
The font from Part 0 will go into a data
directory, then main.py
will be created as an entry point.
/data/dejavu16x16_gs_tc.png
/main.py
/main.py
is the entry point of the program. You can use python main.py
to start the program after the following is implemented.
#!/usr/bin/env python3
# main.py
import tcod
MOVE_KEYS = {
tcod.event.K_UP: (0, -1),
tcod.event.K_DOWN: (0, 1),
tcod.event.K_LEFT: (-1, 0),
tcod.event.K_RIGHT: (1, 0),
}
def main() -> None:
screen_width = 80
screen_height = 50
player_x: int = screen_width // 2
player_y: int = screen_height // 2
tileset = tcod.tileset.load_tilesheet("data/dejavu16x16_gs_tc.png", 32, 8, tcod.tileset.CHARMAP_TCOD)
with tcod.context.new(
columns=screen_width,
rows=screen_height,
tileset=tileset,
title="Yet Another Roguelike Tutorial",
vsync=True,
) as context:
root_console = tcod.Console(screen_width, screen_height, order="F")
while True:
root_console.clear()
root_console.print(x=player_x, y=player_y, string="@")
context.present(root_console)
for event in tcod.event.wait():
if isinstance(event, tcod.event.Quit):
raise SystemExit(0)
if isinstance(event, tcod.event.KeyDown):
if event.sym in MOVE_KEYS:
delta_x, delta_y = MOVE_KEYS[event.sym]
dest_x = player_x + delta_x
dest_y = player_y + delta_y
if 0 <= dest_x < screen_width and 0 <= dest_y < screen_height:
player_x, player_y = dest_x, dest_y
if __name__ == "__main__":
main()
#!/usr/bin/env python3
is a shebang and must be the first line to be useful.
It is normally used to make scripts executable on Linux, but is also used by the Windows Python launcher.
tcod
is imported along with the two other modules we’ve added.
MOVE_KEYS
is a Python dictionary mapping of tcod KeySym’s to in-game directions.
This will be expanded in later parts.
The main
function will be the entry point of the program.
There’s nothing special about the name other than the terminology, the special nature of this function comes from the __name__ == "__main__"
condition at the bottom of the script which is only True when the script is directly run, compared to importing main from an interactive prompt.
main
starts by setting the screen size, then sets the player position to the center of the screen.
The floor division operator is used so that the numbers don’t promote to a float type.
The tileset is loaded with tcod.tileset.load_tilesheet The Python-tcod docs have a character reference to keep track of which layouts have what glyphs.
tcod.context.new is used to setup the window and returns a Context instance.
Contexts must be closed once you’re done with them, but the with
statement will do this automatically when exiting the with-block.
Then a tcod.Console is created with the same size that was given to tcod.context.new
,
order="F"
sets the console arrays to be indexed in x, y
order.
This is a convenient way to handle array indexes so we’ll use order="F"
a lot when working with NumPy.
You might wonder why order="F"
isn’t the default and there is an explanation for that.
These arrays are not being used yet.
Now with while True:
the game-loop begins, with the only way of existing this loop normally being the SystemExit
exceptions implemented later.
root_console
is cleared, then the player position is printed to root_console
, then root_console
is displayed using context.present(root_console)
.
The for-loop waits for there to be events then iterates over all events until none are left. This is an efficient way to handle events when the game doesn’t have real-time animations or mechanics. If you have real-time effects then you should replace tcod.event.wait with tcod.event.get.
isinstance is being used here to sort events by type.
This has an effect on type-checking, where anything within an isinstance
branch can be assumed to actually be that type, much like a type cast in any other language.
Trying to close the window will result in a Quit
event.
When this happens we will raise SystemExit which will propagate and terminate the script.
For KeyDown
events we check if the key is in the MOVE_KEYS
dictionary then try to move by that amount.
If the destination is on the screen then the player moves to that spot.
You can see the current progress of this code in its entirety here.
If you want to distribute your game then you can set that up now or at any time later.