You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Small update to configuration section to note that `<py-config>` applies
only to py/mpy type scripts.
Major additions to `pygame-ce.md` on how to get started by explaining
the changes needed from "stock" pygame-ce code to run in pyscript, and
specifically ways to allow the same code to run cross-platform (locally
and in pyscript online).
The `style="image-rendering: pixelated` on the canvas preserves the
122
+
pixelated look on high-DPI screens or when zoomed-in. Remove it to have a
123
+
"smoothed" look.
124
+
125
+
Lastly, you need to define the `pyscript.toml` file to expose any files that
126
+
your game loads -- in this case, `intro_ball.gif`
127
+
[(download from pygame GitHub)](https://github.com/pygame-community/pygame-ce/blob/80fe4cb9f89aef96f586f68d269687572e7843f6/docs/reST/tutorials/assets/intro_ball.gif?raw=true).
128
+
129
+
```toml title="pyscript.toml"
130
+
[files]
131
+
"intro_ball.gif" = ""
132
+
```
133
+
134
+
Now you only need to serve the 3 files to a browser. If using
135
+
[pyscript.com](https://pyscript.com) you only need to ensure the content of the
136
+
files, click save then run and view the preview tab. Or, if you are on a machine
137
+
with Python installed you can do it from a command line running in the same
138
+
directory as the project:
139
+
140
+
```
141
+
python -m http.server -b 127.0.0.1 8000
142
+
```
143
+
144
+
This will start a website accessible only to your machine (`-b 127.0.0.1` limits
145
+
access only to "localhost" -- your own machine). After running this, you can
146
+
visit [http://localhost:8000/](http://localhost:8000/) to run the game in your
147
+
browser.
148
+
149
+
Congratulations! Now you know the basics of updating games to run in PyScript.
150
+
You can continue to develop your game in the typical PyGame-CE way.
151
+
152
+
## Running Locally
153
+
154
+
Placing an `await` call in the main program script as in the example is not
155
+
technically valid Python as it should be in an `async` function. In the
156
+
environment executed by PyScript, the code runs in an `async` context so this
157
+
works; however, you will notice you cannot run the `quickstart.py` on your
158
+
local machine with Python. To fix that, you need to add just a little more
159
+
code:
160
+
161
+
Place the entire game in a function called `run_game` so that function can be
162
+
declared as `async`, allowing it to use `await` in any environment. Import the
163
+
`asyncio` package and add the `try ... except` code at the end. Now when running
164
+
in the browser, `asyncio.create_task` is used, but when running locally
165
+
`asyncio.run` is used. Now you can develop and run locally but also support
166
+
publish to the web via PyScript.
167
+
168
+
```python
169
+
import asyncio
170
+
import sys, pygame
171
+
172
+
asyncdefrun_game():
173
+
pygame.init()
174
+
175
+
# Game init ...
176
+
177
+
whileTrue:
178
+
for event in pygame.event.get():
179
+
if event.type == pygame.QUIT: sys.exit()
180
+
181
+
# Game logic ...
182
+
183
+
await asyncio.sleep(1/60)
184
+
185
+
try:
186
+
asyncio.get_running_loop() # succeeds if in async context
187
+
asyncio.create_task(run_game())
188
+
exceptRuntimeError:
189
+
asyncio.run(run_game()) # start async context as we're not in one
190
+
```
191
+
192
+
!!! Info
193
+
194
+
In the web version, the `sys.exit()` was never used because the `QUIT`
195
+
event is not generated, but in the local version, responding to the event
196
+
is mandatory.
197
+
198
+
## Advanced Timing
199
+
200
+
While the `await asyncio.sleep(1/60)` is a quick way to approximate 60 FPS,
201
+
like all sleep-based timing methods in games this is not precise. Generating
202
+
the frame itself takes time, so sleeping 1/60th of a second means total frame
203
+
time is longer and actual FPS will be less than 60. Our usage of `clock.tick()`
204
+
and `dt` in the earlier code ensures the ball will move at the correct rate,
205
+
but performance will not be ideal.
206
+
207
+
A better way is to do this is to run your game at the same frame rate as the
208
+
display (usually 60, but can be 75, 100, 144, or higher on some displays). When
209
+
running in the browser, the proper way to do this is with the JavaScript API
210
+
called `requestAnimationFrame`. Using the FFI (foreign function interface)
211
+
capabilities of PyScript, we can request the browser's JavaScript runtime to
212
+
call the game. The main issue of this method is it requires work to separate the
213
+
game setup from the game's execution, which may require more advanced Python
214
+
code such as `global` or `class`. However, one benefit is that the `asyncio`
215
+
usages are gone.
216
+
217
+
218
+
When running locally, you get the same effect from the `vsync=1` parameter on
219
+
`pygame.display.set_mode` as `pygame.display.flip()` will pause until the screen
220
+
has displayed the frame. In the web version, the `vsync=1` will do nothing,
221
+
`flip` will not block, leaving the browser itself to control the timing using
222
+
`requestAnimationFrame` by calling `run_one_frame` (via `on_animation_frame`)
223
+
each time the display updates.
224
+
225
+
Additionally, since frame lengths will be different on each machine, we need to
226
+
account for this by creating and using a `dt` variable by using a
227
+
`pygame.time.Clock`. We update the speed to be in pixels per second and multiply
228
+
by `dt` (in seconds) to get the number of pixels to move.
229
+
230
+
The code will look like this:
231
+
232
+
```python
233
+
import sys, pygame
234
+
235
+
pygame.init()
236
+
237
+
size = width, height =320, 240
238
+
speed = pygame.Vector2(150, 150) # use Vector2 so we can multiply with dt
0 commit comments