pygame collision detection question

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

41 Replies - 4691 Views - Last Post: 01 April 2013 - 12:18 AM Rate Topic: -----

#1 slidon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 29
  • Joined: 09-February 13

pygame collision detection question

Posted 26 February 2013 - 12:41 PM

Hi, I am creating a quite simple platformer style game. I have added collision detection so the player stops when he walks into a crate but though I've added the same thing for the top of the crate, the collision detection seem's to be ignored for a few frames and the player only stops when a bit of him is in the crate.
I'm using this code to detect the collision
if runner.rect.colliderect(crate):
            if runner.rect.y < runner.groundy:
                runner.reset_jump()


the collision detection works fine for the sides which use the same if statement as the collision detection for the top of the crate.
my image and rect are setup like this
self.image = pygame.image.load("runner.png").convert_alpha()
self.rect = self.image.get_rect()


thanks in advance!

Is This A Good Question/Topic? 0
  • +

Replies To: pygame collision detection question

#2 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 27 February 2013 - 12:29 AM

I feel that this is still really messy and a bit twitchy but perhaps it will help you. Here I use mask collision rather than rectangle collision (rectangles are still crucial mind you). It can be done either way, but eventually you will need to understand bitmasks anyway. As last time, the images are loaded from my photobucket so the code won't work if your computer isn't online when you run it.

import os,sys
import pygame as pg

class _Physics:
    def __init__(self):
        self.x_vel = 0.0
        self.y_vel = 0.0
        self.y_vel_i = 0.0
        self.grav = 20
        self.fall = False
        self.time = None
    def phys_update(self):
        if self.fall:
            if not self.time:
                self.time = pg.time.get_ticks()
            self.y_vel = self.grav*((pg.time.get_ticks()-self.time)/1000.0) + self.y_vel_i
        else:
            self.time = None
            self.y_vel = 0

class Player(_Physics):
    """Class representing our player."""
    def __init__(self, location,speed):
        _Physics.__init__(self)
        self.image = PLAY_IMG
        self.mask  = pg.mask.from_surface(self.image)
        self.speed = speed
        self.jump_power = 9
        self.rect = self.image.get_rect()
        self.rect.topleft = location

    def get_pos(self,Mask):
        """Caluclate where our player will end up this frame including collissions."""
        #Has the player walked off an edge?
        if not self.fall and not Mask.overlap_area(self.mask, (self.rect.x,self.rect.y+1)):
            self.fall = True
        #Has the player landed?
        elif self.fall and self.y_vel > 0 and Mask.overlap_area(self.mask, (self.rect.x,self.rect.y+int(self.y_vel))):
            while Mask.overlap_area(self.mask, (self.rect.x,self.rect.y+int(self.y_vel))):
                self.y_vel -= 1
            self.fall = False
            self.y_vel_i = 0
        #Has the player hit an obstacle above him?
        elif self.fall and self.y_vel < 0 and Mask.overlap_area(self.mask, (self.rect.x,self.rect.y+int(self.y_vel))):
            while Mask.overlap_area(self.mask, (self.rect.x,self.rect.y+int(self.y_vel))):
                self.y_vel += 1
            self.y_vel_i = 0
        #Is the player running into a wall?.
        if not Mask.overlap_area(self.mask, (self.rect.x+int(self.x_vel),self.rect.y)):
            self.rect.x += self.x_vel
        self.rect.y += self.y_vel

    def update(self,Surf,Mask):
        self.get_pos(Mask)
        self.phys_update()
        Surf.blit(self.image,self.rect)

class Block:
    """Class representing obstacles."""
    def __init__(self,location):
        self.image = BLOCK_IMG
        self.rect = self.image.get_rect()
        self.rect.topleft = location
    def update(self,Surf):
        Surf.blit(self.image,self.rect)

