How to detect collision/mouse-over between the mouse and a sprite?

Goal: to know when a sprite is clicked / active with the mouse

Using: Python 3.2 64bit, Pygame 1.92 64bit, windows 7 64bit

I spend 6 hours to no avail...I've tried :

s.rect.collidepoint(pygame.mouse.get_pos())
s.collidepoint(pygame.mouse.get_pos())
s.sprite.spritecollide(pygame.mouse.get_pos())
s.spritecollide(pygame.mouse.get_pos())
s.sprite.collide_rect(pygame.mouse.get_pos())
s.collide_rect(pygame.mouse.get_pos())

I've also tried turning the mouse location, which I really don't want to do, like someone else mentioned here on another post, into a sprite and collide like that with the same results ;(

I'm able to successfully mouse-collide with an image, but as soon as I turn the image into a sprite class, it becomes a nightmare...what's wrong with the sprite class? Or am I wasting time trying to use sprites for the nice collision features and just use images with rect collision instead?

Keep on getting the AttributeError: 'Sheldon' object has no attribute 'Rect' (s.Rect.collidepoint) or AttributeError: 'tuple' object has no attribute 'collidepoint' (s.collidepoint) or AttributeError: 'Rake' object has no attribute 'sprite' (s.sprite.collidepoint)

Since I'm new to python/pygame, should I be putting this detection in an Update/Render method in the sprite class itself, or am I using the wrong event polling???

I haven't bothered trying to recode the mousedown/up/dragging since I can't even get the mouse-over to work

Hopefully this time the post gets a working response...the others didn't ;(

Thanks for your help.

Code:

import pygame
from pygame import *
from pygame.locals import *
from pygame.sprite import *

class Sheldon(Sprite):
    def __init__(self):
        Sprite.__init__(self)
        self.image = transform.scale(image.load('sheldon.jpg').convert(),(230,310))
        self.rect = self.image.get_rect()

class Rake(Sprite):
    def __init__(self):
        Sprite.__init__(self)
        self.image = transform.scale(image.load('rake.jpg').convert(),(230,310))
        self.rect = self.image.get_rect()

class Sprite_Mouse_Location(Sprite):
    def __init__(self,x,y):
        Sprite.__init__(self)
        self.rect = pygame.Rect(x,y,1,1)
        print(self.rect)

pygame.init()
window = display.set_mode( (800,600) )
sheldon = Sheldon()
sheldon.rect = (10,10)
all_sprites = Group(sheldon)
rake = Rake()
rake.rect = (400,250)
all_sprites.add(rake)
x,y = pygame.mouse.get_pos()
mouse_sprite = Sprite_Mouse_Location(x,y)
running = True

while running == True:
    for event in pygame.event.get():
        if event.type == QUIT or event.type == KEYUP and event.key == K_ESCAPE :
            pygame.quit()

        elif event.type == MOUSEMOTION :
            for s in all_sprites : 
                if pygame.sprite.collide_rect(s,mouse_sprite):
                    print("hit")

    window.fill( (0,0,0) )
    all_sprites.update()
    all_sprites.draw(window)
    display.update()

Upvotes: 1

Views: 11771

Answers (3)

furas
furas

Reputation: 143197

You don't need Sprite_Mouse_Location.

BTW: to set position you need

rake.rect.topleft = (400, 250)

# or 

rake.rect.x = 400
rake.rect.y = 250

not

rake.rect = (400, 250)

because it replace pygame.Rect() with tuple


Example code:

I use Surface instead of image.load() so everyone can run it without images.

import pygame

# --- constants --- (UPPER_CASE names)

BLACK = (0, 0, 0)
RED   = (255, 0, 0)
GREEN = (0, 255, 0)

# --- classes --- (CamelCase names)

class Sheldon(pygame.sprite.Sprite):

    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.Surface((230, 310))
        self.image.fill(RED)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

    def check_click(self, mouse):
        if self.rect.collidepoint(mouse):
            print("hit RED")

class Rake(pygame.sprite.Sprite):

    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.Surface((230, 310))
        self.image.fill(GREEN)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

    def check_click(self, mouse):
        if self.rect.collidepoint(mouse):
            print("hit GREEN")

# --- main --- (lower_case names)

# - init -

pygame.init()
window = pygame.display.set_mode((800,600))

# - objects -

sheldon = Sheldon(10, 10)
#sheldon.rect.topleft = (10, 10)

rake = Rake(400, 250)
#rake.rect.topleft = (400, 250)

all_sprites = pygame.sprite.Group()
all_sprites.add(sheldon, rake)

# - mainloop -

running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT or \
           (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            running = False

        elif event.type == pygame.MOUSEBUTTONDOWN:
            for s in all_sprites:
                s.check_click(event.pos)

    window.fill(BLACK)
    all_sprites.update()
    all_sprites.draw(window)
    pygame.display.update()

# - end -     

pygame.quit()

Upvotes: 2

thanks to alanxoc3 and a new day, code working posting here because I'm sure another newbie is going to want to do this type of mouse click

# to create a group of sprites and use the mouse over them individually
import pygame
from pygame import *
from pygame.locals import *
from pygame.sprite import *

class Sheldon(Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self,self.groups) #have to have groups here, not documented well
        self.image = transform.scale(image.load('sheldon.jpg').convert(),(230,310))
        self.rect = self.image.get_rect()

    def clickCheck(self,smouse):
        if pygame.sprite.collide_rect(smouse, self): #could not use sritecollison because it would flag whole group
            print('hit sheldon') # this if the check mouse that its working
#------------------------------------------
class Rake(Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self,self.groups)
        self.image = transform.scale(image.load('rake.jpg').convert(),(230,310))
        self.rect = self.image.get_rect()

    def clickCheck(self,smouse):
        if pygame.sprite.collide_rect( smouse, self ):
            print('hit rake')
#-------------------------------------------        
class Sprite_Mouse_Location(Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.rect = pygame.Rect( 0 , 0 , 1 , 1 ) # no updating needed here
#--------------------------------------------        
pygame.init()
window = display.set_mode( (800,600) )
mouse_sprite = Sprite_Mouse_Location() # had to create a mouse as sprite to use the sprite collision feature
all_sprites = pygame.sprite.Group() # have to declare first, no well documented
Sheldon.groups = all_sprites        # better than all_sprites = Group(sheldon), and can be assigned before instantiation of sheldon!!!
sheldon = Sheldon()
sheldon.rect = (10,10,230,310)
Rake.groups = all_sprites
rake = Rake()
rake.rect = (400,250,230,310)
running = True

while running == True:

    for event in pygame.event.get():

        if event.type == QUIT or event.type == KEYUP and event.key == K_ESCAPE :
            pygame.quit()

        elif event.type == MOUSEBUTTONDOWN:  
            if event.button == 1:
                mouse_sprite.rect.x , mouse_sprite.rect.y = pygame.mouse.get_pos() # have to have this to update mouse here or get wrong location 
                for s in all_sprites: #can't have outside the event or it will continuously check
                    s.clickCheck(mouse_sprite)

    window.fill( (0,0,0) )
    all_sprites.update() # have to have this for group sprites
    all_sprites.draw(window) # have to have this for sprites
    display.flip()

Upvotes: 0

user1159789
user1159789

Reputation:

There are a lot of things that are going on with your code. Coding can be hard at first, but keep sticking to! You'll better as long as you keep trying and don't give up! Your error is occurring because above the loop, you are setting your various sprites' rect variables to tuples instead of rects. Rects are not tuples, they have a bunch of variables that tuples don't have and collide_rect needs some of those variables. I put a couple comments in the code below about your other questions.

import pygame
from pygame import *
from pygame.locals import *
from pygame.sprite import *

class Sheldon(Sprite):
    def __init__(self):
        Sprite.__init__(self)
        self.image = transform.scale(image.load('sheldon.jpg').convert(),(230,310))
        self.rect = self.image.get_rect()

class Rake(Sprite):
    def __init__(self):
        Sprite.__init__(self)
        self.image = transform.scale(image.load('rake.jpg').convert(),(230,310))
        self.rect = self.image.get_rect()

class Sprite_Mouse_Location(Sprite):
    def __init__(self,x,y):
        Sprite.__init__(self)
        self.rect = pygame.Rect(x,y,1,1)
        print(self.rect)

pygame.init()
window = display.set_mode( (800,600) )
sheldon = Sheldon()
sheldon.rect = (10,10) # (10,10) is not a rect!
                       # pygame.Rect(0,0,10,10) is a rect!
all_sprites = Group(sheldon)
rake = Rake()
rake.rect = (400,250) # Same as above comment.
all_sprites.add(rake)
x,y = pygame.mouse.get_pos()              # If you are going to make the mouse
mouse_sprite = Sprite_Mouse_Location(x,y) # a sprite, then update your mouse position in the loop.
running = True

while running == True:
    for event in pygame.event.get():
        if event.type == QUIT or event.type == KEYUP and event.key == K_ESCAPE :
            pygame.quit()

        elif event.type == MOUSEMOTION :
            # You could have this instead.
            # mouse_sprite.rect.x, mouse_sprite.rect.y = pygame.mouse.get_pos()
            # Then move the for loop below to be out of the event loop.

            for s in all_sprites : 
                if pygame.sprite.collide_rect(s,mouse_sprite):
                    print("hit")

    window.fill( (0,0,0) )
    all_sprites.update()
    all_sprites.draw(window)
    display.update()

I'd also recommend going through a pygame tutorial as well as looking at other people's pygame code and trying to understand it line by line. Both those tips helped me out. Good luck.

Upvotes: 0

Related Questions