Reputation: 351
I am trying to learn PyMunk and I used their basic example from the website:
import pymunk
space = pymunk.Space()
space.gravity = 0,-1000
body = pymunk.Body(1,1666)
body.position = 50,100
poly = pymunk.Poly.create_box(body)
space.add(body, poly)
while True:
space.step(0.02)
But it does not create a window, does not show anything. How to use PyGame to create the graphical window?
Upvotes: 3
Views: 4412
Reputation: 20438
Here's an example that shows how I use Pymunk in combination with pygame. The Entity
class is a pygame.sprite.Sprite
subclass to which I attach a pymunk.Body
and a pymunk.Shape
as well as a reference to the pm.Space
, so that the bodies and shapes can be added and removed from it. The position of the sprite's rect gets set to the self.body.position
each frame, so that we get the correct blit position for the self.image
and can simply draw all sprites by calling self.sprite_group.draw(self.screen)
.
import math
import pygame as pg
import pymunk as pm
from pymunk import Vec2d
def flipy(p):
"""Convert chipmunk coordinates to pygame coordinates."""
return Vec2d(p[0], -p[1]+600)
class Entity(pg.sprite.Sprite):
def __init__(self, pos, space):
super().__init__()
self.image = pg.Surface((46, 52), pg.SRCALPHA)
pg.draw.polygon(self.image, (0, 50, 200),
[(0, 0), (48, 0), (48, 54), (24, 54)])
self.orig_image = self.image
self.rect = self.image.get_rect(topleft=pos)
vs = [(-23, 26), (23, 26), (23, -26), (0, -26)]
mass = 1
moment = pm.moment_for_poly(mass, vs)
self.body = pm.Body(mass, moment)
self.shape = pm.Poly(self.body, vs)
self.shape.friction = .9
self.body.position = pos
self.space = space
self.space.add(self.body, self.shape)
def update(self, dt):
pos = flipy(self.body.position)
self.rect.center = pos
self.image = pg.transform.rotate(
self.orig_image, math.degrees(self.body.angle))
self.rect = self.image.get_rect(center=self.rect.center)
# Remove sprites that have left the screen.
if pos.x < 20 or pos.y > 560:
self.space.remove(self.body, self.shape)
self.kill()
def handle_event(self, event):
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
self.body.angular_velocity = 5.5
elif event.key == pg.K_w:
self.body.apply_impulse_at_local_point(Vec2d(0, 900))
class Game:
def __init__(self):
self.done = False
self.clock = pg.time.Clock()
self.screen = pg.display.set_mode((800, 600))
self.gray = pg.Color('gray68')
self.red = pg.Color('red')
# Pymunk stuff.
self.space = pm.Space()
self.space.gravity = Vec2d(0.0, -900.0)
self.static_lines = [
pm.Segment(self.space.static_body, (60, 100), (370, 100), 0),
pm.Segment(self.space.static_body, (370, 100), (600, 300), 0),
]
for lin in self.static_lines:
lin.friction = 0.8
self.space.add(self.static_lines)
# A sprite group which holds the pygame.sprite.Sprite objects.
self.sprite_group = pg.sprite.Group(Entity((150, 200), self.space))
def run(self):
while not self.done:
self.dt = self.clock.tick(30) / 1000
self.handle_events()
self.run_logic()
self.draw()
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
if event.type == pg.MOUSEBUTTONDOWN:
self.sprite_group.add(Entity(flipy(event.pos), self.space))
for sprite in self.sprite_group:
sprite.handle_event(event)
def run_logic(self):
self.space.step(1/60) # Update physics.
self.sprite_group.update(self.dt) # Update pygame sprites.
def draw(self):
self.screen.fill(pg.Color(140, 120, 110))
for line in self.static_lines:
body = line.body
p1 = flipy(body.position + line.a.rotated(body.angle))
p2 = flipy(body.position + line.b.rotated(body.angle))
pg.draw.line(self.screen, self.gray, p1, p2, 5)
self.sprite_group.draw(self.screen)
# Debug draw. Outlines of the Pymunk shapes.
for obj in self.sprite_group:
shape = obj.shape
ps = [pos.rotated(shape.body.angle) + shape.body.position
for pos in shape.get_vertices()]
ps = [flipy((pos)) for pos in ps]
ps += [ps[0]]
pg.draw.lines(self.screen, self.red, False, ps, 1)
pg.display.flip()
if __name__ == '__main__':
pg.init()
Game().run()
pg.quit()
Upvotes: 1
Reputation: 4603
What that example does is create a simulation, add a box shaped object inside and then run the simulation infinitely. The code doesn't print or draw anything, so you will not actually see the output. To get a better understanding and something on screen I suggest you start with the tutorial: http://www.pymunk.org/en/latest/tutorials/SlideAndPinJoint.html
Pymunk is a 2d rigid body physics library, which means that what it does is simulate how objects move and interact with each other in 2 dimensions. Its not made for drawing to the screen or read input.
You can of course use it as is without anything else, and just print out the result of the simulation. But more common is that you want to draw to the screen, read input and so on. One way to do that is by using the game library Pygame that helps out with drawing to the screen, reading input, having a game loop and so on.
Pymunk itself does have some helper functions so that you can easily connect it with Pygame (and a couple of other libraries), but this is not the core part. Usually these helper functions are good for when you want something quick-n-dirty such as a prototype and you don't have need to customize the drawing.
Now, this said, if you want to see something you can add a print statement to the while loop, so it becomes like this:
while True:
space.step(0.02)
print(body.position)
Then it will print out the position of the ball each step of the simulation, and you can see that its changing all the time (because of the gravity that is set on the space).
There are more advanced examples included in Pymunk that are both interactive and show something on screen. These examples depends on mostly either Pygame or Pyglet, but the principle is the same in case you have a different library you want to use it with.
Upvotes: 5