1
\$\begingroup\$

Here is my problem: I am creating a game and I have a board made out of polygons (hexagons). I want to be able to click on the different tiles but I can't find a simple method. I understood how to detect a click on basic surfaces such as rectangle or pictures, but not with more complex shapes like hexagons. Is it possible to do so?

I first searched for a Pygame function close to this but I didn't find any. Then I searched for the sprites, and I think it is possible, but very long. And the last way I found was to simply detect the color. However I don't want to change the color of the tiles.

How can I detect a click on a polygon? (Hexagons specifically)

\$\endgroup\$
1
  • \$\begingroup\$ Do you have a regular tiling grid? If so, you can just apply some math to your clicked point to round it to the nearest hexagonal cell, without doing polygon tests on every displayed tile sprite. If you want help concocting such a function, you should show us your game's perspective, alignment of the hexagon grid, and the coordinate systems you use for screen space and tile space. \$\endgroup\$
    – DMGregory
    Apr 16, 2020 at 8:44

4 Answers 4

0
\$\begingroup\$

I am currently using PyGame to build a small RPG game project, and I can personally attest that there is no built-in way to do this, at least nothing that I could find in the documentation or forums. Which is obviously very annoying and took me a long time to figure out.

The way I solved it was by:

1. Having a game loop that detects all hardware inputs from the mouse or keyboard:

for event in pygame.event.get():

2. Checking if a particular event is a mouse click event:

if event.type == pygame.MOUSEBUTTONUP:

3. Getting the position on screen where the mouse clicked:

pygame.mouse.get_pos()

4. Checking if anything with a special "clickable" attribute is on the screen at that position, and doing appropriate actions. For example, if I wanted to check for a particular object to see if the cursor was over that object at the moment of the click, I would do:

if clickableObject.collidepoint(mousePosition):

Hopefully this helps!


Edit: I reread your question and am now realizing you wanted to know specifically about polygon detection, rather than general shape detection. Apologies if I was not answering your specific question. You may want to use something like Box2D for anything more complicated than a rectangular collision area, but most polygons should just be a matter of doing some more math.

\$\endgroup\$
1
\$\begingroup\$

I just ran into this issue when creating a board using triangles, I simply wanted to highlight whichever triangle the mouse was hovering over. As such I figured out:

When drawing the polygons you can simultaneously use the collidepoint() function to get a bool from the mouse position.

e.g.

if pg.draw.polygon(screen, white, polygon, 1).collidepoint(pg.mouse.get_pos()):
    pg.draw.polygon(screen, white, polygon, 0)
\$\endgroup\$
0
\$\begingroup\$

First, I want to thank you for your answer. I tried a method using the first 3 steps you gave, it worked (approximately) but it was not so optimized. I couldn't figur how to create a clickableObject using polygons. Then I discovered the masks, and using a mask on a polygon picture worked with the .collidepoint(pos). I hope it will work for my 70 polygons on the screen, but it worked just fine for one...

In my case I was using hexagons and I admit it is a very regular shape, I just find it strange that we could not use the "normal method".

Thanks again, and I hope I will one day play your RPG Pygame game.

~Definity

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Please do not use Answers to reply to another answer — that's what Comments are for, if you need to ask for clarification or suggest extra information for an existing answer. Please post in the Your Answer box only to share a new solution to the problem. \$\endgroup\$
    – DMGregory
    Apr 17, 2020 at 11:01
0
\$\begingroup\$

You can use pygame and PIL. I have this code:

import pygame, PIL.Image
pygame.init()

info = pygame.display.Info()
root = pygame.Surface((info.current_w, info.current_h))

def isPolygonInCords(pos: list, cordsOfPolygon):
    global info, root
    pygame.draw.polygon(root, (255, 255, 0), cordsOfPolygon)
    a = pygame.image.tostring(root, 'RGB')

    b = PIL.Image.fromBytes('RGB', (info.current_w, info.current_h), a)

    try:
        return b.getpixel(pos) == (255, 255, 0)

    except:
        return None
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .