Skip to content

Commit 0c79338

Browse files
committed
Split state handing into multiple modules.
1 parent 9896049 commit 0c79338

5 files changed

Lines changed: 98 additions & 37 deletions

File tree

g.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""This module stores globally mutable variables used by this program."""
2+
from __future__ import annotations
3+
4+
import tcod.console
5+
import tcod.context
6+
7+
import game.state
8+
9+
console: tcod.console.Console
10+
"""The main console."""
11+
12+
context: tcod.context.Context
13+
"""The window managed by tcod."""
14+
15+
states: list[game.state.State] = []
16+
"""A stack of states with the last item being the active state."""

game/state.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Base classes for states."""
2+
from __future__ import annotations
3+
4+
from typing import Protocol
5+
6+
import tcod.console
7+
import tcod.event
8+
9+
10+
class State(Protocol):
11+
"""An abstract game state."""
12+
13+
def on_event(self, event: tcod.event.Event) -> None:
14+
"""Called on events."""
15+
16+
def on_draw(self, console: tcod.console.Console) -> None:
17+
"""Called when the state is being drawn."""

game/state_tools.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""State handling functions."""
2+
import tcod.console
3+
4+
import g
5+
6+
7+
def main_draw() -> None:
8+
"""Render and present the active state."""
9+
if not g.states:
10+
return
11+
g.console.clear()
12+
g.states[-1].on_draw(g.console)
13+
g.context.present(g.console)
14+
15+
16+
def main_loop() -> None:
17+
"""Run the active state forever."""
18+
while g.states:
19+
main_draw()
20+
for event in tcod.event.wait():
21+
print(event)
22+
if g.states:
23+
g.states[-1].on_event(event)

game/states.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""A collection of game states."""
2+
from __future__ import annotations
3+
4+
import attrs
5+
import tcod.console
6+
import tcod.event
7+
from tcod.event import KeySym
8+
9+
10+
@attrs.define(eq=False)
11+
class ExampleState:
12+
"""Example state with a hard-coded player position."""
13+
14+
player_x: int
15+
"""Player X position, left-most position is zero."""
16+
player_y: int
17+
"""Player Y position, top-most position is zero."""
18+
19+
def on_event(self, event: tcod.event.Event) -> None:
20+
"""Move the player on events and handle exiting. Movement is hard-coded."""
21+
match event:
22+
case tcod.event.Quit():
23+
raise SystemExit()
24+
case tcod.event.KeyDown(sym=KeySym.LEFT):
25+
self.player_x -= 1
26+
case tcod.event.KeyDown(sym=KeySym.RIGHT):
27+
self.player_x += 1
28+
case tcod.event.KeyDown(sym=KeySym.UP):
29+
self.player_y -= 1
30+
case tcod.event.KeyDown(sym=KeySym.DOWN):
31+
self.player_y += 1
32+
33+
def on_draw(self, console: tcod.console.Console) -> None:
34+
"""Draw the player with print. Bounds do not need to be checked with this function."""
35+
console.print(self.player_x, self.player_y, "@")

main.py

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,14 @@
22
"""Main entry-point module. This script is used to start the program."""
33
from __future__ import annotations
44

5-
import attrs
65
import tcod.console
76
import tcod.context
87
import tcod.event
98
import tcod.tileset
109

11-
12-
@attrs.define(eq=False)
13-
class ExampleState:
14-
"""Example state with a hard-coded player position."""
15-
16-
player_x: int
17-
"""Player X position, left-most position is zero."""
18-
player_y: int
19-
"""Player Y position, top-most position is zero."""
20-
21-
def on_event(self, event: tcod.event.Event) -> None:
22-
"""Move the player on events and handle exiting. Movement is hard-coded."""
23-
match event:
24-
case tcod.event.Quit():
25-
raise SystemExit()
26-
case tcod.event.KeyDown(sym=tcod.event.KeySym.LEFT):
27-
self.player_x -= 1
28-
case tcod.event.KeyDown(sym=tcod.event.KeySym.RIGHT):
29-
self.player_x += 1
30-
case tcod.event.KeyDown(sym=tcod.event.KeySym.UP):
31-
self.player_y -= 1
32-
case tcod.event.KeyDown(sym=tcod.event.KeySym.DOWN):
33-
self.player_y += 1
34-
35-
def on_draw(self, console: tcod.console.Console) -> None:
36-
"""Draw the player with print. Bounds do not need to be checked with this function."""
37-
console.print(self.player_x, self.player_y, "@")
10+
import g
11+
import game.state_tools
12+
import game.states
3813

3914

4015
def main() -> None:
@@ -43,15 +18,10 @@ def main() -> None:
4318
"data/Alloy_curses_12x12.png", columns=16, rows=16, charmap=tcod.tileset.CHARMAP_CP437
4419
)
4520
tcod.tileset.procedural_block_elements(tileset=tileset)
46-
console = tcod.console.Console(80, 50)
47-
state = ExampleState(player_x=console.width // 2, player_y=console.height // 2)
48-
with tcod.context.new(console=console, tileset=tileset) as context:
49-
while True: # Main loop
50-
console.clear() # Clear the console before any drawing
51-
state.on_draw(console) # Draw the current state
52-
context.present(console) # Render the console to the window and show it
53-
for event in tcod.event.wait(): # Event loop, blocks until pending events exist
54-
state.on_event(event) # Dispatch events to the state
21+
g.console = tcod.console.Console(80, 50)
22+
g.states = [game.states.ExampleState(player_x=g.console.width // 2, player_y=g.console.height // 2)]
23+
with tcod.context.new(console=g.console, tileset=tileset) as g.context:
24+
game.state_tools.main_loop()
5525

5626

5727
if __name__ == "__main__":

0 commit comments

Comments
 (0)