开发者

Collision detection using sprites in Pygame

I'm trying to use collision detection to detect when my mouse hits an image that I've imported. I get the error "tuple does not have attribute rect"

 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,开发者_JAVA百科 left[2], left[3]), right):
            print('Hi')


Peter suggested, and you also figured it out, that it's easier to work with Rects instead of positions when dealing with collision detection.

I would take that one step further: always work with Sprites!

With Sprites you get access to all those handy collision detection functions in pygame.sprite. And if you ever decide to move that image around, it's much easier to update position and animate. It also contains the image surface, all in a single object. Not to mention sprite Groups!

Sprites also have a .rect attribute, so you can always do low level rect manipulation if you want to with mysprite.rect

That said, here's how you can get a Sprite out of your 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())

Create more sprites for image_two, _three, etc. Or create a function (or, even better, subclass Sprite), receiving position and filename as arguments, so you can create sprites in a single line as:

image_two = MySprite(filename, x, y)

Now you can optionally group them:

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

Drawing is as easy as:

my_images.draw(screen)

That will blit all images at once, each one in their own positions! Cool, huh?

Let's create a "fake" Sprite for the mouse cursor:

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

I've made it a 1x1 sprite so it only collide on mouse hotspot. Notice that it does not have an .image attribute (hence "fake" sprite), but pygame does not care since we're not going to draw it anyway.

And now the best part:

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

In a single line you tested collision against all images, and not only you know if the mouse collided with any, but also which one it did!

It really pays off to use Sprites ;)


The problem is that pygame.sprite.collide_rect() takes two Sprite objects. You are passing it two tuples - neither the cursor nor the image are Sprites and so lack a rect attribute.

You could make a Sprite using image_one, but it will be more tricky to convert the cursor into a Sprite. I think it would be easier to manually test whether the cursor is within the 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!'

Notice that I test whether the mouse has moved before testing whether it's in the image, to avoid repeating the calculation needlessly.


This isn't related to pygame or python, but may help.

Lazy Foo has a number of great tutorials for SDL, but they are in C++. They are extremely well commented though. The link to them is here: http://www.lazyfoo.net/SDL_tutorials/index.php

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