class Control:
    def __init__(self):
        self.state = "GAME"
        self.Player = Player((50,-50), 3)
        #Make some obstacles
        self.Obstacles = [Block((400,350)),Block((300,200)),Block((200,150))]
        for i in range(10):
            self.Obstacles.append(Block((i*50,400)))
        self.bg_mask = self.make_bg_mask() #Make a background mask for collission.
        self.Clock = pg.time.Clock()

    def event_loop(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.state = "QUIT"
            #Key down events.
            elif event.type == pg.KEYDOWN:
                if event.key in (pg.K_RIGHT,pg.K_d):
                    self.Player.x_vel = self.Player.speed
                elif event.key in (pg.K_LEFT,pg.K_a):
                    self.Player.x_vel = -self.Player.speed
                elif event.key == pg.K_SPACE and not self.Player.fall:
                    self.Player.y_vel_i = -self.Player.jump_power
                    self.Player.fall = True
                elif event.key == pg.K_ESCAPE:
                    self.state = "QUIT"
            #Key up events.
            elif event.type == pg.KEYUP:
                keys = pg.key.get_pressed()
                if event.key in (pg.K_RIGHT,pg.K_d):
                    if keys[pg.K_LEFT] or keys[pg.K_a]:
                        self.Player.x_vel = -self.Player.speed
                    else:
                        self.Player.x_vel = 0
                elif event.key in (pg.K_LEFT,pg.K_a):
                    if keys[pg.K_RIGHT or pg.K_d]:
                        self.Player.x_vel = self.Player.speed
                    else:
                        self.Player.x_vel = 0

    def update(self,Surf):
        Surf.fill((50,50,50))
        for obs in self.Obstacles:
            obs.update(Surf)
        self.Player.update(Surf,self.bg_mask)

    def main(self,Surf):
        """Our games infinite loop"""
        while True:
            if self.state == "GAME":
                self.event_loop()
                self.update(Surf)
            elif self.state == "QUIT":
                break
            pg.display.update()
            self.Clock.tick(65)

    def make_bg_mask(self):
        temp = pg.Surface(SCREENSIZE).convert_alpha()
        temp.fill((0,0,0,0))
        for obs in self.Obstacles:
            obs.update(temp)
        return pg.mask.from_surface(temp)

def image_from_url(url):
    """This function loads an image from an url.
    Ignore this if you just care about Pygame functionality.
    If you are interested however, the importing nonsense is there
    to make this work in both py2 and py3."""
    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()) #Return value can be loaded by pygame.image.load

###################
if __name__ == "__main__":
    os.environ['SDL_VIDEO_CENTERED'] = '1'
    pg.init()
    SCREENSIZE = (500,500)
    SCREEN = pg.display.set_mode(SCREENSIZE)
    face_url  = "http://i1192.photobucket.com/albums/aa340/Mekire/smallface.png"
    block_url = "http://i1192.photobucket.com/albums/aa340/Mekire/block.png"
    PLAY_IMG  = pg.image.load(image_from_url(face_url)).convert_alpha()
    BLOCK_IMG = pg.image.load(image_from_url(block_url)).convert()

    RunIt = Control()
    RunIt.main(SCREEN)
    pg.quit();sys.exit()


Hope that helps. Later I will attempt to clean it up and make it more efficient, but it should still be instructive.
-Mek
Was This Post Helpful? 0
  • +
  • -

#3 slidon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 29
  • Joined: 09-February 13

Re: pygame collision detection question

Posted 27 February 2013 - 01:17 PM

Hi, again. Thanks for writing the code! I have created a surface with these lines
self.bg_surface = pygame.Surface((640, 480)).convert_alpha()
self.bg_surface.fill((0, 0, 0, 0))

and changed colliderect with
if Mask.overlap_area(self.mask, (self.rect.x, self.rect.y + 1)):

but I get this error

AttributeError:' pygame.Surface' object has no attribute 'overlap_area'

I did some searching and I cant find an explanation of masks so if you no of one then please let me know!
thanks

