user20759990
user20759990

Reputation:

Trying to do collision with bullets and asteroids in my game, but pygame thinks that the bullet hitbox is a tuple

So, I am making a space-themed asteroid shooter game, and I need help yet again. Collision between the bullet and one of the asteroids is not possible, pygame just returns an AttributeError and states that "'tuple' object has no attribute 'topleft'". (I think it has something to do with the collision function). If you need it, here is the code:

import random
import pygame
pygame.init()
pygame.font.init()

#initalizing all the clunky variables
size = (900,700)
BLACK = (0, 0, 30)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
YELLOW = (0, 255, 0)
x_pos = 450
y_pos = 600
direct = 0
w = 100
h = 100
screen = pygame.display.set_mode(size)
klok = pygame.time.Clock()

#main ship image and its rotations
ship = pygame.image.load('u-sniper.png')
shipL = pygame.transform.rotate(ship, 270)
shipR = pygame.transform.rotate(ship, 90)
shipD = pygame.transform.rotate(ship, 180)
#init hitbox
hitbox = ship.get_rect()
hitbox.center = w//2,h//2

#score variable and font thingy
score = 0
score_font = pygame.font.SysFont('Arial', 50)
title_font = pygame.font.SysFont('Arial', 80)


#funct for drawing ship
def drawShip():
    if direct == 0:
        screen.blit(ship, [x_pos,y_pos])
    if direct == 1:
        screen.blit(shipR, [x_pos,y_pos])
    if direct == 2:
        screen.blit(shipD, [x_pos,y_pos])
    if direct == 3:
        screen.blit(shipL, [x_pos,y_pos])

        

#asteroid obstacles (these are meant to collide with the ship)
class asteroid:
    def __init__(self,x,y,spawn):
        self.x = x
        self.y = y
        self.spawn = spawn
        
    #draws the asteroid
    def draw(self):
        if self.spawn == 1:
            pygame.draw.circle(screen, RED, (self.x,self.y), 30)
        if self.spawn == 2:
            pygame.draw.circle(screen, BLUE, (self.x,self.y), 30)
    
    #moves the asteroid
    def move(self):
        self.y += random.randrange(0, 10, 1)
        if self.y > 650:
            self.y = 0
            self.x = random.randrange(0, 900, 1)
            global score
            score += 1

    
    #funct reserved for a special kind of asteroid that spawns at the players x value (but not y)                    
    def moveintel(self):
        self.y += 8
        if self.y > 650:
            self.y = 0
            self.x = x_pos
            global score
            score += 1
            
#bullet class
class bullet:
    def __init__(self,x,y,spawn,hbas):
        self.x = x
        self.y = y
        self.spawn = spawn
        self.hbas = hbas
    #if K is pressed, summon a bullet
    def summon(self):
        global x_pos
        global y_pos
        self.x = x_pos
        self.y = y_pos
        if self.hbas == 0:
            self.spawn = 1
            self.hbas = 1
            
    #draws the bullet
    def drawbull(self):
        if self.spawn == 1:
            pygame.draw.circle(screen, YELLOW, (self.x,self.y), 10)

    
        
    #moves the bullet
    def movebull(self):
        if self.spawn == 1: 
            self.y -= 8
        if self.y < 0:
            self.spawn = 0
            self.hbas = 0

    
            
        


#asteroid flags, intelroid stands for "inteligent asteroid"        
asteroid_2_enabled = True
intelroid_enabled = True

done = False
game = False
title = True

#asteroid class setup and whatnot
roid = asteroid(450,0,1)
roidII = asteroid(350,0,1)
intelroid = asteroid(250,0,2)
#asteroid hitbox init
rect_asteroid = (roid.x, roid.y, 30, 30)
rect_asteroidII = (roidII.x, roidII.y, 30, 30)
intelroidrect = (intelroid.x, intelroid.y, 30, 30)

