Python Question

Why does the collision detection not function correctly?

import random, pygame, sys, json, time, os
import colours as c
import xml.etree.ElementTree as ET

pygame.init()

with open('CONFIG.json') as config_file:
CONFIG = json.load(config_file)

gameDisplay = pygame.display.set_mode((CONFIG['screen_resolution']))
pygame.display.set_caption('BEE RPG TYCOON')

pygame.display.update()


#Collisions


gameExit = False


x = 300
y = 300
x_change = 0
y_change = 0

clock = pygame.time.Clock()

class Spritesheet:
#Loads an atlas image
def __init__(self, imgFile, dataFile):
self.spritesheet = pygame.image.load(imgFile).convert()
if dataFile:
tree = ET.parse(dataFile)
self.map = {}
for node in tree.iter():
if node.attrib.get('name'):
name = node.attrib.get('name')
self.map[name]={}
self.map[name]['x'] = int(node.attrib.get('x'))
self.map[name]['y'] = int(node.attrib.get('y'))
self.map[name]['width'] = int(node.attrib.get('width'))
self.map[name]['height'] = int(node.attrib.get('height'))
def getImageRect(self, x, y, w, h):
return self.spritesheet.subsurface(pygame.Rect(x,y,w,h))


def getImageName(self, name):
rect = pygame.Rect(self.map[name]['x'], self.map[name]['y'],
self.map[name]['width'], self.map[name]['height'])

return self.spritesheet.subsurface(rect)

#Spritesg
sheet = Spritesheet("walkRight.png", "charSprite.xml")


class player():
def __init__(self, x, y, sprite, width, height):
self.x=x
self.y=y
self.sprite = sprite
self.sprite.set_colorkey(c.green)
self.width = width
self.height = height
self.rect = self.sprite.get_rect()


player = player(300, 300, sheet.getImageName("walkRightIdle.png"), 20, 22)

class enemy():

def __init__(self,x,y,bx,by,sprite,movement,trackRad, lock, movRange,mv,width,height):
#Basic Properties
self.x=x
self.y=y
self.bx=bx
self.by=by
self.sprite = sprite
self.width = width
self.height = height
self.rect = self.sprite.get_rect()
#Artificial Intelligence
self.movement = movement #How far it moves per frame.
self.trackRad = trackRad #The radius in which the enemy can move
self.lock = lock #Locks the enemy into a pattern
self.movRange = movRange #When lock = 1 this determines how far it can go from it's base position, when lock = 2 this determines how far it goes in a square
self.mv = mv #The Random generator that decides which direction it moves.
#Lock Mechanics
#0 - The enemy goes anywhere randomly (Looks janky)
#1 - The enemy goes anywhere randomly, but if it leaves it's movRange it goes back (also looks janky)
#2 - The enemy patrols in a square
#3 - The enemy chases the player
#4 - The enemy patrols and chases the player

basicEnemy = enemy(310,310,310,310, sheet.getImageName("walkRightIdleE.png"),5,10,1,50,random.randint(0,3), 20,22)
basicEnemy1 = enemy(250,250,250,250, sheet.getImageName("walkRightIdleE.png"),5,10,0,0,random.randint(0,3), 20 ,22)
basicEnemy2 = enemy(100,100,100,100, sheet.getImageName("walkRightIdleE.png"),5,10,2,2,random.randint(0,3),20,22)


class hive():

def __init__(self, x, y, sprite):

self.x = x
self.y = y
self.sprite = sprite

mv = random.randint(0,3)
def enemyAi(enemy, player):
enemy.mv = random.randint(0,50)
#Collisions
if enemy.rect.colliderect(player.rect):
print("stopped")
elif enemy.lock == 0:
if enemy.mv == 0:
enemy.x = enemy.x + enemy.movement
elif enemy.mv == 1:
enemy.y = enemy.y + enemy.movement
elif enemy.mv == 2:
enemy.x = enemy.x - enemy.movement
elif enemy.mv == 3:
enemy.y = enemy.y - enemy.movement
else:
print("Nothing")
elif enemy.lock == 1:
if enemy.mv == 0:
if enemy.x > enemy.bx + enemy.movRange:
enemy.x = enemy.x - enemy.movement
else:
enemy.x = enemy.x + enemy.movement
elif enemy.mv == 1:
if enemy.y > enemy.by + enemy.movRange:
enemy.y = enemy.y - enemy.movement
else:
enemy.y = enemy.y + enemy.movement
elif enemy.mv == 2:
if enemy.x < enemy.bx - enemy.movement:
enemy.x = enemy.x - enemy.movement
else:
enemy.x = enemy.x - enemy.movement
elif enemy.mv == 3:
if enemy.y < enemy.by - enemy.movRange:
enemy.y = enemy.y + enemy.movement
else:
enemy.y = enemy.y - enemy.movement
elif enemy.lock == 2:
enemy.x = enemy.x + enemy.movement
enemy.y = enemy.y + enemy.movement
enemy.x = enemy.x - enemy.movement
enemy.y = enemy.y - enemy.movement