oh and one more thing. What caused the weird rect collision problems?
Was This Post Helpful? 0
  • +
  • -

#4 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 27 February 2013 - 03:51 PM

Masks and rectangles and surfaces are different types of objects. When you want to do pixel perfect collision in a game you will have to use masks. A mask is an array bits set to zero or one corresponding to the pixels in your image.

Documentation here:Pygame mask documentation

Mask collision produces much more accurate results (assuming your sprites aren't just rectangles, but it takes slightly longer. The error you got happened because you called a Mask method with a Surface. I create my sprite masks with:
self.mask  = pg.mask.from_surface(self.image)
and I created my background mask with
def make_bg_mask(self):
    temp = pg.Surface(SCREENSIZE).convert_alpha()
    temp.fill((0,0,0,0))
    for obs in self.Obstacles:
        obs.update(temp)
    return pg.mask.from_surface(temp),temp

Because mask collision is a more expensive process sometimes people do initial collision tests with rectangles and then do mask tests if those come back positive.

Anyway... I simplified my code a little bit, still a bit twitchy; I will continue to try to improve it. Here is an update:
import os,sys
import pygame as pg

class _Physics:
    def __init__(self):
        self.x_vel = 0.0
        self.y_vel = 0.0
        self.y_vel_i = 0.0
        self.grav = 20
        self.fall = False
        self.time = None
    def phys_update(self):
        if self.fall:
            if not self.time:
                self.time = pg.time.get_ticks()
            self.y_vel = self.grav*((pg.time.get_ticks()-self.time)/1000.0) + self.y_vel_i
        else:
            self.time = None
            self.y_vel = 0

class Player(_Physics):
    """Class representing our player."""
    def __init__(self, location,speed):
        _Physics.__init__(self)
        self.image = PLAY_IMG
        self.mask  = pg.mask.from_surface(self.image)
        self.speed = speed
        self.jump_power = 9
        self.rect = self.image.get_rect()
        self.rect.topleft = location

    def get_pos(self,Mask):
        """Caluclate where our player will end up this frame including collissions."""
        #Has the player walked off an edge?
        if not self.fall and not self.overlap(Mask,(0,1)):
            self.fall = True
        #Has the player landed from a fall or jumped into an object above them?
        elif self.fall and self.y_vel and self.overlap(Mask,(0,int(self.y_vel))):
            sign = (1 if self.y_vel>0 else -1)
            while self.overlap(Mask,(0,int(self.y_vel))):
                self.y_vel += (1 if sign<0 else -1)
            self.y_vel_i = 0
            self.y_vel = int(self.y_vel)
            self.fall = False
        self.rect.y += self.y_vel
        #Is the player running into a wall?.
        if not self.overlap(Mask,(int(self.x_vel),0)):
            self.rect.x += self.x_vel

    def overlap(self,Mask,(offset)):
        off = (self.rect.x+offset[0],self.rect.y+offset[1])
        return Mask.overlap_area(self.mask,off)

    def update(self,Surf,Mask):
        self.get_pos(Mask)
        self.phys_update()
        Surf.blit(self.image,self.rect)

class Block:
    """Class representing obstacles."""
    def __init__(self,location):
        self.image = BLOCK_IMG
        self.rect = self.image.get_rect()
        self.rect.topleft = location
    def update(self,Surf):
        Surf.blit(self.image,self.rect)

class Control:
    def __init__(self):
        self.state = "GAME"
        self.Player = Player((50,-50), 4)
        #Make some obstacles
        self.Obstacles = [Block((400,350)),Block((300,220)),Block((150,120))]
        for i in range(10):
            self.Obstacles.append(Block((i*50,400)))
        self.bg_mask,self.bg_image = self.make_bg_mask() #Make a background mask for collission.
        self.Clock = pg.time.Clock()

    def event_loop(self):
        keys = pg.key.get_pressed()
        self.Player.x_vel = 0
        if keys[pg.K_LEFT] or keys[pg.K_a]:
            self.Player.x_vel -= self.Player.speed
        if keys[pg.K_RIGHT] or keys[pg.K_d]:
            self.Player.x_vel += self.Player.speed

        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.state = "QUIT"
            elif event.type == pg.KEYDOWN: #Key down events.
                if event.key == pg.K_SPACE and not self.Player.fall: #Jump
                    self.Player.y_vel_i = -self.Player.jump_power
                    self.Player.fall = True
                elif event.key == pg.K_ESCAPE: #Quit with escape key
                    self.state = "QUIT"

    def update(self,Surf):
        Surf.fill((50,50,50))
        Surf.blit(self.bg_image,(0,0))
        self.Player.update(Surf,self.bg_mask)

    def main(self,Surf):
        """Our games infinite loop"""
        while True:
            if self.state == "GAME":
                self.event_loop()
                self.update(Surf)
            elif self.state == "QUIT":
                break
            pg.display.update()
            self.Clock.tick(65)

    def make_bg_mask(self):
        temp = pg.Surface(SCREENSIZE).convert_alpha()
        temp.fill((0,0,0,0))
        for obs in self.Obstacles:
            obs.update(temp)
        return pg.mask.from_surface(temp),temp

def image_from_url(url):
    """This function loads an image from an url.
    Ignore this if you just care about Pygame functionality.
    If you are interested however, the importing nonsense is there
    to make this work in both py2 and py3."""
    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()) #Return value can be loaded by pygame.image.load

