1515
1616from arcade .utils import is_pyodide
1717
18- if is_pyodide () :
18+ if is_pyodide :
1919 pyglet .options .backend = "webgl"
2020
2121import pyglet .config
@@ -193,7 +193,7 @@ def __init__(
193193 pyglet .options .dpi_scaling = "platform"
194194
195195 desired_gl_provider = "opengl"
196- if is_pyodide () :
196+ if is_pyodide :
197197 gl_api = "webgl"
198198
199199 if gl_api == "webgl" :
@@ -304,8 +304,9 @@ def __init__(
304304 assert update_rate <= draw_rate , (
305305 "An arcade window's draw rate cannot be faster than its update rate"
306306 )
307- self ._draw_rate = max (update_rate , draw_rate )
307+ self ._draw_rate = min (update_rate , draw_rate )
308308 self ._accumulated_draw_time : float = 0.0
309+ self ._accumulated_update_time : float = 0.0
309310
310311 # Fixed rate cannot be changed post initialization as this throws off physics sims.
311312 # If more time resolution is needed in fixed updates, devs can do 'sub-stepping'.
@@ -578,10 +579,22 @@ def _dispatch_frame(self, delta_time: float) -> None:
578579 The modulus on the accumulated draw time means that when the update rate is greater
579580 than the draw rate no time is lost.
580581
582+ This method is entirely skipped when running in pyodide, this is because the event loop
583+ is driven by requestAnimationFrame in the browser, which adds some unique limitations and
584+ considerations around Arcade's event loop handling. In pyglet, the draw() function of the
585+ window is called directly during the requestAnimationFrame loop, so Arcade handles special
586+ control of the update/draw timing directly in that function. Arcade's version of this function
587+ is never called on desktop, because this function is called instead, and this calls directly
588+ to the superclass's implementation.
589+
581590 Args:
582591 delta_time: The amount of time since the last update.
583592 """
593+ if is_pyodide :
594+ return
595+
584596 self ._dispatch_updates (delta_time )
597+
585598 self ._accumulated_draw_time += delta_time
586599
587600 if self ._draw_rate <= self ._accumulated_draw_time :
@@ -592,7 +605,7 @@ def _dispatch_frame(self, delta_time: float) -> None:
592605
593606 # In case the window close in on_update, on_fixed_update or input callbacks
594607 if not self .closed :
595- self .draw (self ._accumulated_draw_time )
608+ super () .draw (self ._accumulated_draw_time )
596609 self ._accumulated_draw_time %= self ._draw_rate
597610
598611 def _dispatch_updates (self , delta_time : float ) -> None :
@@ -617,6 +630,44 @@ def _dispatch_updates(self, delta_time: float) -> None:
617630 fixed_count += 1
618631 self .dispatch_event ("on_update" , GLOBAL_CLOCK .delta_time )
619632
633+ def draw (self , dt : float ) -> None :
634+ """
635+ Render a frame.
636+
637+ On desktop this is driven by arcade's clock-scheduled
638+ :meth:`_dispatch_frame`, which calls the super version of this method direclty.
639+ This implementation is only called when using Pyglet's pyodide backend as part of it's
640+ requestAnimationFrame loop.
641+
642+ The loop rate in a browser is tied inherently to the requestAnimationFrame speed, which
643+ is tied to the monitor's refresh rate, so basically the Arcade loop can never be called
644+ faster than the monitor refresh rate in a browser. This method does some special handling
645+ of the update rate to make the updates happen multiple times per loop to achieve the target
646+ update rate if it is higher than the refresh rate.
647+
648+ It does not bypass the refresh rate for draw rate, because the framebuffer will never drawn
649+ faster to the canvas than that anyways, so us running it faster than that is pointless.
650+ """
651+ self ._accumulated_update_time += dt
652+ while self ._accumulated_update_time >= self ._update_rate :
653+ GLOBAL_CLOCK .tick (self ._update_rate )
654+ fixed_count = 0
655+ while GLOBAL_FIXED_CLOCK .accumulated >= self ._fixed_rate and (
656+ self ._fixed_frame_cap is None or fixed_count <= self ._fixed_frame_cap
657+ ):
658+ GLOBAL_FIXED_CLOCK .tick (self ._fixed_rate )
659+ self .dispatch_event ("on_fixed_update" , self ._fixed_rate )
660+ fixed_count += 1
661+
662+ self .dispatch_event ("on_update" , GLOBAL_CLOCK .delta_time )
663+ self ._accumulated_update_time -= self ._update_rate
664+
665+ self ._accumulated_draw_time += dt
666+ if self ._accumulated_draw_time < self ._draw_rate :
667+ return
668+ self ._accumulated_draw_time %= self ._draw_rate
669+ super ().draw (dt )
670+
620671 def flip (self ) -> None :
621672 """
622673 Present the rendered content to the screen.
0 commit comments