Reputation: 415
I'm making a CheckButton Widget to be able to use in game menus. Wondering how I might be able to check if the mouse is colliding with the circle? Using the self.surface.get_rect() method doesn't seem to work. is there a way to calculate where the circle is based on its location in its surface object? I was just going to just draw a smaller black circle inside the circle when self.active == True then back to its default color if its False. should I be using Sprites for this?
class CheckButton():
"""add label?"""
def __init__(self, screen, pos,size=(10,10),color=GREY):
self.screen = screen
self.pos = pos
self.size = size
self.color = color
self.active = False
self.surface = pygame.surface.Surface(self.size)
self.rect = self.surface.get_rect()
self.center = (5,5)
def check_for_click(self):
pos = pygame.mouse.get_pos()
mouseClicked = pygame.mouse.get_pressed()
if self.rect.collidepoint(pos) and mouseClicked == (1,0,0):
self.active = True
print(self.active)
def draw(self):
self.surface.fill(BG_COLOR)
pygame.draw.circle(self.surface,self.color, self.center,5, 0)
self.screen.blit(self.surface, self.pos)
Upvotes: 1
Views: 376
Reputation: 101052
When using pygame, don't give your objects attributes like pos
or center
(if you don't have to for whatever reasons). Just use the pygame's Sprite
and Rect
classes, which will handle all these things for you.
Here's a running example. Note the comments for further explanations:
import pygame
from math import hypot
pygame.init()
screen = pygame.display.set_mode((400, 400))
BG_COLOR=(55,0,200)
# note that pygame comes with a lot of colors already defined in THECOLORS
GREY=pygame.color.THECOLORS['grey']
# pygame's Group is great for sprite handling, but it does not offer a function for event handling
# so we create our own simple Group
class EventAwareGroup(pygame.sprite.Group):
def handle(self, event):
for spr in self.sprites():
if hasattr(spr, 'handle'):
spr.handle(event)
class CheckButton(pygame.sprite.Sprite):
def __init__(self, pos, size=(10,10), color=(255,100,200)):
super().__init__()
self.image = pygame.surface.Surface(size)
# we use a random color as colorkey, which means this color acts
# as a substitute for 'transparent'; so we don't have to care about the
# actual background
self.image.set_colorkey((99,32,127))
self.image.fill((99,32,127))
self.rect = self.image.get_rect()
# our image is a simple circle
# note how we can use the attributes of Rect to easily find the center of our Surface
pygame.draw.circle(self.image, color, self.rect.center, size[0]//2, 0)
# when the checkbox is active, we want to show another image, so let's create it here
# we want to do the drawing once, so we do it in the __init__ function
self.toggle_image = self.image.copy()
pygame.draw.circle(self.toggle_image, (0, 0, 0), self.rect.center, size[0]//3, 0)
# now let's position our checkbox at 'pos'
self.rect.center = pos
self.active = False
def handle(self, event):
# since we want to toggle the active state of the checkbox when a mouse click occurs,
# it's better to listen for the MOUSEBUTTONDOWN event
if event.type == pygame.MOUSEBUTTONDOWN:
# to check if the mouse click was actually in the circle, we simple calculate the distance
d = hypot(event.pos[0] - self.rect.center[0], event.pos[1] - self.rect.center[1])
if d <= self.rect.width/2 and event.button == 1:
# now let's toggle the active flag and the images
self.active = not self.active
self.image, self.toggle_image = self.toggle_image, self.image
c = CheckButton([150, 100], [100, 100])
g = EventAwareGroup(c)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
g.handle(event)
# note how simple and clean our main loop is
# when we need other sprites, just add them to the g Group
# no need to change the main loop for that
screen.fill(BG_COLOR)
g.update()
g.draw(screen)
pygame.display.update()
Upvotes: 2