###################
if __name__ == "__main__":
    os.environ['SDL_VIDEO_CENTERED'] = '1'
    pg.init()
    SCREENSIZE = (500,500)
    SCREEN = pg.display.set_mode(SCREENSIZE)
    face_url  = "http://i1192.photobucket.com/albums/aa340/Mekire/smallface.png"
    block_url = "http://i1192.photobucket.com/albums/aa340/Mekire/block.png"
    PLAY_IMG  = pg.image.load(image_from_url(face_url)).convert_alpha()
    BLOCK_IMG = pg.image.load(image_from_url(block_url)).convert()

    RunIt = Control()
    RunIt.main(SCREEN)
    pg.quit();sys.exit()

Cheers,
-Mek
Was This Post Helpful? 0
  • +
  • -

#5 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 27 February 2013 - 04:31 PM

slidon said:

What caused the weird rect collision problems?

Sorry forgot to answer that. You were probably having strange collision issues because you moved your sprite first, then checked for collisions; rather than check collisions at where your sprite was going to move to, and then move it if it was clear. Also because the sprite doesn't just move single pixels per frame you have to use while loops to check numbers lower than the initial amount it wants to move.

i.e. If you do a collision test asking if a collision will occur if your sprite falls 5 pixels and it comes back positive, you still have to test what will happen if it only falls 4 pixels. You have to continue that until either the test returns negative, or the sprite decides it can't move.

-Mek
Was This Post Helpful? 0
  • +
  • -

#6 slidon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 29
  • Joined: 09-February 13

Re: pygame collision detection question

Posted 28 February 2013 - 09:38 AM

Hmmm. I think I will have to do more research to be able to create a working collision detection system with masks.
I've messed around with it but there's quite a bit that I would need more help on, will it work if I try the same thing with rects?
Was This Post Helpful? 0
  • +
  • -

#7 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 01 March 2013 - 01:00 AM

The same basic idea will work with rects but...

