3
votes
import pygame
import random

red = [255,0,0]
green = [0,255,0]
blue = [0,0,255]
white = [255,255,255]
black = [0,0,0]
UP = [0,-1]
DOWN = [0,1]
LEFT = [-1,0]
RIGHT = [1,0]
NOTMOVING = [0,0]
#constants end
#classes
class collidable:
    x = 0
    y = 0
    w = 0
    h = 0
    rect = pygame.Rect(x,y,w,h)
    color = [0,0,0]
    def __init__(self,x,y,w,h,color):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.color = color
        self.rect = pygame.Rect(x,y,w,h)
    def draw(self):
        pygame.draw.rect(screen,self.color,[self.x,self.y,self.w,self.h],6)

class player:
    x = 0
    y = 0
    speed = 0
    rect = pygame.Rect(x,y,x+20,y+20)
    def __init__(self,x,y,speed):
        self.x = x
        self.y = y
        self.speed = speed
        self.rect = pygame.Rect(self.x,self.y,self.x+20,self.y+20)
    def draw(self):
        if player_moving==LEFT:
        pygame.draw.polygon(screen,black,[(self.x-10,self.y),(self.x+10,self.y-10),(self.x+10,self.y+10)])
        elif player_moving==RIGHT:
            pygame.draw.polygon(screen,black,[(self.x+10,self.y),(self.x-10,self.y-10),(self.x-10,self.y+10)])
        elif player_moving==UP:
            pygame.draw.polygon(screen,black,[(self.x,self.y-10),(self.x+10,self.y+10),(self.x-10,self.y+10)])
        elif player_moving==DOWN:
            pygame.draw.polygon(screen,black,[(self.x,self.y+10),(self.x+10,self.y-10),(self.x-10,self.y-10)])
        else:
            pygame.draw.rect(screen,black,pygame.Rect(self.x-10,self.y-10,20,20),6)
    def setpos(self,x,y):
        self.x = x
        self.y = y
    def move(self,direction):
        self.x = self.x + direction[0]*self.speed
        self.y = self.y + direction[1]*self.speed
#classes end

#globals
pygame.init()
screenSize = [800,600]
screenBGColor = white
screen=pygame.display.set_mode(screenSize)
pygame.display.set_caption("Move the Block")
player = player(screenSize[0]/2,screenSize[1]/2,9)
collidables = []
clock=pygame.time.Clock()
for i in range(10):
    collidables.append(collidable(random.randrange(0,screenSize[0]),random.randrange(0,screenSize[1]),random.randrange(10,200),random.randrange(10,200),blue))

running = True
#globals end

#functions
def render():
    screen.fill(screenBGColor)
    clock.tick(60)
    player.draw()
    for c in collidables:
        c.draw()
    pygame.display.flip()
def tick():                                           #----------------HERE
    for c in collidables:
        if player.rect.colliderect(c.rect):
            player_moving = NOTMOVING
            print("hit")
    player.move(player_moving)

#functions end

#main loop
while running==True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            running = False
        if event.type==pygame.KEYDOWN:
            if event.key==pygame.K_LEFT:
                player_moving = LEFT
            if event.key==pygame.K_RIGHT:
                player_moving = RIGHT
            if event.key==pygame.K_UP:
                player_moving = UP
            if event.key==pygame.K_DOWN:
                player_moving = DOWN
        else:
            player_moving = NOTMOVING
    tick()
    render()
#main loop end

pygame.quit()

I am trying to make a simple collision detection to disable player movement when touching a collidable object. But wherever the collidable is located, the collision is always fired. I have no idea why the player does not move, this code should only block movement if the player's center is 10 pixels away from the border of the collidable. I am sure the approach is wrong, but i can't think of any other ways of cheching collision.

