Pygame click on image (not a rectangle)

This is the part of my code, where the problem is:

button = pygame.image.load("button1.png")
screen.blit(button, (100, 100))

This image looks like this:

[1

I need to increase a value of a variable, when the user clicks on the image.

I tryed some solutions, but most of them was drawing an "invisible" rectangle over the picture, and the variable's value vas increasing, even if someone clicked on the white space near the triangle.

Upvotes: 1

Views: 1364

Answers (3)

Valentino
Valentino

Reputation: 7361

You could use Surface.get_at() to check the color of the pixel where the mouse clicks. If it's the background color (white in your case) you consider it outside, otherwise is inside and you trigger the action.

Here a working example. The insideimage function checks that the click is inside the surface button (the rectangle) and checks the color of the pixel at mouse coordinates. Returns True if the click is inside the surface and the color is not white.
This works if the background color is not used again inside the image.

import sys
import pygame

SCREENWIDTH = 500
SCREENHEIGHT = 500

pygame.init()
screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))

button = pygame.image.load("button1.png")
screen.blit(button, (100, 100))

def insideimage(pos, rsurf, refcolor):
    """rsurf: Surface which contains the image
    refcolor: background color, if clicked on this color returns False
    """
    refrect = rsurf.get_rect().move((100, 100))
    pickedcol = screen.get_at(pos)
    return refrect.collidepoint(pos) and pickedcol != refcolor

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.MOUSEBUTTONUP:
            valid = insideimage(event.pos, button, (255, 255, 255, 255))
            #(255, 255, 255, 255) this is color white with alpha channel opaque
            print(valid)

    pygame.display.update()

Upvotes: 1

sloth
sloth

Reputation: 101042

It's quite easy with the mask module.

From the docs:

Useful for fast pixel perfect collision detection. A mask uses 1 bit per-pixel to store which parts collide.


First, create a Mask from the image

mask = pygame.mask.from_surface(button)

Then, when checking for the mouse click event, check if the point in the mask is set.

Here's a simple example:

import pygame

def main():
    pygame.init()
    screen = pygame.display.set_mode((480, 320))
    button = pygame.image.load('button.png').convert_alpha()
    button_pos = (100, 100)
    mask = pygame.mask.from_surface(button)
    x = 0
    while True:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                return
            if e.type == pygame.MOUSEBUTTONDOWN:
                try:
                    if mask.get_at((e.pos[0]-button_pos[0], e.pos[1]-button_pos[1])):
                        x += 1
                        print(x)
                except IndexError:
                    pass

        screen.fill((80,80,80))
        screen.blit(button, button_pos)
        pygame.display.flip()

main()

Example button.png for testing:

enter image description here

Upvotes: 3

Calvin Godfrey
Calvin Godfrey

Reputation: 2359

There's no easy way to do this in pygame other than manually calculating where the mouse is and figuring out if it's in the triangle or not.

The image you're loading (button1.png) is a square image, and so there's no way for pygame or any other library to know what it's "actual" shape is. You'll either have to do it yourself or be okay with the user being able to click on the white space.

Upvotes: 1

Related Questions