texastoast 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. texastoast-0.1.0/.gitignore +13 -0
  2. texastoast-0.1.0/LICENSE +17 -0
  3. texastoast-0.1.0/PKG-INFO +235 -0
  4. texastoast-0.1.0/README.md +210 -0
  5. texastoast-0.1.0/examples/game_template.py +181 -0
  6. texastoast-0.1.0/examples/hello_world.py +51 -0
  7. texastoast-0.1.0/examples/magma_hub_demo.py +98 -0
  8. texastoast-0.1.0/examples/rpg_demo.py +180 -0
  9. texastoast-0.1.0/examples/sprite_demo.py +159 -0
  10. texastoast-0.1.0/examples/tilemap_demo.py +52 -0
  11. texastoast-0.1.0/pyproject.toml +37 -0
  12. texastoast-0.1.0/tests/test_camera.py +56 -0
  13. texastoast-0.1.0/tests/test_collision.py +55 -0
  14. texastoast-0.1.0/tests/test_entity.py +45 -0
  15. texastoast-0.1.0/tests/test_i2c.py +80 -0
  16. texastoast-0.1.0/tests/test_input.py +38 -0
  17. texastoast-0.1.0/tests/test_tilemap.py +68 -0
  18. texastoast-0.1.0/texastoast/__init__.py +55 -0
  19. texastoast-0.1.0/texastoast/core/__init__.py +13 -0
  20. texastoast-0.1.0/texastoast/core/config.py +18 -0
  21. texastoast-0.1.0/texastoast/core/game.py +70 -0
  22. texastoast-0.1.0/texastoast/core/loop.py +67 -0
  23. texastoast-0.1.0/texastoast/i2c/__init__.py +5 -0
  24. texastoast-0.1.0/texastoast/i2c/bus.py +116 -0
  25. texastoast-0.1.0/texastoast/i2c/hub.py +128 -0
  26. texastoast-0.1.0/texastoast/i2c/protocol.py +78 -0
  27. texastoast-0.1.0/texastoast/input/__init__.py +16 -0
  28. texastoast-0.1.0/texastoast/input/abstract.py +44 -0
  29. texastoast-0.1.0/texastoast/input/keyboard.py +47 -0
  30. texastoast-0.1.0/texastoast/input/magma_hub.py +76 -0
  31. texastoast-0.1.0/texastoast/render/__init__.py +16 -0
  32. texastoast-0.1.0/texastoast/render/camera.py +39 -0
  33. texastoast-0.1.0/texastoast/render/canvas.py +76 -0
  34. texastoast-0.1.0/texastoast/render/sprite.py +108 -0
  35. texastoast-0.1.0/texastoast/ui/__init__.py +5 -0
  36. texastoast-0.1.0/texastoast/ui/dialogue.py +133 -0
  37. texastoast-0.1.0/texastoast/ui/hud.py +111 -0
  38. texastoast-0.1.0/texastoast/ui/menu.py +153 -0
  39. texastoast-0.1.0/texastoast/world/__init__.py +5 -0
  40. texastoast-0.1.0/texastoast/world/collision.py +81 -0
  41. texastoast-0.1.0/texastoast/world/entity.py +56 -0
  42. texastoast-0.1.0/texastoast/world/tilemap.py +77 -0
  43. texastoast-0.1.0/tools/tile_editor.py +407 -0
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .venv/
10
+ venv/
11
+ .env
12
+ .pytest_cache/
13
+ .mypy_cache/
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 magmacrunch media
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.5
2
+ Name: texastoast
3
+ Version: 0.1.0
4
+ Summary: Python RPG engine and Magma Hub I2C layer for magmacrunch game systems
5
+ Author: magmacrunch media
6
+ License-Expression: Apache-2.0
7
+ License-File: LICENSE
8
+ Keywords: game,i2c,raspberry-pi,rpg,tkinter
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Games/Entertainment
18
+ Classifier: Topic :: System :: Hardware :: Hardware Drivers
19
+ Requires-Python: >=3.10
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest>=7.0; extra == 'dev'
22
+ Provides-Extra: hardware
23
+ Requires-Dist: smbus2>=0.6; extra == 'hardware'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # texastoast
27
+
28
+ Python RPG engine and Magma Hub I2C layer for magmacrunch game systems.
29
+
30
+ A tkinter-based 2D game engine inspired by [adenosine](https://github.com/magmacrunchmedia/adenosine), with I2C hardware abstraction for Raspberry Pi + Pico "Magma Hub" controllers.
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ # Basic install (keyboard-only, no hardware)
36
+ pip install -e .
37
+
38
+ # With I2C hardware support (Raspberry Pi)
39
+ pip install -e ".[hardware]"
40
+
41
+ # Development (includes pytest)
42
+ pip install -e ".[dev]"
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```python
48
+ from texastoast import Game, CanvasRenderer, TileMap, Entity, KeyboardInput
49
+
50
+ game = Game(title="My Game", width=400, height=300, fps=30)
51
+ renderer = CanvasRenderer(game.canvas, 400, 300)
52
+ keyboard = KeyboardInput(game.root)
53
+
54
+ tilemap = TileMap([
55
+ [1, 1, 1, 1, 1],
56
+ [1, 0, 0, 0, 1],
57
+ [1, 1, 1, 1, 1],
58
+ ], tile_size=20, solid_tiles={1})
59
+
60
+ player = Entity(x=40, y=40, width=14, height=14, speed=100)
61
+
62
+ def update(dt):
63
+ state = keyboard.poll()
64
+ player.move(state.dx, state.dy, tilemap)
65
+ renderer.camera.follow(player.center_x, player.center_y,
66
+ map_width=tilemap.width, map_height=tilemap.height)
67
+
68
+ def render():
69
+ renderer.clear()
70
+ renderer.draw_tilemap(tilemap, {0: "#7cb342", 1: "#5d4037"})
71
+ renderer.draw_rect(player.x, player.y, player.width, player.height, "#e94560")
72
+
73
+ game.set_update(update)
74
+ game.set_render(render)
75
+ game.start()
76
+ ```
77
+
78
+ ## Examples
79
+
80
+ | Example | Description |
81
+ |---------|-------------|
82
+ | `examples/hello_world.py` | Minimal movement demo |
83
+ | `examples/tilemap_demo.py` | Walk around a larger map |
84
+ | `examples/sprite_demo.py` | Animated character sprites |
85
+ | `examples/rpg_demo.py` | NPCs, dialogue, menus, HUD |
86
+ | `examples/game_template.py` | Full game starting point |
87
+ | `examples/magma_hub_demo.py` | I2C controller input |
88
+ | `tools/tile_editor.py` | Tile map editor GUI |
89
+
90
+ ## API Reference
91
+
92
+ ### Core
93
+
94
+ ```python
95
+ from texastoast import Game, Config, GameLoop
96
+
97
+ game = Game(title="My Game", width=640, height=480, fps=30)
98
+ game.set_update(update_fn) # def update(dt: float): ...
99
+ game.set_render(render_fn) # def render(): ...
100
+ game.start()
101
+ ```
102
+
103
+ ### Rendering
104
+
105
+ ```python
106
+ from texastoast import CanvasRenderer, Camera
107
+
108
+ renderer = CanvasRenderer(game.canvas, 640, 480)
109
+ renderer.draw_tilemap(tilemap, {0: "#7cb342", 1: "#5d4037"})
110
+ renderer.draw_rect(x, y, w, h, color)
111
+ renderer.draw_image(x, y, photo_image)
112
+ renderer.draw_hud_text(x, y, text, fill="#fff", font=("Courier", 10))
113
+
114
+ # Camera
115
+ renderer.camera.follow(target_x, target_y, map_width=800, map_height=600)
116
+ renderer.camera.set_position(x, y)
117
+ ```
118
+
119
+ ### World
120
+
121
+ ```python
122
+ from texastoast import TileMap, Entity, AABB
123
+
124
+ # Tile map
125
+ tilemap = TileMap(grid_data, tile_size=16, solid_tiles={1, 2})
126
+ tilemap = TileMap.from_file("map.json", tile_size=16)
127
+ tilemap.save("map.json")
128
+ tilemap.get(col, row) # -> tile_id
129
+ tilemap.is_solid(col, row) # -> bool
130
+ tilemap.is_solid_at(world_x, world_y) # -> bool
131
+
132
+ # Entity
133
+ player = Entity(x=0, y=0, width=16, height=16, speed=100)
134
+ player.move(dx, dy, tilemap) # with collision
135
+ player.aabb # -> AABB for overlap checks
136
+ player.collides_with(other_entity) # -> bool
137
+ ```
138
+
139
+ ### Input
140
+
141
+ ```python
142
+ from texastoast import KeyboardInput, InputState
143
+
144
+ keyboard = KeyboardInput(game.root)
145
+ state = keyboard.poll()
146
+
147
+ state.up, state.down, state.left, state.right # bool
148
+ state.a, state.b, state.start, state.select # bool
149
+ state.dx, state.dy # float (-1, 0, 1)
150
+ state.is_any_direction() # bool
151
+ ```
152
+
153
+ ### I2C (Magma Hub)
154
+
155
+ ```python
156
+ from texastoast import I2CBus, MagmaHub, MagmaHubInput, CompositeInput
157
+
158
+ # Direct I2C
159
+ bus = I2CBus(1) # I2C bus number
160
+ hubs = MagmaHub.scan_buses(bus_numbers=[1])
161
+ hub = hubs[0]
162
+ hub.poll() # -> [ControllerState, ...]
163
+
164
+ # Input adapter (same interface as KeyboardInput)
165
+ hub_input = MagmaHubInput(hub, controller_index=0)
166
+ state = hub_input.poll()
167
+
168
+ # Auto-fallback composite
169
+ controls = CompositeInput(keyboard, hub_input)
170
+ state = controls.poll() # uses hub if connected, else keyboard
171
+ ```
172
+
173
+ ### UI
174
+
175
+ ```python
176
+ from texastoast.ui import DialogueBox, Menu, HUD
177
+
178
+ # Dialogue
179
+ dialogue = DialogueBox(game.canvas, 640, 480)
180
+ dialogue.show("Hello, world!", speaker="NPC", on_complete=callback)
181
+ dialogue.dismiss()
182
+
183
+ # Menu
184
+ menu = Menu(game.canvas, 640, 480)
185
+ menu.show(["Play", "Settings", "Quit"],
186
+ on_select=lambda i, label: print(label),
187
+ on_cancel=lambda: menu.hide())
188
+ menu.move_up()
189
+ menu.move_down()
190
+ menu.confirm()
191
+
192
+ # HUD
193
+ hud = HUD(game.canvas, 640, 480)
194
+ hud.add_stat("hp", "HP", value=100, max_value=100, color="#e94560")
195
+ hud.set_stat("hp", 75)
196
+ hud.add_text("score", "Score: 0", 10, 10, fill="#fdd835")
197
+ hud.set_text("score", "Score: 100")
198
+ hud.render()
199
+ ```
200
+
201
+ ## Magma Hub Hardware
202
+
203
+ The Magma Hub is a Raspberry Pico acting as an I2C slave, providing controller input (buttons + joystick) to the Pi master. texastoast abstracts this hardware so games don't need to know about I2C details.
204
+
205
+ ### Protocol
206
+
207
+ | Address | Data | Description |
208
+ |---------|------|-------------|
209
+ | 0x00 | 8-bit | Button status (bitmask) |
210
+ | 0x01 | 8-bit | Joystick status |
211
+
212
+ ### Button Bitmask
213
+
214
+ | Bit | Button |
215
+ |-----|--------|
216
+ | 0 | Up |
217
+ | 1 | Down |
218
+ | 2 | Left |
219
+ | 3 | Right |
220
+ | 4 | A |
221
+ | 5 | B |
222
+ | 6 | Start |
223
+ | 7 | Select |
224
+
225
+ ## Design Philosophy
226
+
227
+ - **No opinions** — engines provide systems, you wire them together
228
+ - **Configurable** — pass callbacks and data, don't inherit from base classes
229
+ - **Tiny** — small, focused modules with minimal dependencies
230
+ - **Graceful fallback** — I2C hardware is optional, keyboard always works
231
+ - **Testable** — game logic doesn't depend on tkinter
232
+
233
+ ## License
234
+
235
+ Apache-2.0. Copyright 2026 magmacrunch media.
@@ -0,0 +1,210 @@
1
+ # texastoast
2
+
3
+ Python RPG engine and Magma Hub I2C layer for magmacrunch game systems.
4
+
5
+ A tkinter-based 2D game engine inspired by [adenosine](https://github.com/magmacrunchmedia/adenosine), with I2C hardware abstraction for Raspberry Pi + Pico "Magma Hub" controllers.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ # Basic install (keyboard-only, no hardware)
11
+ pip install -e .
12
+
13
+ # With I2C hardware support (Raspberry Pi)
14
+ pip install -e ".[hardware]"
15
+
16
+ # Development (includes pytest)
17
+ pip install -e ".[dev]"
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```python
23
+ from texastoast import Game, CanvasRenderer, TileMap, Entity, KeyboardInput
24
+
25
+ game = Game(title="My Game", width=400, height=300, fps=30)
26
+ renderer = CanvasRenderer(game.canvas, 400, 300)
27
+ keyboard = KeyboardInput(game.root)
28
+
29
+ tilemap = TileMap([
30
+ [1, 1, 1, 1, 1],
31
+ [1, 0, 0, 0, 1],
32
+ [1, 1, 1, 1, 1],
33
+ ], tile_size=20, solid_tiles={1})
34
+
35
+ player = Entity(x=40, y=40, width=14, height=14, speed=100)
36
+
37
+ def update(dt):
38
+ state = keyboard.poll()
39
+ player.move(state.dx, state.dy, tilemap)
40
+ renderer.camera.follow(player.center_x, player.center_y,
41
+ map_width=tilemap.width, map_height=tilemap.height)
42
+
43
+ def render():
44
+ renderer.clear()
45
+ renderer.draw_tilemap(tilemap, {0: "#7cb342", 1: "#5d4037"})
46
+ renderer.draw_rect(player.x, player.y, player.width, player.height, "#e94560")
47
+
48
+ game.set_update(update)
49
+ game.set_render(render)
50
+ game.start()
51
+ ```
52
+
53
+ ## Examples
54
+
55
+ | Example | Description |
56
+ |---------|-------------|
57
+ | `examples/hello_world.py` | Minimal movement demo |
58
+ | `examples/tilemap_demo.py` | Walk around a larger map |
59
+ | `examples/sprite_demo.py` | Animated character sprites |
60
+ | `examples/rpg_demo.py` | NPCs, dialogue, menus, HUD |
61
+ | `examples/game_template.py` | Full game starting point |
62
+ | `examples/magma_hub_demo.py` | I2C controller input |
63
+ | `tools/tile_editor.py` | Tile map editor GUI |
64
+
65
+ ## API Reference
66
+
67
+ ### Core
68
+
69
+ ```python
70
+ from texastoast import Game, Config, GameLoop
71
+
72
+ game = Game(title="My Game", width=640, height=480, fps=30)
73
+ game.set_update(update_fn) # def update(dt: float): ...
74
+ game.set_render(render_fn) # def render(): ...
75
+ game.start()
76
+ ```
77
+
78
+ ### Rendering
79
+
80
+ ```python
81
+ from texastoast import CanvasRenderer, Camera
82
+
83
+ renderer = CanvasRenderer(game.canvas, 640, 480)
84
+ renderer.draw_tilemap(tilemap, {0: "#7cb342", 1: "#5d4037"})
85
+ renderer.draw_rect(x, y, w, h, color)
86
+ renderer.draw_image(x, y, photo_image)
87
+ renderer.draw_hud_text(x, y, text, fill="#fff", font=("Courier", 10))
88
+
89
+ # Camera
90
+ renderer.camera.follow(target_x, target_y, map_width=800, map_height=600)
91
+ renderer.camera.set_position(x, y)
92
+ ```
93
+
94
+ ### World
95
+
96
+ ```python
97
+ from texastoast import TileMap, Entity, AABB
98
+
99
+ # Tile map
100
+ tilemap = TileMap(grid_data, tile_size=16, solid_tiles={1, 2})
101
+ tilemap = TileMap.from_file("map.json", tile_size=16)
102
+ tilemap.save("map.json")
103
+ tilemap.get(col, row) # -> tile_id
104
+ tilemap.is_solid(col, row) # -> bool
105
+ tilemap.is_solid_at(world_x, world_y) # -> bool
106
+
107
+ # Entity
108
+ player = Entity(x=0, y=0, width=16, height=16, speed=100)
109
+ player.move(dx, dy, tilemap) # with collision
110
+ player.aabb # -> AABB for overlap checks
111
+ player.collides_with(other_entity) # -> bool
112
+ ```
113
+
114
+ ### Input
115
+
116
+ ```python
117
+ from texastoast import KeyboardInput, InputState
118
+
119
+ keyboard = KeyboardInput(game.root)
120
+ state = keyboard.poll()
121
+
122
+ state.up, state.down, state.left, state.right # bool
123
+ state.a, state.b, state.start, state.select # bool
124
+ state.dx, state.dy # float (-1, 0, 1)
125
+ state.is_any_direction() # bool
126
+ ```
127
+
128
+ ### I2C (Magma Hub)
129
+
130
+ ```python
131
+ from texastoast import I2CBus, MagmaHub, MagmaHubInput, CompositeInput
132
+
133
+ # Direct I2C
134
+ bus = I2CBus(1) # I2C bus number
135
+ hubs = MagmaHub.scan_buses(bus_numbers=[1])
136
+ hub = hubs[0]
137
+ hub.poll() # -> [ControllerState, ...]
138
+
139
+ # Input adapter (same interface as KeyboardInput)
140
+ hub_input = MagmaHubInput(hub, controller_index=0)
141
+ state = hub_input.poll()
142
+
143
+ # Auto-fallback composite
144
+ controls = CompositeInput(keyboard, hub_input)
145
+ state = controls.poll() # uses hub if connected, else keyboard
146
+ ```
147
+
148
+ ### UI
149
+
150
+ ```python
151
+ from texastoast.ui import DialogueBox, Menu, HUD
152
+
153
+ # Dialogue
154
+ dialogue = DialogueBox(game.canvas, 640, 480)
155
+ dialogue.show("Hello, world!", speaker="NPC", on_complete=callback)
156
+ dialogue.dismiss()
157
+
158
+ # Menu
159
+ menu = Menu(game.canvas, 640, 480)
160
+ menu.show(["Play", "Settings", "Quit"],
161
+ on_select=lambda i, label: print(label),
162
+ on_cancel=lambda: menu.hide())
163
+ menu.move_up()
164
+ menu.move_down()
165
+ menu.confirm()
166
+
167
+ # HUD
168
+ hud = HUD(game.canvas, 640, 480)
169
+ hud.add_stat("hp", "HP", value=100, max_value=100, color="#e94560")
170
+ hud.set_stat("hp", 75)
171
+ hud.add_text("score", "Score: 0", 10, 10, fill="#fdd835")
172
+ hud.set_text("score", "Score: 100")
173
+ hud.render()
174
+ ```
175
+
176
+ ## Magma Hub Hardware
177
+
178
+ The Magma Hub is a Raspberry Pico acting as an I2C slave, providing controller input (buttons + joystick) to the Pi master. texastoast abstracts this hardware so games don't need to know about I2C details.
179
+
180
+ ### Protocol
181
+
182
+ | Address | Data | Description |
183
+ |---------|------|-------------|
184
+ | 0x00 | 8-bit | Button status (bitmask) |
185
+ | 0x01 | 8-bit | Joystick status |
186
+
187
+ ### Button Bitmask
188
+
189
+ | Bit | Button |
190
+ |-----|--------|
191
+ | 0 | Up |
192
+ | 1 | Down |
193
+ | 2 | Left |
194
+ | 3 | Right |
195
+ | 4 | A |
196
+ | 5 | B |
197
+ | 6 | Start |
198
+ | 7 | Select |
199
+
200
+ ## Design Philosophy
201
+
202
+ - **No opinions** — engines provide systems, you wire them together
203
+ - **Configurable** — pass callbacks and data, don't inherit from base classes
204
+ - **Tiny** — small, focused modules with minimal dependencies
205
+ - **Graceful fallback** — I2C hardware is optional, keyboard always works
206
+ - **Testable** — game logic doesn't depend on tkinter
207
+
208
+ ## License
209
+
210
+ Apache-2.0. Copyright 2026 magmacrunch media.
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ """Game template — a starting point for new texastoast games.
3
+
4
+ This demonstrates the full feature set:
5
+ - Game loop with fixed timestep
6
+ - Tile map with collision
7
+ - Camera following player
8
+ - Keyboard input
9
+ - HUD with stats
10
+ - Dialogue system
11
+ - Pause menu
12
+
13
+ Copy this file and modify it to build your own game.
14
+ """
15
+
16
+ from texastoast import Game, CanvasRenderer, TileMap, Entity, KeyboardInput
17
+ from texastoast.ui import DialogueBox, Menu, HUD
18
+
19
+ # ── Config ──────────────────────────────────────────────────────────
20
+
21
+ SCREEN_W = 400
22
+ SCREEN_H = 300
23
+ TILE_SIZE = 20
24
+ FPS = 30
25
+ PLAYER_SPEED = 100
26
+
27
+ # ── Colors ──────────────────────────────────────────────────────────
28
+
29
+ TILE_COLORS = {
30
+ 0: "#7cb342", # grass
31
+ 1: "#5d4037", # wall
32
+ 2: "#1e88e5", # water
33
+ 3: "#fdd835", # path
34
+ }
35
+
36
+ # ── Map ─────────────────────────────────────────────────────────────
37
+
38
+ LEVEL_1 = [
39
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
40
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
41
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
42
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
43
+ [1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1],
44
+ [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
45
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
46
+ [1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1],
47
+ [1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1],
48
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
49
+ [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
50
+ [1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1],
51
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
52
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
53
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
54
+ ]
55
+
56
+ # ── Init ────────────────────────────────────────────────────────────
57
+
58
+ game = Game(title="texastoast game template", width=SCREEN_W, height=SCREEN_H, fps=FPS)
59
+ renderer = CanvasRenderer(game.canvas, SCREEN_W, SCREEN_H)
60
+ keyboard = KeyboardInput(game.root)
61
+ dialogue = DialogueBox(game.canvas, SCREEN_W, SCREEN_H)
62
+ menu = Menu(game.canvas, SCREEN_W, SCREEN_H)
63
+ hud = HUD(game.canvas, SCREEN_W, SCREEN_H)
64
+
65
+ tilemap = TileMap(LEVEL_1, tile_size=TILE_SIZE, solid_tiles={1, 2})
66
+ player = Entity(x=60, y=60, width=14, height=14, speed=PLAYER_SPEED)
67
+
68
+ # ── Game state ──────────────────────────────────────────────────────
69
+
70
+ paused = False
71
+ showing_dialogue = False
72
+ hp = 100
73
+ xp = 0
74
+ score = 0
75
+
76
+ hud.add_stat("hp", "HP", value=hp, max_value=100, color="#e94560")
77
+ hud.add_stat("xp", "XP", value=xp, max_value=100, color="#4fc3f7")
78
+ hud.add_text("score", "Score: 0", SCREEN_W - 120, 4, fill="#fdd835")
79
+ hud.add_text("pos", "", 4, SCREEN_H - 16, fill="#666666", font=("Courier", 8))
80
+
81
+
82
+ # ── Input handling ──────────────────────────────────────────────────
83
+
84
+ def handle_keypress(event):
85
+ global paused, showing_dialogue, hp, xp, score
86
+
87
+ key = event.keysym
88
+
89
+ if dialogue.active:
90
+ if key in ("z", "Z", "Return", "space"):
91
+ dialogue.dismiss()
92
+ return
93
+
94
+ if menu.active:
95
+ if key in ("Up", "w", "W"):
96
+ menu.move_up()
97
+ elif key in ("Down", "s", "S"):
98
+ menu.move_down()
99
+ elif key in ("z", "Z", "Return"):
100
+ menu.confirm()
101
+ elif key in ("x", "X", "Escape"):
102
+ menu.cancel()
103
+ return
104
+
105
+ if key in ("Escape", "p", "P"):
106
+ toggle_pause()
107
+ elif key in ("z", "Z", "Return"):
108
+ # Example: press Z near water to "fish"
109
+ col, row = tilemap.to_grid_coords(player.center_x, player.center_y)
110
+ for dr in range(-1, 2):
111
+ for dc in range(-1, 2):
112
+ if tilemap.get(col + dc, row + dr) == 2:
113
+ showing_dialogue = True
114
+ dialogue.show("You caught a fish! +10 XP",
115
+ on_complete=_on_dialogue_done)
116
+ xp = min(100, xp + 10)
117
+ hud.set_stat("xp", xp)
118
+ return
119
+
120
+
121
+ def _on_dialogue_done():
122
+ global showing_dialogue
123
+ showing_dialogue = False
124
+
125
+
126
+ def toggle_pause():
127
+ global paused
128
+ paused = not paused
129
+ if paused:
130
+ menu.show(["Resume", "Restart", "Quit"],
131
+ on_select=_on_menu_select,
132
+ on_cancel=lambda: toggle_pause(),
133
+ title="PAUSED")
134
+ else:
135
+ menu.hide()
136
+
137
+
138
+ def _on_menu_select(index, label):
139
+ global paused, hp, xp, score
140
+ if label == "Resume":
141
+ paused = False
142
+ elif label == "Restart":
143
+ hp, xp, score = 100, 0, 0
144
+ player.x, player.y = 60, 60
145
+ hud.set_stat("hp", hp)
146
+ hud.set_stat("xp", xp)
147
+ paused = False
148
+ elif label == "Quit":
149
+ game.quit()
150
+
151
+
152
+ game.bind_key("<Key>", handle_keypress)
153
+
154
+
155
+ # ── Update ──────────────────────────────────────────────────────────
156
+
157
+ def update(dt):
158
+ if dialogue.active or menu.active or paused:
159
+ return
160
+
161
+ state = keyboard.poll()
162
+ player.move(state.dx, state.dy, tilemap)
163
+ renderer.camera.follow(
164
+ player.center_x, player.center_y,
165
+ map_width=tilemap.width, map_height=tilemap.height,
166
+ )
167
+ hud.set_text("pos", f"({int(player.x)}, {int(player.y)})")
168
+
169
+
170
+ # ── Render ──────────────────────────────────────────────────────────
171
+
172
+ def render():
173
+ renderer.clear()
174
+ renderer.draw_tilemap(tilemap, TILE_COLORS)
175
+ renderer.draw_rect(player.x, player.y, player.width, player.height, "#e94560")
176
+ hud.render()
177
+
178
+
179
+ game.set_update(update)
180
+ game.set_render(render)
181
+ game.start()
@@ -0,0 +1,51 @@
1
+ """Minimal texastoast example — a colored square you can move with arrow keys."""
2
+
3
+ from texastoast import Game, CanvasRenderer, TileMap, Entity, KeyboardInput
4
+
5
+ # --- Setup ---
6
+ game = Game(title="texastoast hello", width=320, height=240, fps=30)
7
+ renderer = CanvasRenderer(game.canvas, 320, 240)
8
+ keyboard = KeyboardInput(game.root)
9
+
10
+ # A tiny map: 0 = grass, 1 = wall
11
+ tilemap = TileMap(
12
+ [
13
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
14
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
15
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
16
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
17
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
18
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
19
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
20
+ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
21
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
22
+ ],
23
+ tile_size=16,
24
+ solid_tiles={1},
25
+ )
26
+
27
+ TILE_COLORS = {0: "#7cb342", 1: "#5d4037"}
28
+
29
+ player = Entity(x=48, y=48, width=12, height=12, speed=100)
30
+
31
+
32
+ # --- Update ---
33
+ def update(dt: float):
34
+ state = keyboard.poll()
35
+ player.move(state.dx, state.dy, tilemap)
36
+ renderer.camera.follow(
37
+ player.center_x, player.center_y,
38
+ map_width=tilemap.width, map_height=tilemap.height,
39
+ )
40
+
41
+
42
+ # --- Render ---
43
+ def render():
44
+ renderer.clear()
45
+ renderer.draw_tilemap(tilemap, TILE_COLORS)
46
+ renderer.draw_rect(player.x, player.y, player.width, player.height, "#e94560")
47
+
48
+
49
+ game.set_update(update)
50
+ game.set_render(render)
51
+ game.start()