I'm trying to program a traffic simulation and need the pygame collision detection. However as soon as i run the program (it isn't finished yet) it tells me i have an attribute error on car_up because it hasn't got the attribute rect. Can someone tell me why it is so and what i can do to improve it? And yes i have been trying figuring it out on my own but with no success.
import pygame
import random
import threading
from pygame.locals import (QUIT, KEYDOWN, K_ESCAPE)
# Define constants for the screen width and height
SCREEN_WIDTH = 1500
SCREEN_HEIGHT = 400
grey=[90 , 90 , 90]
green =[125, 255, 50]
spawnrate_up=1500
spawnrate_down=800
dimentions=[75,35]
#CLASSES
#create car
class Car_up (pygame.sprite.Sprite):
def __init__(self, green, dimentions):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface(dimentions)
self.image.fill(green)
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()
self.rect.x = random.randint(-100, -20)
self.rect.y = 150
self.speedx= 10
self.speedy= 0
# move car and delete once out of screen
def update(self):
merge=random.randint(750,1000)
if self.rect.left > SCREEN_WIDTH:
self.kill()
if self.rect.colliderect(car_down.rect):
car_up.speed.x=car_up.speed.y=0
elif self.rect.centery<=266 and self.rect.centerx>merge:
self.speedx=10
self.speedy=3
else:
self.speedx=10
self.speedy=0
self.rect.move_ip(self.speedx, self.speedy)
class Car_down(pygame.sprite.Sprite):
def __init__(self, green, dimentions):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface(dimentions)
self.image.fill(green)
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()
self.rect.x = random.randint(-100,-20)
self.rect.y = 250
self.speedx= 10
self.speedy= 0
# move car and delete once out of screen
def update(self):
self.speedx=10
self.speedy=0
self.rect.move_ip(self.speedx, self.speedy)
if self.rect.left > SCREEN_WIDTH:
self.kill()
pygame.init()
# The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock=pygame.time.Clock()
#create custom event
ADDCAR_down= pygame.USEREVENT + 1
ADDCAR_up= pygame.USEREVENT + 2
pygame.time.set_timer(ADDCAR_up, spawnrate_up )
pygame.time.set_timer(ADDCAR_down, spawnrate_down )
#create car
car_up= pygame.sprite.Group()
car_down= pygame.sprite.Group()
car_down.add(Car_down(green,dimentions))
car_up.add(Car_up(green,dimentions))
#infinite loop
run = True
#MAIN
while run:
# Look at every event in the queue
for event in pygame.event.get():
# Did the user hit a key?
if event.type == KEYDOWN:
# Was it the Escape key? If so, stop the loop.
if event.key == K_ESCAPE:
run = False
# Did the user click the window close button? If so, stop the loop.
elif event.type == QUIT:
run = False
elif event.type == ADDCAR_down:
# Create the new CAR and add it to sprite groups
new_car_down = Car_down(green,dimentions)
car_down.add(new_car_down)
elif event.type == ADDCAR_up:
new_car_up = Car_up(green,dimentions)
car_up.add(new_car_up)
#grey screen
screen.fill(grey)
# Draw the car on the screen
car_up.draw(screen)
car_up.update()
car_down.draw(screen)
car_down.update()
pygame.display.flip()
clock.tick(25)
car_down is a pygame.sprite.Group so obviously it doesn't have a rect attribute. However the pygams.sprites.Sprite object in the Group have a rect attribute. You need to use pygame.sprite.spritecollide to detect collision of a Sprite and the objects in a Group:
if self.rect.colliderect(car_down.rect):
if pygame.sprite.spritecollide(self, car_down, False):
See also How do I detect collision in pygame?
Related
I am working on a basic pong pygame and I have coded my main.py, paddle.py, and ball.py files and unfortunately, when I run the game it only displays a black pygame window. My paddles, ball, net, and score are not visible... it's just blank.
Screenshot of Blank/Black Window
The following is my code, I have seperated it by each file.
I cannot seem to find what is causing this error so any feedback would be appreciated.
MAIN.PY
# Import pygame library and initialize the game engine
import pygame
from paddle import Paddle
from ball import Ball
pygame.init()
# Define some colors
BLACK = (0,0,0)
WHITE = (255,255,255)
# Open a new window
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Pong")
paddleA = Paddle(WHITE, 10, 100)
paddleA.rect.x = 20
paddleA.rect.y = 200
paddleB = Paddle(WHITE, 10, 100)
paddleB.rect.x = 670
paddleB.rect.y = 200
ball = Ball(WHITE, 10, 10)
ball.rect.x = 345
ball.rect.y = 195
# This will be a list that contains all the sprites we intend to use in game.
all_sprites_list = pygame.sprite.Group()
# Add paddles to the list of sprites
all_sprites_list.add(paddleA)
all_sprites_list.add(paddleB)
all_sprites_list.add(ball)
# Loop will carry on until user exits the game (ex. clicks the close button)
carryOn = True
# Clock will be used to control how fast the screen updates
clock = pygame.time.Clock()
# Initialize player scores
scoreA = 0
scoreB = 0
# ----- Main Program Loop -----
while carryOn:
# --- Main Event Loop ---
for event in pygame.event.get(): # user did something
if event.type==pygame.QUIT: # if user clicked close
carryOn==False # Flag that we are done so we exit this loop
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_x: # Pressing the x key will quit the game
carryOn==False
# Moving the paddles when the user uses the arrow keys (Player A),
# or W/S keys (Player B)
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
paddleA.moveUp(5)
if keys[pygame.K_s]:
paddleA.moveDown(5)
if keys[pygame.K_UP]:
paddleB.moveUp(5)
if keys[pygame.K_DOWN]:
paddleB.moveDown(5)
# --- Game Logic ---
all_sprites_list.update()
# Checks if the ball is bouncing against any of the 4 walls
if ball.rect.x>=690:
ball.velocity[0] = -ball.velocity[0]
if ball.rect.x<=0:
ball.velocity[0] = -ball.velocity[0]
if ball.rect.y>490:
ball.velocity[1] = -ball.velocity[1]
if ball.rect.y<0:
ball.velocity[1] = -ball.velocity[1]
#Detect collisions between the ball and the paddles
if pygame.sprite.collide_mask(ball, paddleA) or pygame.sprite.collide_mask(ball, paddleB):
ball.bounce()
# --- Drawing Code ---
# clears the screen to black
screen.fill(BLACK)
# draws the net
pygame.draw.line(screen, WHITE, [349, 0], [349, 500], 5)
# Draws all sprites in one go (I only have 2 for now)
all_sprites_list.draw(screen)
# Display scores
font = pygame.font.Font(None, 74)
text = font.render(str(scoreA), 1, WHITE)
screen.blit(text, (250,10))
text.font.render(str(scoreB), 1, WHITE)
screen.blit(text (420,10))
# update screen with what we've drawn
pygame.display.flip()
# limit to 60 frames per second
clock.tick(60)
# Once we have exited the main program loop we stop the game engine
pygame.quit()
PADDLE.PY
import pygame
BLACK = (0,0,0)
class Paddle(pygame.sprite.Sprite):
# This class represents a paddle. It derives from the "Sprite" class in Pygame.
def __init__(self, color, width, height):
# Call the parent class (Sprite) constructor
super().__init__()
# Pass in the color of the paddle and it's x and y position (width nd height).
# Set the background color as transparent
self.image = pygame.Surface([width, height])
self.image.fill(BLACK)
self.image.set_colorkey(BLACK)
# Draw the paddle which is a rectangle
pygame.draw.rect(self.image, color, [0,0, width, height])
# Fetch the rectangle object that has the dimensions of the image
self.rect = self.image.get_rect()
def moveUp(self, pixels):
self.rect.y -= pixels
# Check that you are not going too far (off screen)
if self.rect.y < 0:
self.rect.y = 0
def moveDown(self, pixels):
self.rect.y += pixels
# Check that you are not going too far (off screen)
if self.rect.y > 400:
self.rect.y = 400
BALL.PY
import pygame
from random import randint
BLACK = (0,0,0)
class Ball(pygame.sprite.Sprite):
#This class represents a ball. It derives from the "Sprite" class in Pygame.
def __init__(self, color, width, height):
# Call the parent class (Sprite) constructor
super().__init__()
# Pass in the color of the ball, its width and height.
# Set the background color and set it to be transparent
self.image = pygame.Surface([width, height])
self.image.fill(BLACK)
self.image.set_colorkey(BLACK)
# Draw the ball (a rectangle!)
pygame.draw.rect(self.image, color, [0, 0, width, height])
self.velocity = [randint(4,8),randint(-8,8)]
# Fetch the rectangle object that has the dimensions of the image.
self.rect = self.image.get_rect()
def update(self):
self.rect.x += self.velocity[0]
self.rect.y += self.velocity[1]
def bounce(self):
self.velocity[0] = -self.velocity[0]
self.velocity[1] = randint(-8,8)
You are simply not flipping the screen in the main loop, in the main file.
All is actually being updated, but nothing is being rendered on the screen.
Just intend the code from
# --- Drawing Code ---
to
clock.tick(60)
I think you forgot to indent it.
Just be careful not to include pygame.quit() in the main loop.
Just add a tabulation layer from
...
# --- Drawing Code ---
...
to end in main.py
Okay, so basically what I'm trying to do is keep the main file a little cleaner and I'm starting with the "Zombie" enemy by making it's own file which will most likely contain all enemies, and importing it in.
So I'm confused on how I'd set-up the Class for a sprite, you don't have to tell me how to get it to move or anything like that I just want it to simply appear. The game doensn't break when I run it as is, I just wanted to ask this question before I goto sleep so I can hopefully get a lot done with the project done tomorrow (School related)
Code is unfinished like I said just wanted to ask while I get some actual sleep just a few google searches and attempts.
Eventually I'll take from the advice given here to make a "Hero" class as well, and as well as working with importing other factors if we have the time.
Zombie code:
import pygame
from pygame.locals import *
class ZombieEnemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('images/zombie.png')
# self.images.append(img)
# self.image = self.images[0]
self.rect = self.image.get_rect()
zombieX = 100
zombieY = 340
zombieX_change = 0
Main Code:
import pygame
from pygame.locals import *
import Zombie
# Intialize the pygame
pygame.init()
# Create the screen
screen = pygame.display.set_mode((900, 567))
#Title and Icon
pygame.display.set_caption("Fighting Game")
# Add's logo to the window
# icon = pygame.image.load('')
# pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('images/character.png')
playerX = 100
playerY = 340
playerX_change = 0
def player(x,y):
screen.blit(playerImg,(x,y))
Zombie.ZombieEnemy()
def zombie(x,y):
screen.blit()
# Background
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load('images/background.png')
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
BackGround = Background('background.png', [0,0])
# Game Loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed check right, left.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
#playerX_change = -2.0
BackGround.rect.left = BackGround.rect.left + 2.5
if event.key == pygame.K_RIGHT:
#playerX_change = 2.0
BackGround.rect.left = BackGround.rect.left - 2.5
# if event.type == pygame.KEYUP:
# if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
# BackGround.rect.left = 0
screen.blit(BackGround.image, BackGround.rect)
playerX += playerX_change
player(playerX,playerY)
pygame.display.flip()
Your sprite code is basically mostly there already. But as you say, it needs an update() function to move the sprites somehow.
The idea with Sprites in PyGame is to add them to a SpriteGroup, then use the group functionality for handling the sprites together.
You might want to modify the Zombie class to take an initial co-ordinate location:
class ZombieEnemy(pygame.sprite.Sprite):
def __init__( self, x=0, y=0 ):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('images/zombie.png')
self.rect = self.image.get_rect()
self.rect.center = ( x, y ) # NOTE: centred on the co-ords
Which allows the game to create a Zombie at a particular starting point (perhaps even a random one).
So to have a sprite group, first you need to create the container:
all_zombies = pygame.sprite.Group()
Then when you create a new zombie, add it to the group. Say you wanted to start with 3 randomly-positioned zombies:
for i in range( 3 ):
new_x = random.randrange( 0, WINDOW_WIDTH ) # random x-position
new_y = random.randrange( 0, WINDOW_HEIGHT ) # random y-position
all_zombies.add( Zombie( new_x, new_y ) ) # create, and add to group
Then in the main loop, call .update() and .draw() on the sprite group. This will move and paint all sprites added to the group. In this way, you may have separate groups of enemies, bullets, background-items, etc. The sprite groups allow easy drawing and collision detection between other groups. Think of colliding a hundred bullets against a thousand enemies!
while running:
for event in pygame.event.get():
# ... handle events
# Move anything that needs to
all_zombies.update() # call the update() of all zombie sprites
playerX += playerX_change
# Draw everything
screen.blit(BackGround.image, BackGround.rect)
player(playerX,playerY)
all_zombies.draw( screen ) # paint every sprite in the group
pygame.display.flip()
EDIT: Added screen parameter to all_zombies.draw()
It's probably worthwhile defining your player as a sprite too, and having a single-entry group for it as well.
First you could keep position in Rect() in class. And you would add method which draws/blits it.
import pygame
class ZombieEnemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load('images/zombie.png')
self.rect = self.image.get_rect()
self.rect.x = 100
self.rect.y = 340
self.x_change = 0
def draw(self, screen):
screen.blit(self.image, self.rect)
Next you have to assign to variable when you create it
zombie = Zombie.ZombieEnemy()
And then you can use it to draw it
zombie.draw(screen)
in
screen.blit(BackGround.image, BackGround.rect)
player(playerX,playerY)
zombie.draw(screen)
pygame.display.flip()
The same way you can create class Player and add method draw() to class Background and then use .
background.draw(screen)
player.draw(screen)
zombie.draw(screen)
pygame.display.flip()
Later you can use pygame.sprite.Group() to keep all objects in one group and draw all of them using one command - group.draw()
I am beginning to code a space invaders game and trying to just get the ship down and let it move back and forth across the screen. I'm very beginner status so it is a big challenge for me. Whenever I try to run it it tells me that I'm requiring another positional argument in my update function but I don't understand what I'm supposed to do.
I've tried moving around the variable initialization for keys but it hasn't changed anything. If anyone wants to take a look at my code and tell me what I could do it would be amazing.
import pygame, sys
from pygame import *
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption("Space Invaders")
pygame.mouse.set_visible(0)
WIDTH = 800
vel = 5
width = 64
keys = pygame.key.get_pressed()
BLACK = (0, 0, 0)
all_sprites = pygame.sprite.Group()
class Player(pygame.sprite.Sprite):
def _init_(self):
pygame.sprite.Sprite._init_(self)
self.image = pygame.image.load("images\ship.png")
self.rect = self.image.get_rect()
self.rect.center = (WIDTH/2, 40)
def update(self, keys, *args):
if keys[pygame.K_LEFT] and self.rect.x > vel:
self.rect.x -= vel
if keys[pygame.K_RIGHT] and self.rect.x < 800 - width - vel:
self.rect.x += vel
screen.blit(self.image, self.rect)
player = Player()
all_sprites.add(player)
run = True
while run:
pygame.time.delay(100)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
all_sprites.update()
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display
pygame.quit()
I know this is just the beginning but I can't figure out what I'm missing here.
You've to pass the current states of the keyboard buttons to .update().
Note, the arguments which are passed to all_sprites.update() are delegated to player.update(). all_sprites is pygame.sprite.Group object. The .update() method calls .update() on each contained sprite and pass the parameters through.
Get the states of the keyboard buttons by pygame.key.get_pressed() and pass it to .update:
keys = pygame.key.get_pressed()
all_sprites.update(keys)
The name of the constructor has to be __init__ rather than _init_ . See Class:
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# [...]
I know i need a loop to check if a list of bullets hits a player.
I've tried researching online for 2 hours for reference code but all use sprites and classes.
#Bullet Collision with players
for i in range(len(bullets_2)):
#player is a rectangle style object
if bullets_2[i].colliderect(player):
player_health -= 10
Sadly enough my computer science teacher hasn't taught the class about sprites or classes, so let's avoid that.
I tried having the code above check if the list collides with the rectangle player.
The point of the above code is for the game to to take health away from the health bar if the enemy player's bullets hit the player.
EDIT:
I only have about 8 days to finish this game
TLDR:
How do I check to see if a list collides with a rectangle.
As in the comment, here's the code.
Here's the images I am using
import pygame, time, sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800,600))
clock = pygame.time.Clock()
class playerClass(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("player.png").convert()
self.image.set_alpha(196)
self.rect = self.image.get_rect()
self.rect.y = 260
self.rect.x = 500
def update(self):
pass
class bulletClass(pygame.sprite.Sprite):
def __init__(self, speed, starty):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.rect = self.image.get_rect()
self.rect.y = starty
self.rect.x = 0
self.speed = speed
def update(self):
self.rect.x += self.speed
gameExit = False
player = playerClass()
bullet1 = bulletClass(7,265)
bullet2 = bulletClass(10,295)
bullet3 = bulletClass(7,325)
bulletSprites = pygame.sprite.RenderPlain((bullet1, bullet2, bullet3))
playerSprites = pygame.sprite.RenderPlain((player))
bulletRectList = [bullet1.rect, bullet2.rect, bullet3.rect]
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
screen.fill((255,255,255))
bulletSprites.update()
bulletSprites.draw(screen)
playerSprites.update()
playerSprites.draw(screen)
collidedBulletList = player.rect.collidelistall(bulletRectList)
if len(collidedBulletList) > 0:
for i in collidedBulletList:
print(i)
pygame.display.update()
clock.tick(10)
In this code, if you want to add a bullet just declare a new object
bullet4 = bulletClass(speed, yCoordinateToBeginWith)
and append it to bulletSprites and the bulletRectList and you are done. Using sprites simplifies this. Making your code sprite friendly would be difficult at the beginning but appending it is definitely easy afterwards.
I have created two simple sprites in PyGame and one of them is an Umbrella, the other one is a rain drop.
The Raindrops are added into a sprite group called all_sprites. The Umbrella sprite has its own group called Umbrella_sprite
The raindrops are "falling" from top of the screen and if one of them touches the umbrella / collides with it.. the raindrop is supposed to be deleted. BUT instead of that specific raindrops all other are affected by this.
main file (rain.py)
#!/usr/bin/python
VERSION = "0.1"
import os, sys, raindrop
from os import path
try:
import pygame
from pygame.locals import *
except ImportError, err:
print 'Could not load module %s' % (err)
sys.exit(2)
# main variables
WIDTH, HEIGHT, FPS = 300, 300, 30
# initialize game
pygame.init()
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Rain and Rain")
# background
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((40,44,52))
# blitting
screen.blit(background,(0,0))
pygame.display.flip()
# clock for FPS settings
clock = pygame.time.Clock()
def main():
all_sprites = pygame.sprite.Group()
umbrella_sprite = pygame.sprite.Group()
# a function to create new drops
def newDrop():
nd = raindrop.Raindrop()
all_sprites.add(nd)
# creating 10 rain drops
for x in range(0,9): newDrop()
# variable for main loop
running = True
# init umbrella
umb = raindrop.Umbrella()
# all_sprites.add(umb)
umbrella_sprite.add(umb)
# event loop
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for enemy in all_sprites:
gets_hit = pygame.sprite.spritecollideany(umb, all_sprites)
if gets_hit:
all_sprites.remove(enemy)
screen.blit(background,(100,100))
# clear
all_sprites.clear(screen,background)
umbrella_sprite.clear(screen,background)
# update
all_sprites.update()
umbrella_sprite.update()
# draw
all_sprites.draw(screen)
umbrella_sprite.draw(screen)
# flip the table
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
main()
raindrop.py ( Raindrop() & Umbrella() )
import pygame
from pygame.locals import *
from os import path
from random import randint
from rain import HEIGHT, WIDTH
img_dir = path.join(path.dirname(__file__), 'img')
class Raindrop(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.width = randint(32, 64)
self.height = self.width + 33
self.image = pygame.image.load(path.join(img_dir, "raindrop.png")).convert_alpha()
self.image = pygame.transform.scale(self.image, (self.width, self.height))
self.speedy = randint(1, 15)
self.rect = self.image.get_rect()
self.rect.x = randint(0, 290)
self.rect.y = -self.height
def reset(self):
self.rect.y = -self.height
def update(self):
self.rect.y += self.speedy
if self.rect.y >= HEIGHT:
self.rect.y = -self.height
self.rect.x = randint(0, 290)
class Umbrella(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.width = 50
self.height = 50
self.image = pygame.image.load(path.join(img_dir,"umbrella.png")).convert_alpha()
self.image = pygame.transform.scale(self.image, (self.width, self.height))
self.speedx = 10
self.rect = self.image.get_rect()
self.rect.x = (WIDTH/2) - self.width
self.rect.y = (0.7 * HEIGHT)
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and self.rect.x > 0:
self.rect.x -= self.speedx
elif keys[pygame.K_RIGHT] and self.rect.x < (WIDTH - self.width):
self.rect.x += self.speedx
This is your problem:
for enemy in all_sprites:
gets_hit = pygame.sprite.spritecollideany(umb, all_sprites)
if gets_hit:
all_sprites.remove(enemy)
You're looping through the group, and if any sprite collides, deleting all of them.
You don't need to loop through the group - the collision functions take care of that. You just need to use the spritecollide function, which compares a sprite versus a group. That function will return a list of collisions, as well as using the DOKILL flag to delete them automatically:
gets_hit = pygame.sprite.spritecollide(umb, all_sprites, True)
spritecollideany checks if the sprite collides with any sprite in the group and returns this sprite, so gets_hit is a trueish value as long as the collided sprite in the group is not removed and the if gets_hit: block gets executed. That means the code in the for loop simply keeps deleting every sprite in the group that appears before the collided sprite is reached and removed. A simple fix would be to check if the hit sprite is the enemy: if enemy == gets_hit:, but the code would still be inefficient, because spritecollideany has to loop over the all_sprites group again and again inside of the for loop.
I recommend to use spritecollide instead of spritecollideany as well, since it's more efficient and just one line of code.