#defining bullet and respective hitbox, pygame thinks its a "tuple"
pbullet = bullet(0,0,0,0)
bulletrect = (pbullet.x, pbullet.y, 10, 10)


#these three functions deal with collision (thanks to Rabbid76)
def checkForCollisions():
    hitbox.topleft = (x_pos, y_pos)
    rect_asteroid = (roid.x, roid.y, 30, 30)
    collide = hitbox.colliderect(rect_asteroid)
    return collide

def checkForCollisions_II():
    hitbox.topleft = (x_pos, y_pos)
    rect_asteroidII = (roidII.x, roidII.y, 30, 30)
    collide = hitbox.colliderect(rect_asteroidII)
    return collide
    
def checkForCollisions_intelroid():
    hitbox.topleft = (x_pos, y_pos)
    intelroidrect = (intelroid.x, intelroid.y, 30, 30)
    collide = hitbox.colliderect(intelroidrect)
    return collide

#here is where its going wrong, it says that "topleft has no atribut "tuple""
def cFC_Bullet():
    p_x = pbullet.x
    p_y = pbullet.y
    bulletrect.topleft = (p_x, p_y)
    intelroidrect = (intelroid.x, intelroid.y, 30, 30)
    collide = bullet_rect.colliderect(intelroidrect)
    return collide



#loop
while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
    #a WIP title
    if title == True:
        screen.fill(BLUE)
        title_surface = title_font.render("Blasteroids", False, (255,255,255))
        screen.blit(title_surface, (100,100))
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                game = True
                title = False
        
        
    if game == True:
        screen.fill(BLACK)
        drawShip()
        roid.draw()
        roid.move()
        pbullet.drawbull()
        pbullet.movebull()

        #returns a 0/1 or boolean for collision
        collide = checkForCollisions()
        if collide == 1 or collide == True:
            print("Asteroid 1 HIT")
            done = True

            
        #same here
        if asteroid_2_enabled == True:
            roidII.draw()
            roidII.move()
            collideII = checkForCollisions_II()
            if collideII == 1 or collideII == True:
                print("Asteroid 2 HIT")
                done = True
                

        

        #and here
        if intelroid_enabled == True:
            intelroid.draw()
            intelroid.moveintel()
            collideintelroid = checkForCollisions_intelroid()
            if collideintelroid == 1 or collideintelroid == True:
                print("Intelroid HIT")
                done = True

        #code thats SUPPOSED to deal with bullet collisions and asteroids, but its not working
        bc = cFC_Bullet()
        if bc == 1 or bc == True:
            intelroid_enabled = False
            print("Bullet HIT")


        
        #renders and blits the score
        score_surface = score_font.render("Score: {0}".format(score), False, (255,255,255))
        screen.blit(score_surface, (0,0))

        

        #if branch that moves the ship
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                y_pos -= 5
                direct = 0
            if event.key == pygame.K_DOWN:
                y_pos += 5
                direct = 2
            if event.key == pygame.K_RIGHT:
                x_pos += 5
                direct = 3
            if event.key == pygame.K_LEFT:
                x_pos -= 5
                direct = 1
            if event.key == pygame.K_f:
                pbullet.summon()
                print("f")
        
    #collision between screen boundaries
        if x_pos > 850:
            x_pos -= 6
        if x_pos < -50:
            x_pos += 6
        if y_pos > 650:
            y_pos -= 6
        if y_pos < 0:
            y_pos += 6

        

    pygame.display.flip()
    klok.tick(60)
pygame.quit()

I tried stuffing the pbullet.x and pbullet.y values into variables, but it just doesn't work.

Upvotes: 1

Views: 65

Answers (1)

Rabbid76
Rabbid76

Reputation: 211135

colliderect is a method of pygame.Rect. However, bulletrect is not a pygame.Rect object. You have to create an instance object of the pygame.Rect class:

bulletrect = (pbullet.x, pbullet.y, 10, 10)

bulletrect = pygame.Rect(pbullet.x, pbullet.y, 10, 10)

Upvotes: 1

Related Questions