-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
We will build a small game: a player that walks around a walled room, with a camera that follows and a HUD. Every snippet here runs as written.
pip install texastoasttexastoast needs only the standard library plus tkinter. If import tkinter
fails, install your platform's tk package (sudo apt install python3-tk on
Debian/Ubuntu; it ships with the python.org installers on macOS and Windows).
from texastoast import Game
game = Game(title="My Game", width=400, height=300, fps=30)
game.start()That is a working game: an empty window that closes cleanly. start() blocks
until the window is closed.
CanvasRenderer draws onto the game's canvas. Give it an update and a
render:
from texastoast import Game, CanvasRenderer
game = Game(title="My Game", width=400, height=300, fps=30)
renderer = CanvasRenderer(game.canvas, 400, 300)
def update(dt):
pass
def render():
renderer.clear()
renderer.draw_rect(50, 50, 20, 20, "#e94560")
game.set_update(update)
game.set_render(render)
game.start()clear() every frame, then draw. The canvas keeps whatever you put on it
otherwise.
A TileMap is a grid of integers plus a tile size. Which ids block movement is
up to you:
from texastoast import TileMap
GRID = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 1, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
tilemap = TileMap(GRID, tile_size=32, solid_tiles={1})
TILE_COLORS = {0: "#7cb342", 1: "#5d4037"} # grass, wallDraw it with draw_tilemap. A tile is drawn when its id appears in the color
map; ids you leave out stay transparent:
def render():
renderer.clear()
renderer.draw_tilemap(tilemap, TILE_COLORS)Entity holds a position, a size and a speed in pixels per second.
move() takes the frame's dt and, optionally, a tile map to collide against:
from texastoast import Entity, KeyboardInput
keyboard = KeyboardInput(game.root)
player = Entity(x=48, y=48, width=20, height=20, speed=120)
def update(dt):
state = keyboard.poll()
player.move(state.dx, state.dy, dt, tilemap)Spawn the player somewhere walkable. x=48, y=48 with tile_size=32 puts it in
tile (1, 1), which is 0 in the grid above. Dropping an entity inside a solid
tile leaves it stuck — nothing can push it out.
Collision handles the rest: the player slides along walls instead of catching on them, stops flush against them, and cannot tunnel through one at high speed.
For a map larger than the window, follow the player:
def update(dt):
state = keyboard.poll()
player.move(state.dx, state.dy, dt, tilemap)
renderer.camera.follow(
player.center_x, player.center_y,
map_width=tilemap.width, map_height=tilemap.height, dt=dt,
)map_width/map_height clamp the camera so it never shows past the map edge.
Every draw_* call except draw_hud_text is camera-relative.
HUD elements are screen-space and ignore the camera:
from texastoast.ui import HUD
hud = HUD(renderer)
hud.add_stat("hp", "HP", value=100, max_value=100, color="#e94560")
hud.add_text("score", "Score: 0", 300, 8, fill="#fdd835")
def render():
renderer.clear()
renderer.draw_tilemap(tilemap, TILE_COLORS)
renderer.draw_rect(player.x, player.y, player.width, player.height, "#e94560")
hud.render() # last, so it draws on topUpdate values with hud.set_stat("hp", 75) and hud.set_text("score", "Score: 10").
from texastoast import Game, CanvasRenderer, TileMap, Entity, KeyboardInput
from texastoast.ui import HUD
GRID = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 1, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
TILE_COLORS = {0: "#7cb342", 1: "#5d4037"}
game = Game(title="My Game", width=400, height=300, fps=30)
renderer = CanvasRenderer(game.canvas, 400, 300)
keyboard = KeyboardInput(game.root)
hud = HUD(renderer)
game.on_close(keyboard.destroy)
tilemap = TileMap(GRID, tile_size=32, solid_tiles={1})
player = Entity(x=48, y=48, width=20, height=20, speed=120)
hud.add_stat("hp", "HP", value=100, max_value=100, color="#e94560")
def update(dt):
state = keyboard.poll()
player.move(state.dx, state.dy, dt, tilemap)
renderer.camera.follow(
player.center_x, player.center_y,
map_width=tilemap.width, map_height=tilemap.height, dt=dt,
)
def render():
renderer.clear()
renderer.draw_tilemap(tilemap, TILE_COLORS)
renderer.draw_rect(player.x, player.y, player.width, player.height, "#e94560")
hud.render()
game.set_update(update)
game.set_render(render)
game.start()Arrow keys or WASD to move.
The same shape extends to the other widgets, with one rule: they are
frame-driven. Construct them from the renderer, advance the dialogue from
update, and draw all of them from render:
from texastoast.ui import DialogueBox
dialogue = DialogueBox(renderer)
dialogue.show("Welcome, traveler!", speaker="Old Wizard")
def update(dt):
dialogue.update(dt) # advances the typewriter
...
def render():
renderer.clear()
...
hud.render()
dialogue.render() # after clear(), every frameMiss the render() call and the box never appears; miss update(dt) and the
text never types. See UI Components.
-
Core Concepts — why
dtmatters and how the loop behaves - Tile Maps and Collision — map files, collision rules
- UI Components — dialogue boxes and menus
- Hardware Dev Kit — controllers, without owning any
-
examples/game_template.pyin the repo — the same ideas with dialogue, a pause menu and stats already wired up
texastoast · PyPI · Apache-2.0