I would actually say that it is a little trickier to do with rectangles personally. The reason for this is you can make one mask that contains all the "solid" objects on the screen (although sometimes this isn't efficient) and just check collisions against that one object. If you want to do it all with rectangle collision however, you have to check collisions against every single object individually.

Regardless I rewrote my code to use rects so you can see for yourself:
import os,sys
from random import randint
import pygame as pg

class _Physics:
    def __init__(self):
        self.x_vel = self.y_vel= self.y_vel_i = 0
        self.grav = 20
        self.fall = False
        self.time = None
    def phys_update(self):
        if self.fall:
            if not self.time:
                self.time = pg.time.get_ticks()
            self.y_vel = self.grav*((pg.time.get_ticks()-self.time)/1000.0) + self.y_vel_i
        else:
            self.time = None
            self.y_vel = 0

class Player(_Physics):
    """Class representing our player."""
    def __init__(self, location,speed):
        _Physics.__init__(self)
        self.image = PLAY_IMG
        self.speed = speed
        self.jump_power = 10
        self.rect = self.image.get_rect()
        self.rect.topleft = location

        self.collide_ls = [] #what obstacles does the player collide with

    def get_pos(self,Obstacles):
        """Calculate where our player will end up this frame including collissions."""
        #Has the player walked off an edge?
        if not self.fall and not self.collide_with(Obstacles,[0,1]):
            self.fall = True
        #Has the player landed from a fall or jumped into an object above them?
        elif self.fall and self.collide_with(Obstacles,[0,int(self.y_vel)]):
            self.y_vel = self.adjust_pos(self.collide_ls,[0,int(self.y_vel)],1)
            self.y_vel_i = 0
            self.fall = False
        self.rect.y += int(self.y_vel) #Update y position before testing x.
        #Is the player running into a wall?.
        if self.collide_with(Obstacles,(int(self.x_vel),0)):
            self.x_vel = self.adjust_pos(self.collide_ls,[int(self.x_vel),0],0)
        self.rect.x += int(self.x_vel)

    def adjust_pos(self,Obstacles,offset,off_ind):
        offset[off_ind] += (1 if offset[off_ind]<0 else -1)
        while 1:
            if any(self.collide_with(self.collide_ls,offset)):
                offset[off_ind] += (1 if offset[off_ind]<0 else -1)
            else:
                return offset[off_ind]
    def collide_with(self,Obstacles,offset):
        test = ((self.rect.x+offset[0],self.rect.y+offset[1]),self.rect.size)
        self.collide_ls = []
        for Obs in Obstacles:
            if pg.Rect(test).colliderect(Obs.rect):
                self.collide_ls.append(Obs)
        return self.collide_ls

    def update(self,Surf,Obstacles):
        self.get_pos(Obstacles)
        self.phys_update()
        Surf.blit(self.image,self.rect)

class Block:
    """Class representing obstacles."""
    def __init__(self,location):
        self.make_image()
        self.rect = pg.Rect(location,(50,50))
    def make_image(self):
        self.image = pg.Surface((50,50)).convert()
        self.image.fill([randint(0,255) for i in range(3)])
        self.image.blit(SHADE_IMG,(0,0))
    def update(self,Surf):
        Surf.blit(self.image,self.rect)

class Control:
    """Class for managing event loop and game states."""
    def __init__(self):
        self.state = "GAME"
        self.Player = Player((50,-25), 4)
        self.make_obstacles()
        self.Clock = pg.time.Clock()
    def event_loop(self):
        keys = pg.key.get_pressed()
        self.Player.x_vel = 0
        if keys[pg.K_LEFT] or keys[pg.K_a]:
            self.Player.x_vel -= self.Player.speed
        if keys[pg.K_RIGHT] or keys[pg.K_d]:
            self.Player.x_vel += self.Player.speed
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.state = "QUIT"
            elif event.type == pg.KEYDOWN: #Key down events.
                if event.key == pg.K_SPACE and not self.Player.fall: #Jump
                    self.Player.y_vel_i = -self.Player.jump_power
                    self.Player.fall = True
                elif event.key == pg.K_ESCAPE: #Quit with escape key
                    self.state = "QUIT"
    def update(self,Surf):
        Surf.fill((50,50,50))
        [obs.update(Surf) for obs in self.Obstacles]
        self.Player.update(Surf,self.Obstacles)
    def main(self,Surf):
        """Our games infinite loop"""
        while True:
            if self.state == "GAME":
                self.event_loop()
                self.update(Surf)
            elif self.state == "QUIT":
                break
            pg.display.update()
            self.Clock.tick(65)
    def make_obstacles(self):
        self.Obstacles = [Block((400,400)),Block((300,270)),Block((150,170))]
        self.Obstacles += [Block((500+50*i,220)) for i in range(3)]
        for i in range(12):
            self.Obstacles.append(Block((50+i*50,450)))
            self.Obstacles.append(Block((100+i*50,0)))
            self.Obstacles.append(Block((0,50*i)))
            self.Obstacles.append(Block((650,50*i)))

#################################
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()) #Can be loaded by pygame.image.load