2
Are you reading this book: inventwithpython.com ? - yati sagade
Truly, are you expecting us to debug the program for you? :o - mac
Sorry, I did'nt mean that. I am sure the code is wrong, I need a better approach to collision detection. My post is lacking that because my internet is so slow nowadays that when i accidentally hit enter to send, it didn't cancel. - Kroltan
transform print("hit") to see where the hit occur (et see if it is not true. Your code seem good. - A.H
@A.H Sorry, I did'nt understand. I am new to python, what you mean by transforming? - Kroltan

2 Answers

1
votes

Ok, so, basicaly, you are true. Your program is good but:

  • in pygame doc: Rect = (PosX, PosY, Width, Height)

So, your code (diff):

- self.rect = pygame.Rect(self.x,self.y,self.x+20,self.y+20)
+ self.rect = pygame.Rect(self.x,self.y,self.20,self.20)

And also:

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

There is another little problem in your code. For exemple, in your tick() function, you use player_moving, but, in the first iteration, this variable never exist.

The code (which run):

import pygame
import random

red = [255,0,0]
green = [0,255,0]
blue = [0,0,255]
white = [255,255,255]
black = [0,0,0]
UP = [0,-1]
DOWN = [0,1]
LEFT = [-1,0]
RIGHT = [1,0]
NOTMOVING = [0,0]
#constants end
#classes
class collidable:
    x = 0
    y = 0
    w = 0
    h = 0
    rect = pygame.Rect(x,y,w,h)
    color = [0,0,0]
    def __init__(self,x,y,w,h,color):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.color = color
        self.rect = pygame.Rect(x,y,w,h)
    def draw(self):
        pygame.draw.rect(screen,self.color,[self.x,self.y,self.w,self.h],6)

class player:
    x = 0
    y = 0
    speed = 0
    rect = pygame.Rect(x,y,20,20)
    def __init__(self,x,y,speed):
        self.x = x
        self.y = y
        self.speed = speed
        self.rect = pygame.Rect(self.x,self.y,20,20)
    def draw(self):
        if player_moving==LEFT:
                pygame.draw.polygon(screen,black,[(self.x-10,self.y),(self.x+10,self.y-10),(self.x+10,self.y+10)])
        elif player_moving==RIGHT:
            pygame.draw.polygon(screen,black,[(self.x+10,self.y),(self.x-10,self.y-10),(self.x-10,self.y+10)])
        elif player_moving==UP:
            pygame.draw.polygon(screen,black,[(self.x,self.y-10),(self.x+10,self.y+10),(self.x-10,self.y+10)])
        elif player_moving==DOWN:
            pygame.draw.polygon(screen,black,[(self.x,self.y+10),(self.x+10,self.y-10),(self.x-10,self.y-10)])
        else:
            pygame.draw.rect(screen,black,pygame.Rect(self.x-10,self.y-10,20,20),6)
    def setpos(self,x,y):
        self.x = x
        self.y = y
    def move(self,direction):
        self.x = self.x + direction[0]*self.speed
        self.y = self.y + direction[1]*self.speed
        self.rect = pygame.Rect(self.x,self.y,20,20)
#classes end

#globals
pygame.init()
screenSize = [800,600]
screenBGColor = white
screen=pygame.display.set_mode(screenSize)
pygame.display.set_caption("Move the Block")
player = player(screenSize[0]/2,screenSize[1]/2,9)
collidables = []
clock=pygame.time.Clock()
for i in range(10):
    collidables.append(collidable(random.randrange(0,screenSize[0]),random.randrange(0,screenSize[1]),random.randrange(10,200),random.randrange(10,200),blue))

running = True
#globals end
player_moving = NOTMOVING
#functions
def render():
    screen.fill(screenBGColor)
    clock.tick(60)
    player.draw()
    for c in collidables:
        c.draw()
    pygame.display.flip()
def tick(player_moving):                                           #----------------HERE
    for c in collidables:
        if player.rect.colliderect(c.rect):
            player_moving = NOTMOVING
            print("hit"+str(c.rect)+" with "+str(player.rect))
    player.move(player_moving)

#functions end

#main loop
while running==True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            running = False
        if event.type==pygame.KEYDOWN:
            if event.key==pygame.K_LEFT:
                player_moving = LEFT
            if event.key==pygame.K_RIGHT:
                player_moving = RIGHT
            if event.key==pygame.K_UP:
                player_moving = UP
            if event.key==pygame.K_DOWN:
                player_moving = DOWN
        else:
            player_moving = NOTMOVING
    tick(player_moving)
    render()
#main loop end

pygame.quit()
2
votes

You are delving into what is known as AABB (Axis Aligned Bounding Box). You set a box around your character that detects objects around it.

Here are some resources that may help you find out what is going on, as well as tricks to help you implement them better:

http://www.gamasutra.com/view/feature/3426/when_two_hearts_collide_.php

http://www.gamefromscratch.com/post/2012/11/26/GameDev-math-recipes-Collision-detection-using-an-axis-aligned-bounding-box.aspx

Other Various platforming implementations

Read up on these! I struggled with collision detection for a while, these really do help.