Instantly share code, notes, and snippets.

# meunomemauricio/fixed_pendulum.py

Last active October 27, 2022 15:30
Show Gist options
• Save meunomemauricio/edd85dbb4a37d563fc3cefac07935524 to your computer and use it in GitHub Desktop.
Simple Pendulum simulation using Pyglet + PyMunk
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 """Fixed Pendulum Simulation using PyMunk and Pyglet.""" import pymunk import pyglet from pyglet.window import key from pymunk import Vec2d from pymunk.pyglet_util import DrawOptions class Pendulum: """Fixed Pendulum PyMunk Model.""" MASS = 0.100 # kg FORCE = 10 # mN def __init__(self, space: pymunk.Space): self.space = space self._create_entities() def _create_entities(self) -> None: """Create the entities that form the Pendulum.""" self.static_body = pymunk.Body(body_type=pymunk.Body.STATIC) self.static_body.position = (360, 360) moment = pymunk.moment_for_circle( mass=self.MASS, inner_radius=0, outer_radius=10.0 ) self.circle_body = pymunk.Body(mass=self.MASS, moment=moment) self.circle_body.position = (360, 50) circle_shape = pymunk.Circle(body=self.circle_body, radius=10.0) rod_joint = pymunk.constraints.PinJoint( a=self.static_body, b=self.circle_body, ) self.space.add( self.static_body, self.circle_body, circle_shape, rod_joint ) @property def angle(self) -> float: """Angle (deg) between the Pendulum and the resting location.""" return Vec2d(0, -1).get_angle_degrees_between(self.vector) @property def vector(self) -> Vec2d: """Pendulum Vector, from Fixed point to the center of the Circle.""" return self.circle_body.position - self.static_body.position def accelerate(self, direction: Vec2d): """Apply force in the direction `dir`.""" impulse = self.FORCE * direction.normalized() self.circle_body.apply_impulse_at_local_point(impulse=impulse) class SimulationWindow(pyglet.window.Window): """Application simulating the Fixed Pendulum.""" CAPTION = "PyMunk Fixed Pendulum Simulation." WIDTH = 720 HEIGHT = 720 INTERVAL = 1.0 / 100 # 100 updates / second FONT_SIZE = 16 FONT_COLOR = (255, 255, 255, 255) def __init__(self): super().__init__( width=self.WIDTH, height=self.HEIGHT, caption=self.CAPTION ) self.space = pymunk.Space() self.space.gravity = Vec2d(0, -9807) # mm/s² self.model = Pendulum(space=self.space) self.draw_options = DrawOptions() self.keyboard = key.KeyStateHandler() self.push_handlers(self.keyboard) self.angle_label = pyglet.text.Label( font_size=self.FONT_SIZE, x=5, y=self.height - self.FONT_SIZE - 1, color=self.FONT_COLOR, bold=True, ) pyglet.clock.schedule_interval(self.update, interval=self.INTERVAL) def _handle_input(self): """Handle application input.""" if self.keyboard[key.LEFT]: direction = self.model.vector.rotated_degrees(-90) # CW self.model.accelerate(direction=direction) elif self.keyboard[key.RIGHT]: direction = self.model.vector.rotated_degrees(90) # CCW self.model.accelerate(direction=direction) def on_draw(self) -> None: """Screen Draw Event.""" self.clear() self.space.debug_draw(options=self.draw_options) self.angle_label.draw() def update(self, dt: float) -> None: """Update PyMunk's Space state. :param float dt: Time between calls of `update`. """ self._handle_input() self.space.step(dt=self.INTERVAL) self.angle_label.text = f"Angle: {self.model.angle:4.0f}°" # Run application, if executing the module. if __name__ == "__main__": SimulationWindow() pyglet.app.run()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 pyglet==1.5.27 pymunk==6.2.1