# on crash, click Settings->Restart system (due to an issue with pygame-ce + pycafe)
import solara
import numpy as np
import pygame
import asyncio
import time
data = solara.reactive(None)
width = 320
height = 200
player_pos = pygame.Vector2(width / 4, height / 2)
screen = None
canvas = None
### BOILERPLATE START ###
def setup():
global screen, canvas
import js
canvas = js.OffscreenCanvas.new(width, height)
canvas.id = "canvas" # emscripten wants this?
canvas.style = js.Object.new() # otherwise we'll get a style.cursor error
js.pyodide.canvas.setCanvas2D(canvas)
# emscripten assumes globalThis.screen to exist
js.screen = {
"width": width,
"height": height,
}
pygame.display.init()
# we define a mock globalThis.window, and to
# avoid 'eventHandler.target.addEventListener is not a function'
# we put in this mock addEventListener
js.window.addEventListener = js.Function.new()
# monkey patch document
js.document = js.Object.new()
js.document.querySelector = lambda x: js.window
js.document.fullscreenEnabled = False
js.document.addEventListener = js.Function.new()
screen = pygame.display.set_mode((width, height))
def transfer_image():
# read off a pixel from the canvas
context = canvas.getContext("2d")
# can possibly be faster?
mem_obj = context.getImageData(0, 0, width, height).data.to_py()
np_array = np.frombuffer(mem_obj, dtype=np.uint8)
np_array.shape = (height, width, 4)
data.value = np_array
# ideally, all the above boilerplate goes away
### BOILERPLATE END ###
setup()
async def game_loop():
player_pos.x = 10
frames = 100
t0 = time.time()
for i in range(frames):
screen.fill("red")
pygame.draw.circle(screen, "blue", player_pos, 40)
pygame.display.flip()
transfer_image()
await asyncio.sleep(1./frames)
player_pos.x += width/frames
t1 = time.time()
print("fps", frames/(t1-t0))
reset_counter = solara.reactive(0)
def reset():
reset_counter.value += 1
@solara.component
def Page():
solara.Button(label=f"Restart", on_click=reset, outlined=True, color="primary")
solara.lab.use_task(game_loop, dependencies=[reset_counter.value])
if data.value is not None:
solara.Image(data.value)