wip
This commit is contained in:
parent
f55c2fe32b
commit
de1001dd57
30 changed files with 1451 additions and 3 deletions
250
constraints.py
Normal file
250
constraints.py
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
"""
|
||||
Pymunk constraints demo. Showcase of all the constraints included in Pymunk.
|
||||
|
||||
Adapted from the Chipmunk Joints demo:
|
||||
https://github.com/slembcke/Chipmunk2D/blob/master/demo/Joints.c
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import math
|
||||
|
||||
import pygame
|
||||
import pymunk.pygame_util
|
||||
from pymunk.vec2d import Vec2d
|
||||
|
||||
pygame.init()
|
||||
screen = pygame.display.set_mode((1200, 600))
|
||||
clock = pygame.time.Clock()
|
||||
font = pygame.font.Font(None, 24)
|
||||
|
||||
|
||||
help_txt = font.render(
|
||||
"Pymunk constraints demo. Use mouse to drag/drop. Hover to see descr.",
|
||||
True,
|
||||
pygame.Color("darkgray"),
|
||||
)
|
||||
|
||||
space = pymunk.Space()
|
||||
space.gravity = (0.0, 900.0)
|
||||
draw_options = pymunk.pygame_util.DrawOptions(screen)
|
||||
|
||||
# containers
|
||||
box_size = 200
|
||||
w = screen.get_width()
|
||||
h = screen.get_height()
|
||||
for i in range(6):
|
||||
sw = pymunk.Segment(space.static_body, (0, i * box_size), (w, i * box_size), 1)
|
||||
sw.friction = 1
|
||||
sw.elasticity = 1
|
||||
sh = pymunk.Segment(
|
||||
space.static_body, (i * box_size, 0), (i * box_size, h - box_size), 1
|
||||
)
|
||||
sh.friction = 1
|
||||
sh.elasticity = 1
|
||||
space.add(sw, sh)
|
||||
|
||||
|
||||
def add_ball(space, pos, box_offset):
|
||||
body = pymunk.Body()
|
||||
body.position = Vec2d(*pos) + box_offset
|
||||
shape = pymunk.Circle(body, 20)
|
||||
shape.mass = 1
|
||||
shape.friction = 0.7
|
||||
space.add(body, shape)
|
||||
return body
|
||||
|
||||
|
||||
def add_bar(space, pos, box_offset):
|
||||
body = pymunk.Body()
|
||||
body.position = Vec2d(*pos) + box_offset
|
||||
shape = pymunk.Segment(body, (0, 40), (0, -40), 6)
|
||||
shape.mass = 2
|
||||
shape.friction = 0.7
|
||||
space.add(body, shape)
|
||||
return body
|
||||
|
||||
|
||||
def add_lever(space, pos, box_offset):
|
||||
body = pymunk.Body()
|
||||
body.position = pos + Vec2d(*box_offset) + (0, -20)
|
||||
shape = pymunk.Segment(body, (0, 20), (0, -20), 5)
|
||||
shape.mass = 1
|
||||
shape.friction = 0.7
|
||||
space.add(body, shape)
|
||||
return body
|
||||
|
||||
|
||||
def main():
|
||||
txts = {}
|
||||
|
||||
box_offset = 0, 0
|
||||
b1 = add_ball(space, (50, 60), box_offset)
|
||||
b2 = add_ball(space, (150, 60), box_offset)
|
||||
c: pymunk.Constraint = pymunk.PinJoint(b1, b2, (20, 0), (-20, 0))
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = box_size, 0
|
||||
b1 = add_ball(space, (50, 60), box_offset)
|
||||
b2 = add_ball(space, (150, 60), box_offset)
|
||||
c = pymunk.SlideJoint(b1, b2, (20, 0), (-20, 0), 40, 80)
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = box_size * 2, 0
|
||||
b1 = add_ball(space, (50, 60), box_offset)
|
||||
b2 = add_ball(space, (150, 60), box_offset)
|
||||
c = pymunk.PivotJoint(b1, b2, Vec2d(*box_offset) + (100, 60))
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = box_size * 3, 0
|
||||
b1 = add_ball(space, (50, 60), box_offset)
|
||||
b2 = add_ball(space, (150, 60), box_offset)
|
||||
c = pymunk.GrooveJoint(b1, b2, (50, 50), (50, -50), (-50, 0))
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = box_size * 4, 0
|
||||
b1 = add_ball(space, (50, 60), box_offset)
|
||||
b2 = add_ball(space, (150, 60), box_offset)
|
||||
c = pymunk.DampedSpring(b1, b2, (30, 0), (-30, 0), 20, 5, 0.3)
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = box_size * 5, 0
|
||||
b1 = add_bar(space, (50, 80), box_offset)
|
||||
b2 = add_bar(space, (150, 80), box_offset)
|
||||
# Add some joints to hold the circles in place.
|
||||
space.add(pymunk.PivotJoint(b1, space.static_body, (50, 80) + Vec2d(*box_offset)))
|
||||
space.add(pymunk.PivotJoint(b2, space.static_body, (150, 80) + Vec2d(*box_offset)))
|
||||
c = pymunk.DampedRotarySpring(b1, b2, 0, 3000, 60)
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = 0, box_size
|
||||
b1 = add_lever(space, (50, 100), box_offset)
|
||||
b2 = add_lever(space, (150, 100), box_offset)
|
||||
# Add some joints to hold the circles in place.
|
||||
space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset)))
|
||||
space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset)))
|
||||
# Hold their rotation within 90 degrees of each other.
|
||||
c = pymunk.RotaryLimitJoint(b1, b2, math.pi / 2, math.pi / 2)
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = box_size, box_size
|
||||
b1 = add_lever(space, (50, 100), box_offset)
|
||||
b2 = add_lever(space, (150, 100), box_offset)
|
||||
# Add some pin joints to hold the circles in place.
|
||||
space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset)))
|
||||
space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset)))
|
||||
# Ratchet every 90 degrees
|
||||
c = pymunk.RatchetJoint(b1, b2, 0, math.pi / 2)
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = box_size * 2, box_size
|
||||
b1 = add_bar(space, (50, 100), box_offset)
|
||||
b2 = add_bar(space, (150, 100), box_offset)
|
||||
# Add some pin joints to hold the circles in place.
|
||||
space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset)))
|
||||
space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset)))
|
||||
# Force one to sping 2x as fast as the other
|
||||
c = pymunk.GearJoint(b1, b2, 0, 2)
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
box_offset = box_size * 3, box_size
|
||||
b1 = add_bar(space, (50, 100), box_offset)
|
||||
b2 = add_bar(space, (150, 100), box_offset)
|
||||
# Add some pin joints to hold the circles in place.
|
||||
space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset)))
|
||||
space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset)))
|
||||
# Make them spin at 1/2 revolution per second in relation to each other.
|
||||
c = pymunk.SimpleMotor(b1, b2, math.pi)
|
||||
txts[box_offset] = inspect.getdoc(c)
|
||||
space.add(c)
|
||||
|
||||
# TODO add one or two advanced constraints examples, such as a car or rope
|
||||
|
||||
mouse_joint = None
|
||||
mouse_body = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
|
||||
|
||||
# Build rendered help texts
|
||||
box_texts = {}
|
||||
for k in txts:
|
||||
l = 0
|
||||
box_texts[k] = []
|
||||
# Only take the first 5 lines.
|
||||
for line in txts[k].splitlines()[:5]:
|
||||
txt = font.render(line, True, pygame.Color("black"))
|
||||
box_texts[k].append(txt)
|
||||
|
||||
while True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
exit()
|
||||
elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
|
||||
exit()
|
||||
elif event.type == pygame.MOUSEBUTTONDOWN:
|
||||
if mouse_joint is not None:
|
||||
space.remove(mouse_joint)
|
||||
mouse_joint = None
|
||||
|
||||
p = Vec2d(*event.pos)
|
||||
hit = space.point_query_nearest(p, 5, pymunk.ShapeFilter())
|
||||
if hit is not None and hit.shape.body.body_type == pymunk.Body.DYNAMIC:
|
||||
shape = hit.shape
|
||||
# Use the closest point on the surface if the click is outside
|
||||
# of the shape.
|
||||
if hit.distance > 0:
|
||||
nearest = hit.point
|
||||
else:
|
||||
nearest = p
|
||||
mouse_joint = pymunk.PivotJoint(
|
||||
mouse_body,
|
||||
shape.body,
|
||||
(0, 0),
|
||||
shape.body.world_to_local(nearest),
|
||||
)
|
||||
mouse_joint.max_force = 50000
|
||||
mouse_joint.error_bias = (1 - 0.15) ** 60
|
||||
space.add(mouse_joint)
|
||||
|
||||
elif event.type == pygame.MOUSEBUTTONUP:
|
||||
if mouse_joint is not None:
|
||||
space.remove(mouse_joint)
|
||||
mouse_joint = None
|
||||
|
||||
screen.fill(pygame.Color("white"))
|
||||
|
||||
screen.blit(help_txt, (5, screen.get_height() - 20))
|
||||
|
||||
mouse_pos = pygame.mouse.get_pos()
|
||||
|
||||
# Display help message
|
||||
x = mouse_pos[0] // box_size * box_size
|
||||
y = mouse_pos[1] // box_size * box_size
|
||||
|
||||
if (x, y) in box_texts:
|
||||
txts = box_texts[(x, y)]
|
||||
i = 0
|
||||
for txt in txts:
|
||||
pos = (5, box_size * 2 + 10 + i * 20)
|
||||
screen.blit(txt, pos)
|
||||
i += 1
|
||||
|
||||
mouse_body.position = mouse_pos
|
||||
|
||||
space.step(1.0 / 60)
|
||||
|
||||
space.debug_draw(draw_options)
|
||||
pygame.display.flip()
|
||||
|
||||
clock.tick(60)
|
||||
pygame.display.set_caption(f"fps: {clock.get_fps()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue