-
Notifications
You must be signed in to change notification settings - Fork 6
/
rocket_pt.py
157 lines (119 loc) · 5.08 KB
/
rocket_pt.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
""" Run the rocket game on prompt-toolkit.
Not a lot of fun to play this way, but hey, it works over SSH!
"""
import sys
import time
import math
import prompt_toolkit as pt
from rocket import BaseRocketGame
assert pt.__version__ > '2'
styles = {
'default': 'bg:#ffffff #000000',
'enemy': 'bg:#ffff00 #000000',
'bullet': 'bg:#ffffff #ff0000',
'particle': 'bg:#ffffff #888888',
'player': 'bg:#0000ff #000000',
}
class RocketUiControl(pt.layout.UIControl):
def __init__(self, paintfunc):
self._paintfunc = paintfunc
def create_content(self, width, height):
lines = self._paintfunc(width, height)
# lines = [pt.formatted_text.to_formatted_text(line) for line in lines]
lines = [[(styles[d], s) for d, s in line] for line in lines]
return pt.layout.UIContent(lambda i: lines[i], len(lines), show_cursor=False)
class PtRocketGame(BaseRocketGame):
""" Rocket game with prompt_toolkit providing a drawing canvas and user input,
so that it can run in the command line, and over SSH.
"""
def __init__(self):
BaseRocketGame.__init__(self)
# Global key bindings.
bindings = pt.key_binding.KeyBindings()
for key in ('space', 'up', 'left', 'right', 'escape', 'q'):
bindings.add(key)(self._press_key)
control = RocketUiControl(self.paint)
container = pt.layout.containers.Window(content=control)
self._app = pt.application.Application(layout=pt.layout.Layout(container),
key_bindings=bindings,
min_redraw_interval=0.01,
mouse_support=False, full_screen=True)
self._size = 0, 0
self._lasttime = time.time()
self._highscore = 0
self._size_scale = 10
self._key_release = {}
def run(self):
self._app.run()
def paint(self, w, h):
# Resize?
if (w, h) != self._size:
self._size = w, h
self.game.exports.resize(w*self._size_scale, h*self._size_scale)
# Init lines
lines = []
for y in range(h+1):
lines.append([('default', ' ') for i in range(w+1)])
self._lines = lines
# Update and draw
progress = time.time() - self._lasttime
self._lasttime = time.time()
self.game.exports.update(progress)
self.game.exports.draw()
self._release_keys()
self._app.invalidate() # Request a new paint event (also see app.min_redraw_interval)
return self._lines
## Events going into the WASM module
def _press_key(self, event):
try:
key = event.key_sequence[0].key
except Exception:
return
self._toggle_key(key, True)
self._key_release[key] = time.time() + 0.1
def _release_keys(self):
now = time.time()
for key in list(self._key_release.keys()):
t = self._key_release[key]
if t < now:
self._key_release.pop(key)
self._toggle_key(key, False)
def _toggle_key(self, key, b):
if key in (' ', 'space'):
self.game.exports.toggle_shoot(b)
elif key == 'left':
self.game.exports.toggle_turn_left(b)
elif key == 'right':
self.game.exports.toggle_turn_right(b)
elif key == 'up':
self.game.exports.toggle_boost(b)
elif key in ('q', 'escape'):
self._app.exit()
## Events generated by WASM module
def wasm_clear_screen(self) -> None: # [] -> []
pass # not needed, we start with a blanc canvas each iteration
def _round_pos(self, x, y):
x = max(0, min(int(x / self._size_scale + 0.5), self._size[0]))
y = max(0, min(int(y / self._size_scale + 0.5), self._size[1]))
return x, y
def wasm_draw_bullet(self, x: float, y: float) -> None: # [(0, 'f64'), (1, 'f64')] -> []
x, y = self._round_pos(x, y)
self._lines[y][x] = 'bullet', '*'
def wasm_draw_enemy(self, x: float, y: float) -> None: # [(0, 'f64'), (1, 'f64')] -> []
x, y = self._round_pos(x, y)
self._lines[y][x] = 'enemy', 'O'
def wasm_draw_particle(self, x: float, y: float, a: float) -> None: # [(0, 'f64'), (1, 'f64'), (2, 'f64')] -> []
x, y = self._round_pos(x, y)
self._lines[y][x] = 'particle', '.'
def wasm_draw_player(self, x: float, y: float, a: float) -> None: # [(0, 'f64'), (1, 'f64'), (2, 'f64')] -> []
x, y = self._round_pos(x, y)
self._lines[y][x] = 'player', 'X'
def wasm_draw_score(self, score: float) -> None: # env.draw_score: [(0, 'f64')] -> []
score = int(score)
self._highscore = max(self._highscore, score)
text = f'Score: {score}, HighScore: {self._highscore}'
for i in range(len(text)):
self._lines[0][i] = 'default', text[i]
if __name__ == '__main__':
game = PtRocketGame()
game.run()