Reputation:
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
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