180 lines
5 KiB
Python
180 lines
5 KiB
Python
"""Basic showcase on how the transform property on SpaceDebugDrawOptions can
|
|
be used as a camera to allow panning. Use arrows to move the camera.
|
|
"""
|
|
|
|
__docformat__ = "reStructuredText"
|
|
|
|
import random
|
|
import sys
|
|
|
|
import pygame
|
|
import pymunk.pygame_util
|
|
from pymunk.vec2d import Vec2d
|
|
|
|
random.seed(0)
|
|
|
|
|
|
def main():
|
|
pygame.init()
|
|
screen = pygame.display.set_mode((600, 600))
|
|
clock = pygame.time.Clock()
|
|
running = True
|
|
font = pygame.font.Font(None, 16)
|
|
text = font.render(
|
|
"Use Arrows (up, down, left, right) to move the camera, "
|
|
"a and z to zoom in / out and s and x to rotate.",
|
|
True,
|
|
pygame.Color("black"),
|
|
)
|
|
|
|
### Physics stuff
|
|
space = pymunk.Space()
|
|
space.gravity = Vec2d(0.0, 900.0)
|
|
draw_options = pymunk.pygame_util.DrawOptions(screen)
|
|
|
|
## Balls
|
|
balls = []
|
|
|
|
body = pymunk.Body()
|
|
body.position = pymunk.Vec2d(407, 354)
|
|
s1 = pymunk.Segment(body, Vec2d(-300, -30), Vec2d(0, 0), 1.0)
|
|
s2 = pymunk.Segment(body, Vec2d(0, 0), Vec2d(0, -100), 1.0)
|
|
s1.density = 0.1
|
|
s2.density = 0.1
|
|
s1.friction = 1
|
|
s2.friction = 1
|
|
space.add(body, s1, s2)
|
|
|
|
c1 = pymunk.constraints.DampedSpring(
|
|
space.static_body,
|
|
body,
|
|
(427, 200),
|
|
(0, -100),
|
|
Vec2d(407, 254).get_distance((427, 200)),
|
|
2000,
|
|
100,
|
|
)
|
|
|
|
c2 = pymunk.constraints.DampedSpring(
|
|
space.static_body,
|
|
body,
|
|
(87, 200),
|
|
(-300, -30),
|
|
Vec2d(107, 324).get_distance((87, 200)),
|
|
2000,
|
|
100,
|
|
)
|
|
space.add(c1, c2)
|
|
|
|
# extra to show how constraints are drawn when very small / large
|
|
body = pymunk.Body(1, 100)
|
|
body.position = 450, 305
|
|
c3 = pymunk.constraints.DampedSpring(
|
|
space.static_body, body, (450, 300), (0, 0), 5, 1000, 100
|
|
)
|
|
space.add(body, c3)
|
|
body = pymunk.Body(1, 100)
|
|
body.position = 500, 2025
|
|
c3 = pymunk.constraints.DampedSpring(
|
|
space.static_body, body, (500, 25), (0, 0), 2000, 1000, 100
|
|
)
|
|
space.add(body, c3)
|
|
|
|
ticks_to_next_ball = 10
|
|
|
|
translation = pymunk.Transform()
|
|
scaling = 1
|
|
rotation = 0
|
|
|
|
while running:
|
|
for event in pygame.event.get():
|
|
if (
|
|
event.type == pygame.QUIT
|
|
or event.type == pygame.KEYDOWN
|
|
and event.key == pygame.K_ESCAPE
|
|
):
|
|
running = False
|
|
elif event.type == pygame.KEYDOWN and event.key == pygame.K_p:
|
|
pygame.image.save(screen, "camera.png")
|
|
|
|
keys = pygame.key.get_pressed()
|
|
left = int(keys[pygame.K_LEFT])
|
|
up = int(keys[pygame.K_UP])
|
|
down = int(keys[pygame.K_DOWN])
|
|
right = int(keys[pygame.K_RIGHT])
|
|
|
|
zoom_in = int(keys[pygame.K_a])
|
|
zoom_out = int(keys[pygame.K_z])
|
|
rotate_left = int(keys[pygame.K_s])
|
|
rotate_right = int(keys[pygame.K_x])
|
|
|
|
translate_speed = 10
|
|
translation = translation.translated(
|
|
translate_speed * left - translate_speed * right,
|
|
translate_speed * up - translate_speed * down,
|
|
)
|
|
|
|
zoom_speed = 0.1
|
|
scaling *= 1 + (zoom_speed * zoom_in - zoom_speed * zoom_out)
|
|
|
|
rotation_speed = 0.1
|
|
rotation += rotation_speed * rotate_left - rotation_speed * rotate_right
|
|
|
|
# to zoom with center of screen as origin we need to offset with
|
|
# center of screen, scale, and then offset back
|
|
draw_options.transform = (
|
|
pymunk.Transform.translation(300, 300)
|
|
@ pymunk.Transform.scaling(scaling)
|
|
@ translation
|
|
@ pymunk.Transform.rotation(rotation)
|
|
@ pymunk.Transform.translation(-300, -300)
|
|
)
|
|
|
|
ticks_to_next_ball -= 1
|
|
if ticks_to_next_ball <= 0:
|
|
ticks_to_next_ball = 100
|
|
mass = 10
|
|
radius = 25
|
|
inertia = pymunk.moment_for_circle(mass, 0, radius, (0, 0))
|
|
body = pymunk.Body(mass, inertia)
|
|
x = random.randint(115, 350)
|
|
body.position = x, 100
|
|
if random.random() > 0.5:
|
|
shape = pymunk.Circle(body, radius)
|
|
else:
|
|
shape = pymunk.Poly.create_box(
|
|
body, size=(radius * 2, radius * 2), radius=2
|
|
)
|
|
shape.friction = 1
|
|
space.add(body, shape)
|
|
balls.append(shape)
|
|
|
|
### Clear screen
|
|
screen.fill(pygame.Color("white"))
|
|
|
|
### Draw stuff
|
|
space.debug_draw(draw_options)
|
|
|
|
balls_to_remove = []
|
|
for ball in balls:
|
|
if ball.body.position.y > 500:
|
|
balls_to_remove.append(ball)
|
|
|
|
for ball in balls_to_remove:
|
|
space.remove(ball, ball.body)
|
|
balls.remove(ball)
|
|
|
|
screen.blit(text, (5, 5))
|
|
|
|
### Update physics
|
|
dt = 1.0 / 60.0
|
|
space.step(dt)
|
|
|
|
### Flip screen
|
|
pygame.display.flip()
|
|
clock.tick(50)
|
|
pygame.display.set_caption("fps: " + str(clock.get_fps()))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|