Summary
I am making a real-time physics simulation that needs a low delta_t. I have connected this simulation to a python-arcade game window to display the information in real-time.
I made a separate thread for the physics because there are some expensive matrix multiplications in the physics thread. Then, when an update is done I set the resulting states of the game window class that the game window can display whenever it draws a new frame.
Therefore, my thought process would be that the game window class only has to worry about drawing on the screen, while the physics thread takes care of all of the computations.
However, there is a bottleneck in communicating between the game window and the thread and I don't know have the under-the-hood insight.
Minimal Representation of what I want to do:
import threading
import time
import math
import arcade
class DisplayWindow(arcade.Window):
def __init__(self):
super().__init__(width=400, height=400)
self.state = 0
self.FPS = 0
def set_state(self, state):
self.state = state
def on_update(self, delta_time: float):
self.FPS = 1. / delta_time
def on_draw(self):
arcade.start_render()
arcade.draw_text(f'FPS: {self.FPS:0.2f}', 20, 20, arcade.color.WHITE)
arcade.draw_rectangle_filled(center_x=self.state * self.width,
center_y=self.height/2,
color=arcade.color.WHITE,
tilt_angle=0,
width=10,
height=10)
# Thread to simulate physics.
def simulation(display):
t_0 = time.time()
while True:
# Expensive calculation that needs high frequency:
t = time.time() - t_0
x = math.sin(t) / 2 + 0.5 # sinusoid for demonstration
# Send it to the display window
display.set_state(state=x)
# time.sleep(0.1) # runs smoother with this
def main():
display_window = DisplayWindow()
physics_thread = threading.Thread(target=simulation, args=(display_window,), daemon=True)
physics_thread.start()
arcade.run()
return 0
if __name__ == '__main__':
main()
Expected result: Smooth simulation with high frame-rates. The arcade window only has to run the on_draw at 30 or 60 fps. It only has to draw a few things.
Actual result: The physics loop runs super fast and calls the FPS drops.
When I add a time.sleep(0.1) to the physics thread, the whole thing becomes much smoother, I guess for some reason set_state( _ )
slows down the draw loop.