[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
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1562
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: 1131
Joined: Thu Feb 07, 2013 11:33 pm
Location: Asakusa, 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
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1562
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