pythonpygamepymunk

Get the updated coordinates of a pymunk rotating kinetic body


Below is a rotating kinetic pymunk body with a mass in it. Is there a way to get the midpoint of the top horizontal section of "body_type" once the animation has started playing. Initially, the point on the kinetic body I am interested in has the coordinates (400,500). How do I print the updated coordinates of the point in question once the rotation has begun

import pymunk
import pymunk.pygame_util
import pygame

GRAY = (220, 220, 220)

width_mass=50
height_mass=50

pygame.init()
size = 800,600
screen = pygame.display.set_mode(size)
draw_options = pymunk.pygame_util.DrawOptions(screen)

space = pymunk.Space()
space.gravity = (0,-50)

pts = [(-27, -238.5), (27,-238.5), (27,238.5), (-27,238.5)]
body_type=pymunk.Body(body_type=pymunk.Body.KINEMATIC)  
body_type.position = (400, 263.5)  
space.add(body_type)
for i in range(4):
    segment = pymunk.Segment(body_type, pts[i], pts[(i+1)%4], 2)
    segment.elasticity = 0
    segment.friction=0
    space.add(segment)

body_type.angular_velocity=1

body = pymunk.Body(mass=1, moment=100)
body.position = 400,400

mass = pymunk.Poly.create_box(body, (width_mass, height_mass))
mass.elasticity = 0
space.add(body, mass)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
            #pygame.image.save(screen, 'intro1.png')

    screen.fill(GRAY)
    space.debug_draw(draw_options)
    pygame.display.update()
    space.step(0.01)

Solution

  • The current position of a Body is stored in the position attribute (e.g. space.bodies[0].position).
    PyGame uses a coordinate system where the top left corner is (0, 0).The y-axis needs to be reversed (screen.get_height() - pos[1]) as the y-axis is generally pointing up, but in the PyGame coordinate system the y-axis is pointing down.

    running = True
    while running:
        # [...]
    
        # draw a dot in at the center of the bodies
        for body in space.bodies:
            pos = body.position
            pygame.draw.circle(screen, (255,0,0), (pos[0], screen.get_height()-pos[1]), 7)
    
        pygame.display.update()
        space.step(0.01)
    

    The current angle of a Body is stored in the angle attribute (e.g. body_type.angle).
    The current position of a point can be computed by adding the rotated relativ position to the absolute position. The rotated position can be computed by simple Trigonometry:

    pos = abs_pos[0] + rel_dist * math.cos(angle), abs_pos[1] + rel_dist * math.sin(angle)
    

    First you have to compute the relative Polar coordinates from the relative Cartesian coordinates:

    rel_pos = (0, 238.5)
    rel_dist, rel_angle = math.hypot(*rel_pos), math.atan2(rel_pos[1], rel_pos[0])
    

    Add the current angle to the the polar coordinate angle:

    angle = rel_angle + body_type.angle
    

    For instance:

    running = True
    while running:
        # [...]
    
        abs_pos = body_type.position
        rel_pos = (0, 238.5)
        rel_dist, rel_angle = math.hypot(*rel_pos), math.atan2(rel_pos[1], rel_pos[0])
        
        angle = rel_angle + body_type.angle
        pos = abs_pos[0] + rel_dist * math.cos(angle), abs_pos[1] + rel_dist * math.sin(angle)
        pygame.draw.circle(screen, (255, 255, 0), (pos[0], screen.get_height() - pos[1]), 7)
    
        pygame.display.update()
        space.step(0.01)
    

    Minimal example:

    import pymunk
    import pymunk.pygame_util
    import pygame
    import math
    
    GRAY = (220, 220, 220)
    width_mass=50
    height_mass=50
    pygame.init()
    
    size = 800,600
    screen = pygame.display.set_mode(size)
    draw_options = pymunk.pygame_util.DrawOptions(screen)
    
    space = pymunk.Space()
    space.gravity = (0,-50)
    
    pts = [(-27, -238.5), (27,-238.5), (27,238.5), (-27,238.5)]
    body_type=pymunk.Body(body_type=pymunk.Body.KINEMATIC)  
    body_type.position = (400, 263.5)  
    space.add(body_type)
    for i in range(4):
        segment = pymunk.Segment(body_type, pts[i], pts[(i+1)%4], 2)
        segment.elasticity = 0
        segment.friction=0
        space.add(segment)
    
    body_type.angular_velocity=0.5
    
    body = pymunk.Body(mass=1, moment=100)
    body.position = 400,400
    
    mass = pymunk.Poly.create_box(body, (width_mass, height_mass))
    mass.elasticity = 0
    space.add(body, mass)
    
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                #pygame.image.save(screen, 'intro1.png')
    
        screen.fill(GRAY)
        space.debug_draw(draw_options)
    
        for body in space.bodies:
            pos = body.position
            pygame.draw.circle(screen, (255, 0, 0), (pos[0], screen.get_height() - pos[1]), 7)
    
        abs_pos = body_type.position
        rel_pos = (0, 238.5)
        rel_dist, rel_angle = math.hypot(*rel_pos), math.atan2(rel_pos[1], rel_pos[0])
        angle = rel_angle + body_type.angle
        print( body_type.position.angle)
        pos = abs_pos[0] + rel_dist * math.cos(angle), abs_pos[1] + rel_dist * math.sin(angle)
        pygame.draw.circle(screen, (255, 255, 0), (pos[0], screen.get_height() - pos[1]), 7)
    
        pygame.display.update()
        space.step(0.01)