2011-01-13 4 views
1

J'essaye d'utiliser la détection de collision pour détecter quand ma souris frappe une image que j'ai importée. Je reçois l'erreur « tuple n'a pas d'attribut rect »Détection de collision utilisant des sprites dans Pygame

def main(): 


    #Call the SDL arg to center the window when it's inited, and then init pygame 
    os.environ["SDL_VIDEO_CENTERED"] = "1" 
    pygame.init() 

    #Set up the pygame window 
    screen = pygame.display.set_mode((600,600)) 


    image_one = pygame.image.load("onefinger.jpg").convert() 

    screen.fill((255, 255, 255)) 
    screen.blit(image_one, (225,400)) 
    pygame.display.flip() 

    while 1: 
     mousecoords = pygame.mouse.get_pos() 
     left = (mousecoords[0], mousecoords[1], 10, 10) 
     right = image_one.get_bounding_rect() 
     if pygame.sprite.collide_rect((left[0]+255, left[1]+400, left[2], left[3]), right): 
      print('Hi') 

Répondre

1

Le problème est que pygame.sprite.collide_rect() prend deux objets Sprite. Vous lui passez deux tuples - ni le curseur ni l'image ne sont des sprites et manquent donc d'un attribut rect.

Vous pouvez créer un Sprite en utilisant image_one, mais il sera plus difficile de convertir le curseur en Sprite. Je pense qu'il serait plus facile de tester manuellement si le curseur est dans l'image.

#Set up the pygame window 
screen = pygame.display.set_mode((200,200)) 
screen.fill((255, 255, 255)) 

#Set up image properties (would be better to make an object) 
image_one = pygame.image.load("image_one.png").convert() 
image_x = 225 
image_y = 400 
image_width = image_one.get_width() 
image_height = image_one.get_height() 

# Mouse properties 
mouse_width = 10 
mouse_height = 10 

screen.blit(image_one, (image_x, image_y)) 
pygame.display.flip() 

while 1: 
    for event in pygame.event.get(): 
     if event.type == pygame.MOUSEMOTION: 
      mouse_x, mouse_y = pygame.mouse.get_pos() 

      # Test for 'collision' 
      if image_x - mouse_width < mouse_x < image_x + image_width and image_y - mouse_height < mouse_y < image_y + image_height: 
       print 'Hi!' 

Notez que je teste si la souris est déplacé avant de tester que ce soit dans l'image, pour éviter de répéter le calcul inutilement.

+0

Excellente aide! J'ai trouvé un moyen encore plus simple de le résoudre. Lorsque vous "blit" une image à un écran, il renvoie un Rect. Vous affectez simplement une variable égale à ce rect, à savoir: FirstL_Rect = screen.blit (image_one, (185,400)), puis effectuez une détection de collision à l'aide de la fonction "colliderect". Vous pouvez également transformer votre mous einto rect en: mousecoords = pygame.mouse.get_pos() coordinateRect = Rect (mots de passe [0], mousecoords [1], 10, 10) – Parseltongue

+0

Nice one. Je n'avais pas réalisé que le blitting renvoyait un Rect. C'est très utile à savoir. –

+0

@Parseltongue: vous n'avez pas besoin d'utiliser le rect renvoyé par '.blit()': 'image_one' est un * Surface *, et en tant que tel vous pouvez toujours obtenir son rect avec' image_one.get_rect() '. Pas besoin de bliter du tout;) – MestreLion

0

Ce n'est pas lié à Pygame ou python, mais il peut aider.

Lazy Foo propose de nombreux tutoriels pour SDL, mais ils sont en C++. Ils sont extrêmement bien commentés cependant. Le lien vers eux est ici: http://www.lazyfoo.net/SDL_tutorials/index.php

0

Peter a suggéré, et vous avez aussi pensé à elle, qu'il est plus facile de travailler avec Rects au lieu de positions lorsqu'ils traitent avec la détection de collision.

je prendrais un peu plus loin: toujours travailler avec Sprites! Avec Sprites, vous avez accès à toutes ces fonctions de détection de collision très pratiques dans pygame.sprite

Et si jamais vous décidez de déplacer cette image, il est beaucoup plus facile de mettre à jour la position et d'animer. Il contient également la surface de l'image, le tout dans un seul objet. Sans oublier le sprite Groupes!

Sprites ont également un attribut .rect, de sorte que vous pouvez toujours faire manipulation rect bas niveau si vous voulez avec mysprite.rect

Cela dit, voici comment vous pouvez obtenir un sprite de votre image:

image_one = pygame.sprite.Sprite() 
image_one.image = pygame.image.load("image_one.png").convert() 
image_one.rect = pygame.Rect((image_x, image_y), image_one.image.get_size()) 

créer plus sprites pour image_two, _three, etc. ou créer une fonction (ou, mieux encore, sous-classe Sprite), position de réception et nom de fichier comme arguments, de sorte que vous pouvez créer sprites dans une seule ligne comme:

image_two = MySprite(filename, x, y) 

que vous pouvez désormais équiper en option les regrouper:

my_images = pygame.sprite.Group(image_one, image_two, image_three) 

Le dessin est aussi facile que:

my_images.draw(screen) 

Ce sera blit toutes les images à la fois, un chacun dans leur propres positions! Cool hein?

Créons un Sprite « faux » pour le curseur de la souris:

mouse = pygame.sprite.Sprite() 
mouse.rect = pygame.Rect(pygame.mouse.get_pos(), (1, 1)) 

Je l'ai fait un sprite 1x1 il entrer en collision uniquement sur hotspot de la souris. Notez qu'il n'a pas d'attribut .image (d'où le pseudo "sprite"), mais pygame s'en fout puisque nous n'allons pas le dessiner de toute façon.

Et maintenant la meilleure partie:

imagehit = pygame.sprite.spritecollideany(mouse, my_images) 
print imagehit 

En une seule ligne vous avez testé une collision contre toutes les images, et vous savez non seulement si la souris est entré en collision avec tout, mais aussi que l'on c'est fait! Il est vraiment payant d'utiliser Sprites;)