hive1 = hive(250, 300, "hive.png")

spriteAnim = 0
player.sprite = sheet.getImageName("walkRightIdle.png")
while not gameExit: # Game loop
enemyAi(basicEnemy, player)
enemyAi(basicEnemy1,player)
enemyAi(basicEnemy2,player)
for event in pygame.event.get(): #Event handling
if event.type == pygame.QUIT: #Game closes when cross is X ye
gameExit = True # Ends the loop
#Movement
#print(event)

if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if spriteAnim == 0:
player.sprite = sheet.getImageName("walkLeft1.png")
else:
player.sprite = sheet.getImageName("walkLeft2.png")
spriteAnim = 0
x_change += -5

if event.key == pygame.K_RIGHT:
player.sprite = sheet.getImageName("walkRight1.png")
x_change += 5
player.sprite = sheet.getImageName("walkRight2.png")
if event.key == pygame.K_UP:
player.sprite = sheet.getImageName("walkUp1.png")
y_change += -5
player.sprite = sheet.getImageName("walkUp2.png")
if event.key == pygame.K_DOWN:
player.sprite = sheet.getImageName("walkDown1.png")
y_change += 5
player.sprite = sheet.getImageName("walkDown2.png")
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_change = 0
player.sprite = sheet.getImageName("walkLeftIdle.png")
if event.key == pygame.K_RIGHT:
x_change = 0
player.sprite = sheet.getImageName("walkRightIdle.png")
if event.key == pygame.K_UP:
y_change = 0
player.sprite = sheet.getImageName("walkUpIdle.png")
if event.key == pygame.K_DOWN:
player.sprite = sheet.getImageName("walkDownIdle.png")
y_change = 0




hiveSprite = pygame.image.load(hive1.sprite)

player.x += x_change
player.y += y_change

zone = pygame.image.load("Untitled.png")

gameDisplay.fill(c.white)
gameDisplay.blit(zone, (310, 310))
gameDisplay.blit(player.sprite, (player.x, player.y))
gameDisplay.blit(basicEnemy.sprite,(basicEnemy.x, basicEnemy.y))
gameDisplay.blit(basicEnemy1.sprite,(basicEnemy1.x, basicEnemy1.y))
gameDisplay.blit(basicEnemy2.sprite,(basicEnemy2.x, basicEnemy2.y))
pygame.display.update()


clock.tick(int(CONFIG['framesPerSecond']))

















#Code Goes Here

pygame.quit()
quit()


i recently added the code:

if enemy.rect.colliderect(player.rect):


to my program and it causes all of the enemy sprites to freeze when the game loads rather than when they touch the player sprite, i have no clue why this is doing this and any way to stop this and make it work properly (only stop when being touched by another sprite) would be greatly appreciated, i can provide xml and json files if nessicary but i doubt they will be.

Thanks in advanced.

Answer Source

If something goes wrong with the collision detection, print the rects of all involved objects. If you do that, you'll quickly see that the rects are all at the same position (0, 0), therefore they're colliding immediately after the game starts.

You have to set the positions of the rects in your classes:

self.rect.topleft = (self.x, self.y)
# Or
self.rect.x = self.x
self.rect.y = self.y
# Or
self.rect = self.sprite.get_rect(topleft=(self.x, self.y))

You can also use self.rect.center or other attributes of the rect.


Also, don't forget to move the rects of your objects as well in your main loop, otherwise they'll just stay at the same starting position. In your case you can just set the topleft to enemy.x and .y (or just remove the x and y attributes and update the rect.x and rect.y directly):

enemy.rect.topleft = (enemy.x, enemy.y)