if __name__ == "__main__":
    os.environ['SDL_VIDEO_CENTERED'] = '1'
    pg.init()
    SCREENSIZE = (700,500)
    SCREEN = pg.display.set_mode(SCREENSIZE)
    face_url  = "http://i1192.photobucket.com/albums/aa340/Mekire/smallface.png"
    shade_url = "http://i1192.photobucket.com/albums/aa340/Mekire/shader.png"
    PLAY_IMG  = pg.image.load(image_from_url(face_url)).convert_alpha()
    SHADE_IMG = pg.image.load(image_from_url(shade_url)).convert_alpha()
    RunIt = Control()
    RunIt.main(SCREEN)
    pg.quit();sys.exit()
The functions that you should focus on here are adjust_pos and collide_with. Then compare them with the corresponding in the mask version.

Here is the mask version again, supposedly glitch and twitch free now:
import os,sys
from random import randint
import pygame as pg

class _Physics:
    def __init__(self):
        self.x_vel = self.y_vel= self.y_vel_i = 0
        self.grav = 20
        self.fall = False
        self.time = None
    def phys_update(self):
        if self.fall:
            if not self.time:
                self.time = pg.time.get_ticks()
            self.y_vel = self.grav*((pg.time.get_ticks()-self.time)/1000.0) + self.y_vel_i
        else:
            self.time = None
            self.y_vel = 0

class Player(_Physics):
    """Class representing our player."""
    def __init__(self, location,speed):
        _Physics.__init__(self)
        self.image = PLAY_IMG
        self.mask  = pg.mask.from_surface(self.image)
        self.speed = speed
        self.jump_power = 10
        self.rect = self.image.get_rect()
        self.rect.topleft = location

    def get_pos(self,Mask):
        """Calculate where our player will end up this frame including collissions."""
        #Has the player walked off an edge?
        if not self.fall and not self.overlap(Mask,[0,1]):
            self.fall = True
        #Has the player landed from a fall or jumped into an object above them?
        elif self.fall and self.overlap(Mask,[0,int(self.y_vel)]):
            self.y_vel = self.adjust_pos(Mask,[0,int(self.y_vel)],1)
            self.y_vel_i = 0
            self.fall = False
        self.rect.y += int(self.y_vel) #Update y position before testing x.
        #Is the player running into a wall?.
        if self.overlap(Mask,(int(self.x_vel),0)):
            self.x_vel = self.adjust_pos(Mask,[int(self.x_vel),0],0)
        self.rect.x += int(self.x_vel)
    def adjust_pos(self,Mask,offset,off_ind):
        while self.overlap(Mask,offset):
            offset[off_ind] += (1 if offset[off_ind]<0 else -1)
        return offset[off_ind]
    def overlap(self,Mask,offset):
        off = (self.rect.x+offset[0],self.rect.y+offset[1])
        return Mask.overlap_area(self.mask,off)

    def update(self,Surf,Mask):
        self.get_pos(Mask)
        self.phys_update()
        Surf.blit(self.image,self.rect)

