DISCLAIMER: I know other people on this site have had this error but it's been in different contexts and the fixes don't seem to work here.
Hey stackoverflow, Basically I've been making a sideways space invaders game, where your ship follows your mouse's Y position but stays on the left, and clicking shoots a bullet. Enemies spawn randomly from the right and fly to the left, and objects are removed once they each the side of the screen. This all works fine, however when I tried to implement collision detection to see when the shot hits the enemy, I get the error:
TypeError: Argument must be rect style object.
It points to the line "return hitbox.colliderect(target.rect)". To try and work out what was causing this I made some 'print' lines below it to see what 'target.rect' was (and whether it was a proper rect object), and it seemed to be exactly the same style as the shot's own rect, so I'm completely lost as to why colliderect doesn't accept it.
I've annotated pretty much everything, sorry if it's an insult to your intelligence but it should make things easier.
Class that causes problems:
class gameObject:
def __init__(self, image, height, speed):
self.speed = speed
self.image, self.rect = load_image("shot.dsf", -1) #Loads the image and creates rectange
self.pos = image.get_rect().move(0, height)
def move(self):
self.pos = self.pos.move(self.speed, 0) #Moves along
self.rect = [self.pos, 32, 32] #Updates the position of the rectange. Without it the rectangle just stays in the top left corner but the image moves
if self. pos.right > 1400: #Checks if shot goes offscreen
objects.remove(self) #Removes it
def hitreg(self,target):
hitbox = self.rect #Creates hitbox of it's own rectangle
return hitbox.colliderect(target.rect) #SHOULD return true if hitbox collides with the rect of target, however it returns the error
print("OWN RECT: ",self.rect) #Debug purposes, returns ('OWN RECT: [<rect(1350, 245, 32, 32)>, 32, 32])
print("TARGET RECT: ",target.rect) #Debug purposes, returns ('TARGET RECT: [<rect(360, 479, 128, 64)>, 128, 64])
Main Loop
r.drawFrame() #Renders Frame
while running:
sleep(0.0166) #Make sure it only renders at most 60fps
rand = rnd(10,20) #Generates random number from 10 to 20
pos = pygame.mouse.get_pos() #Gets mouse position
for event in pygame.event.get():
if event.type == MOUSEBUTTONUP: #Prevents hang
None
if event.type == MOUSEBUTTONDOWN: #Creates shot if mousebuttondown, at mouse height with random speed
o = gameObject(shot, pos[1], rand)
objects.append(o)
if rnd(1,120) == 60: #Randomely Spawns Enemy Ships
s = enemyShip(enemya, rnd(10,890), rand) #enemya is filename
ships.append(s)
for o in objects: #For each shot
for s in ships: #For each enemy ship
if o.hitreg(s): #Calls hitreg function, s being the target
s.takedamage()
score = score + 10 #Increases score
r.drawFrame() #Renders Frame
If the output shown in your source code can be trusted, your debug statements show that neither self.rect
nor target.rect
are "rect style" objects. They appear to be lists consisting of a rect followed by 2 integers such as this:
OWN RECT: [<rect(1350, 245, 32, 32)>, 32, 32])
TARGET RECT: [<rect(360, 479, 128, 64)>, 128, 64]
The move()
method is responsible for changing self.rect
from a "normal" rect into a list as above, but this modified self.rect
will not behave like a rect. Perhaps in hitreg()
you should be calling hitbox = self.rect[0]
.
Anyway, in this case, I suspect that the output of your debug statements as shown is incorrect. Probably the value for self.rect
is a rect
(because lists do not have method colliderect()
, but colliderect()
does seem to be called), and it is target.rect
that is a list. target.rect
is of type enemyShip
, but you don't show the code for that, so it is not possible to tell what is actually going on there (although one could guess that move()
has been called on it and it's self.rect
corrupted).
I suggest that you capture some real debug output and add that to your question. It would also be helpful if you could post accurate code, because there is at least 1 syntax error, e.g. in the line:
if self. pos.right > 1400:
And what does the code for enemyShip
look like?