Search code examples
pythonpygamebox2d

python box2d pygame screen coordinates to box2d grid


I can't figure out the proper way to get the world coordinates from the mouse coords.

In issues like this: mouseWorld Coordinates Box2D there is a method: box2d.coordPixelsToWorld(x,y); but I can't find this method in the Python library for box2d.

position = pygame.mouse.get_pos() 

position = ??? * ??? 

body.position = position

More Code for Context:


PPM = 20.0  # pixels per meter
TARGET_FPS = 60
TIME_STEP = 1.0 / TARGET_FPS
SCREEN_WIDTH, SCREEN_HEIGHT = 1280, 720  # 640, 480

# --- pygame setup ---
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), 0, 32, display=1)
pygame.display.set_caption('Simple pygame example')
clock = pygame.time.Clock()

body = world.CreateStaticBody(
        position=(i, 1),
        shapes=box2d.b2PolygonShape(box=(1, 1)),
    ))

bodies.append(body)

colors = {
    box2d.b2_staticBody: (255, 255, 255, 255),
    box2d.b2_dynamicBody: (127, 127, 127, 255),
}

# --- main game loop ---
running = True
while running:
    # Check the event queue
    for event in pygame.event.get():
        if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
            # The user closed the window or pressed escape
            running = False

    screen.fill((0, 0, 0, 0))
    
    position = pygame.mouse.get_pos() 

    position = ??? * ??? 

    body.position = position

    for body in bodies:  # or: world.bodies
        # The body gives us the position and angle of its shapes
        # body
        for fixture in body.fixtures:
            # The fixture holds information like density and friction,
            # and also the shape.
            shape = fixture.shape

            # Naively assume that this is a polygon shape. (not good normally!)
            # We take the body's transform and multiply it with each
            # vertex, and then convert from meters to pixels with the scale
            # factor.
            vertices = [(body.transform * v) * PPM for v in shape.vertices]

            # But wait! It's upside-down! Pygame and Box2D orient their
            # axes in different ways. Box2D is just like how you learned
            # in high school, with positive x and y directions going
            # right and up. Pygame, on the other hand, increases in the
            # right and downward directions. This means we must flip
            # the y components.
            vertices = [(v[0], SCREEN_HEIGHT - v[1]) for v in vertices]

            pygame.draw.polygon(screen, colors[body.type], vertices)

    # Make Box2D simulate the physics of our world for one step.
    # Instruct the world to perform a single step of simulation. It is
    # generally best to keep the time step and iterations fixed.
    # See the manual (Section "Simulating the World") for further discussion
    # on these parameters and their implications.
    world.Step(TIME_STEP, 10, 10)

    # Flip the screen and try to keep at the target FPS
    pygame.display.flip()
    clock.tick(TARGET_FPS)

pygame.quit()

if __name__ == "__main__":
    print('Done!')

EDIT: The PPM value is the amount on pixels per meter. If I divide the pygame.mouse.get_pos().x with PPM it is the correct value. But the y value is off by 3 'meters'

EDIT2: Because it is (SCREEN_HEIGHT - y) / PPM


Solution

  • While not familiar with Box2d for Python, but if what you are looking for is to convert mouse X,Y to world X,Y just converting the mouse x,y with the Box2d conversion factor, PIXEL_PER_METERS or whatever you use, so f.ex float PIXEL_PER_METER = 100.f; thus screenpos 1200, 600 is 12,6 in "box2d units / meters"

    • and you've done that and are somewhat off, have you accounted for floating point / integer conversion? Python will after all call a C++ Box2d function, so make sure you're not converting any floats to integers , but on closer inspection it doesnt look like you are doing that.
    • Camera ScreenToWorld or WorldToScreen -> how are they implemented? I would think you have something along those lines somewhere, this problem is a fairly typical symptom of an issue in the Camera function.

    But the answer to how to convert mouse to world is: -if you want world in Box2d units: convert with the scaling factor -add the Camera.Offset value to the mouse x,y to get world position

     Camera.MinWorld  <- update this depending on what camera is focused on
    
     Mouse.x + Camera.MinWorld.x , Mouse.y + Camera.MinWorld.y = world position
    

    world pos to screenpos: pos.x - Camera.MinWorld.x , pos.y - Camera.MinWorld.y