class Block:
    """Class representing obstacles."""
    def __init__(self,location):
        self.make_image()
        self.rect = pg.Rect(location,(50,50))
    def make_image(self):
        self.image = pg.Surface((50,50)).convert()
        self.image.fill([randint(0,255) for i in range(3)])
        self.image.blit(SHADE_IMG,(0,0))
    def update(self,Surf):
        Surf.blit(self.image,self.rect)

class Control:
    """Class for managing event loop and game states."""
    def __init__(self):
        self.state = "GAME"
        self.Player = Player((50,-25), 4)
        self.make_obstacles()
        self.bg_mask,self.bg_image = self.make_bg_mask()
        self.Clock = pg.time.Clock()
    def event_loop(self):
        keys = pg.key.get_pressed()
        self.Player.x_vel = 0
        if keys[pg.K_LEFT] or keys[pg.K_a]:
            self.Player.x_vel -= self.Player.speed
        if keys[pg.K_RIGHT] or keys[pg.K_d]:
            self.Player.x_vel += self.Player.speed
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.state = "QUIT"
            elif event.type == pg.KEYDOWN: #Key down events.
                if event.key == pg.K_SPACE and not self.Player.fall: #Jump
                    self.Player.y_vel_i = -self.Player.jump_power
                    self.Player.fall = True
                elif event.key == pg.K_ESCAPE: #Quit with escape key
                    self.state = "QUIT"
    def update(self,Surf):
        Surf.fill((50,50,50))
        Surf.blit(self.bg_image,(0,0))
        self.Player.update(Surf,self.bg_mask)
    def main(self,Surf):
        """Our games infinite loop"""
        while True:
            if self.state == "GAME":
                self.event_loop()
                self.update(Surf)
            elif self.state == "QUIT":
                break
            pg.display.update()
            self.Clock.tick(65)
    def make_obstacles(self):
        self.Obstacles = [Block((400,400)),Block((300,270)),Block((150,170))]
        self.Obstacles += [Block((500+50*i,220)) for i in range(3)]
        for i in range(12):
            self.Obstacles.append(Block((50+i*50,450)))
            self.Obstacles.append(Block((100+i*50,0)))
            self.Obstacles.append(Block((0,50*i)))
            self.Obstacles.append(Block((650,50*i)))
    def make_bg_mask(self):
        temp = pg.Surface(SCREENSIZE).convert_alpha()
        temp.fill((0,0,0,0))
        for obs in self.Obstacles:
            obs.update(temp)
        return pg.mask.from_surface(temp),temp

#################################
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()) #Can be loaded by pygame.image.load

if __name__ == "__main__":
    os.environ['SDL_VIDEO_CENTERED'] = '1'
    pg.init()
    SCREENSIZE = (700,500)
    SCREEN = pg.display.set_mode(SCREENSIZE)
    face_url  = "http://i1192.photobucket.com/albums/aa340/Mekire/smallface.png"
    shade_url = "http://i1192.photobucket.com/albums/aa340/Mekire/shader.png"
    PLAY_IMG  = pg.image.load(image_from_url(face_url)).convert_alpha()
    SHADE_IMG = pg.image.load(image_from_url(shade_url)).convert_alpha()
    RunIt = Control()
    RunIt.main(SCREEN)
    pg.quit();sys.exit()


Cheers,
-Mek
Was This Post Helpful? 0
  • +
  • -

#8 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 01 March 2013 - 01:00 AM

...bad double posting forum. :nottalkingtoyou:

This post has been edited by Mekire: 01 March 2013 - 01:02 AM

Was This Post Helpful? 0
  • +
  • -

#9 slidon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 29
  • Joined: 09-February 13

Re: pygame collision detection question

Posted 01 March 2013 - 04:32 AM

ok I've had another go. Now I get an this error

Type error: 'module' object is not callable

on this line
self.Obstacles = [crate((400,400)),crate((300,270)),crate((150,170))]

with the create_objects function even if I use your code.
Why do you have the cords of the crate/Block in the obstacles list?

slidon
Was This Post Helpful? 0
  • +
  • -

