[Pygame] masks collision

[Pygame] masks collision

Postby metulburr » Thu May 09, 2013 2:07 am

I know i asked this maybe even more than once. I couldnt find which on a quick scan of threads, as we tended to not stay on topic.

But, I can always get rect collsion to work eevery time, but the masks i think i did it right, but i just dont know why the last if cond is never executed.

I also dont know what the second arg to mask_overlap() means. The offset of the two masks? offset of what point? I just pulled a simple example from somewhere, as i dont really get it yet. Of course maybe thats why it is not being executed as i dont really know what i should be sending as the offset
Control.update()
Code: Select all
        if self.player.bullets:
            for obj in self.player.bullets:
                self.screen.blit(obj.surf, obj.rect)
                obj.rect[1] -= obj.speed
               
                #did obj move off screen
                if obj.rect[1] < 0:
                    self.player.bullets.remove(obj)
                #did obj hit enemy
                if obj.rect.colliderect(self.enemy.rect):
                    print('shot close or hit')
                    offset_x = obj.rect[0] - self.enemy.rect[0]
                    offset_y = obj.rect[1] - self.enemy.rect[1]
                    if obj.mask.overlap(self.enemy.mask, (offset_x, offset_y)):
                        print('enemy hit')
New Users, Read This
version Python 3.3.2 and 2.7.5, tkinter 8.5, pyqt 4.8.4, pygame 1.9.2 pre
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
User avatar
metulburr
 
Posts: 1107
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: [Pygame] masks collision

Postby Mekire » Thu May 09, 2013 2:25 am

Close. Two problems; one of which always gets me too.

if you make a surface like this:
Code: Select all
MySurf=pygame.Surface((50,50)).convert()
MySurf.fill((255,255,255))
and then you do this:
Code: Select all
MyMask = pygame.mask.from_surface(MySurf)
the method automatically uses the topleft pixel color as the non-filled color for the mask.

You need to set a color code so it knows what color is transparent, even if the image doesn't contain any of this color.

Next, you just got some coordinates backwards. Should be this:
Code: Select all
offset_x =  self.enemy.rect.x - obj.rect.x
offset_y =  self.enemy.rect.y - obj.rect.y
if obj.mask.overlap(self.enemy.mask, (offset_x, offset_y)):
    print('enemy hit')

Anyway... this works:
Code: Select all
import pygame,sys

def image_from_url(url):
    try:
        from urllib2 import urlopen
        from cStringIO import StringIO as inout
    except ImportError:
        from urllib.request import urlopen
        from io import BytesIO as inout
    myurl = urlopen(url)
    return inout(myurl.read())

class Projectile:
    limit = 3
    def __init__(self, loc):
        self.surf = pygame.Surface((5,10)).convert()
        self.surf.set_colorkey((255,0,255))
        self.surf.fill((255,255,255))
        self.rect = self.surf.get_rect()
        self.rect.center = loc
        self.mask = pygame.mask.from_surface(self.surf)
        self.speed = 8

class Enemy:
    def __init__(self):
        link = 'http://i1297.photobucket.com/albums/ag23/metulburr/spaceship_enemy3_zpscfeb13bf.png'
        self.orig_image = pygame.image.load(image_from_url(link)).convert()
        self.orig_image = pygame.transform.scale(self.orig_image, (40,80))
        self.orig_image.set_colorkey((255,0,255))
        self.image = pygame.transform.rotate(self.orig_image, 180)
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.image.get_rect()



class Player:
    def __init__(self):
        self.speed = 4

        link = 'http://i1297.photobucket.com/albums/ag23/metulburr/spaceship2_zps095c332a.png'
        self.orig_image = pygame.image.load(image_from_url(link)).convert()
        self.orig_image = pygame.transform.scale(self.orig_image, (40,80))
        self.orig_image.set_colorkey((255,0,255))

        self.image = pygame.transform.rotate(self.orig_image, 180)
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.image.get_rect()

        self.bullets = []

    def move(self, x, y):
        self.rect[0] += x * self.speed
        self.rect[1] += y * self.speed


class Control:
    def __init__(self):
        self.screensize = (800,600)
        self.screen = pygame.display.set_mode(self.screensize)
        self.screenrect = self.screen.get_rect()
        self.clock = pygame.time.Clock()
        self.player = Player()
        self.enemy = Enemy()


        self.mainloop()

    def mainloop(self):
        run = True
        while run:
            self.screen.fill((0,0,0))

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    run = False
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_SPACE:
                        if len(self.player.bullets) <= Projectile.limit:
                            self.player.bullets.append(Projectile(self.player.rect.center))

            self.update()
            pygame.display.flip()
            self.clock.tick(60)

    def update(self):
        self.keys = pygame.key.get_pressed()

        if self.player.bullets:
            for obj in self.player.bullets:
                self.screen.blit(obj.surf, obj.rect)
                obj.rect[1] -= obj.speed

                #did obj move off screen
                if obj.rect[1] < 0:
                    self.player.bullets.remove(obj)
                #did obj hit enemy
                if obj.rect.colliderect(self.enemy.rect):
                    print('shot close or hit')
                    offset_x =  self.enemy.rect.x - obj.rect.x
                    offset_y =  self.enemy.rect.y - obj.rect.y
                    if obj.mask.overlap(self.enemy.mask, (offset_x, offset_y)):
                        print('enemy hit')

        if self.keys[pygame.K_UP]:
            self.player.move(0,-1)
        if self.keys[pygame.K_DOWN]:
            self.player.move(0,1)
        if self.keys[pygame.K_RIGHT]:
            self.player.move(1,0)
        if self.keys[pygame.K_LEFT]:
            self.player.move(-1,0)

        self.player.rect.clamp_ip(self.screenrect) #make sure rect does not go outside of screen
        self.screen.blit(self.enemy.image, self.enemy.rect)
        self.screen.blit(self.player.image, self.player.rect)

app = Control()
pygame.quit();sys.exit()

-Mek
User avatar
Mekire
 
Posts: 818
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: [Pygame] masks collision

Postby metulburr » Thu May 09, 2013 2:33 am

You need to set a color code so it knows what color is transparent, even if the image doesn't contain any of this color.


hmm, ok. I am sure i will do this 100's more times, lol.
ok so i need to set a colorkey for every mask, reagardless

ok cool thanks.
New Users, Read This
version Python 3.3.2 and 2.7.5, tkinter 8.5, pyqt 4.8.4, pygame 1.9.2 pre
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
User avatar
metulburr
 
Posts: 1107
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY


Return to Game Development

Who is online

Users browsing this forum: No registered users and 1 guest