Creating multiple interactive polygon buttons in Pygame

Viewed 204

My goal is to create a lot of polygon button. For example, if I input a number of 6, I want to have 6 polygons.

For example:

import pygame
pygame.init()
SIZE_X = SIZE_Y = 600
screen = pygame.display.set_mode((SIZE_X, SIZE_Y), pygame.RESIZABLE )
red = (255, 0 , 0)

NB_POLYGONS = 6
for i in range(NB_POLYGONS):
      polygons = [ ( x1 + i * 50,y1) , ( x2 + i * 50,y2), ( x3 + i * 50,y3)]#With xn and yn some random cords
      pygame.draw.polygon(screen,red, polygons)

This example works and creates 6 polygons. But how can I make them responsive? For example by clicking on one of them to switch it to blue. In the code I provided I've put 3 points in the polygon, but I want to know if it's possible to do this with an arbitrary polygon.

2 Answers

pygame.draw.polygon() returns a pygame.Rect bounding the changed pixels. Test if the mouse is in the rectangle and draw the polygon again with a different color:

for i in range(NB_POLYGONS):
    points = [(x1 + i*50, y1), (x2 + i*50, y2), (x3 + i*50, y3)]
    bounding_rect = pygame.draw.polygon(screen, 'red', points)
    if bounding_rect.collidepoint(pygame.mouse.get_pos()):
        pygame.draw.polygon(screen, 'blue', points)

If you restrict it to only convex polygons, you can get pixel perfect precision by checking whether the mouse-click intersects it. This can be done by creating triangles between each consecutive vertex in the polygon and checking whether any of them intersects the point.

Checking for intersection between a point and a triangle can be done with Heron's formula.

Here's a minimal example:

def collide(point, polygon):
    assert len(polygon) >= 3, "A polygon must have at least 3 vertices."

    px, py = point
    n = len(polygon)

    for i in range(n):
        x0, y0 = polygon[i]
        x1, y1 = polygon[(i+1) % n]
        x2, y2 = polygon[(i+2) % n]

        area1 = abs((x0-px)*(y1-py) - (x1-px)*(y0-py));
        area2 = abs((x1-px)*(y2-py) - (x2-px)*(y1-py));
        area3 = abs((x2-px)*(y0-py) - (x0-px)*(y2-py));

        area = abs((x1-x0)*(y2-y0) - (x2-x0)*(y1-y0));
        if area1 + area2 + area3 == area:
            return True

    return False


print(collide(point=(10, 10), polygon=[(5, 5), (5, 10), (10, 10), (10, 5)]))  # True
print(collide(point=(20, 10), polygon=[(5, 5), (5, 10), (10, 10), (10, 5)]))  # False
Related