#10 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 01 March 2013 - 05:09 AM

I'm going to need to see more of your code than that to understand what you are doing.

My self.Obstacles attribute of class Control is a list of Block instances. The __init__ for my blocks asks for a location. I am instantiating several Blocks and placing them in a list at the same time.

The line:
self.Obstacles = [Block((400,400)),Block((300,270)),Block((150,170))]
Assigns a list of three Block instances to the attribute self.Obstacles.

Please let me see your crate class and I will attempt to figure out what is going wrong.

Edit: Do you by any chance have a file called crate that you are importing? The interpreter thinks that crate refers to a module, not a class.

-Mek

This post has been edited by Mekire: 01 March 2013 - 05:16 AM

Was This Post Helpful? 0
  • +
  • -

#11 slidon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 29
  • Joined: 09-February 13

Re: pygame collision detection question

Posted 01 March 2013 - 05:33 AM

EDIT:
ok I got it working sort of... everything is setup with bg_masks and bg_images and all of that but the these test lines
def detect_collision(self, Mask):
        if self.mask.overlap(Mask, (0, 1)):
            print "overlapping"

dont seem to work. I dont get any feed back at all.
I know this is a quite general question. If you need some more code or something then please tell me

sorry didn't see the post from you. It really should be an UPDATE:
Was This Post Helpful? 0
  • +
  • -

#12 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 01 March 2013 - 05:39 AM

Yeah a little more code would help, but assuming that is the same function I wrote, that should be checking if there is a block beneath the player, and if there is it should print. Unfortunately I can't tell if that is the case. Can you condense your code to a working example I can look at?

-Mek
Was This Post Helpful? 0
  • +
  • -

#13 slidon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 29
  • Joined: 09-February 13

Re: pygame collision detection question

Posted 01 March 2013 - 05:42 AM

it maybe something to do with this
class main():
    def __init__(self):
        self.create_obstacles()
        self.bg_mask, self.bg_image = self.create_mask()
        for obstacle in self.obstacles:
            self.bg_image.blit(obstacle.image, (obstacle.rect))

I have added the for loop because it seemed to work(at least get the game running) but I know it's probably not the best way to do it.

if thats not the problem then I will give you the relevant parts of my code
Was This Post Helpful? 0
  • +
  • -

#14 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 01 March 2013 - 05:56 AM

Yeah. I will need to see more than that. The way I wrote make_bg_mask it returns both the mask and the background image (no sense in blitting the same thing to two separate surfaces). So I don't understand why you have to blit the obstacles to it again (also the Blocks have an update function so you can just call that passing it the desired surface).

Assuming your code isn't enormous, just let me see all of it. :bigsmile:/>

-Mek
Was This Post Helpful? 0
  • +
  • -

#15 Mekire  Icon User is offline

  • D.I.C Head

Reputation: 116
  • View blog
  • Posts: 212
  • Joined: 11-January 13

Re: pygame collision detection question

Posted 01 March 2013 - 06:51 AM

Hmm... I just realized this is wrong actually:
def detect_collision(self, Mask):
        if self.mask.overlap(Mask, (0, 1)):
            print "overlapping"


The function that I wrote as a method of Player is called overlap and is called like this:
self.overlap(Mask,[0,1]):
The method that the pygame class Mask has is called overlap_area and is called like this:
Mask.overlap(self.mask,offset)

You seem to have mixed the two together. The reason you are seeing nothing is you passed the type of offset I use for my function, not the type that the Mask.overlap method needs.

I should have admittedly been more careful in my naming I suppose.
Try changing the line to this:
def detect_collision(self, Mask):
    if Mask.overlap(self.mask, (self.rect.x,self.rect.y+1)):
        print "overlapping"
and tell me if it starts printing.

-Mek

Edit: gah... getting sloppy. If you saw the pre-edit one, try this instead.

This post has been edited by Mekire: 01 March 2013 - 07:02 AM

Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3