I have created this account only to ask this question :D I am learning python and for my portfolio I am trying to create some game in OOP approach in python.
I have a problem with collisions and I don't even know how to check where the mistake is.
When player's bullets go offscreen, they disappear as they should and there is a limiter for max of 3 bullets. So I guess this part is good for sure.
But when bullet's rect meets green alien's rect, it doesn't disappear nor reduce alien's hp, because alien doesn't disappear...
I am already so frustrated, because this bug stopped me for 2 days... I have my game in 2 files: main.py and static.py for images, classes etc.
I think there is a problem in section #PLAYER'S BULLET BEHAVIOR in Main.py
Please, help :)
Ps. I use VSC if it matters
THIS IS MY Main.py:
import pygame as pg
from static import *
pg.init()
# ------------- BACKGROUND AND LVL SETTINGS ------------- #
bg1 = Background(bg_img1scaled)
lvl = 1
red_enemies_count = 5
green_enemies_count = 5
# ------------- ENEMIES SETTINGS ------------- #
redEnemyList = [RedEnemy() for _ in range(red_enemies_count)]
greenEnemyList = [GreenEnemy() for _ in range(green_enemies_count)]
# ------------- GAME LOOP ------------- #
clock = pg.time.Clock()
run = True
while run:
# FPS HANDLER
clock.tick(FPS)
# EVENT HANDLER
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE and len(p_bulletList) < 3:
p_bulletList.append(P_Bullet())
# ENEMY BEHAVIOR
for red_enemy in redEnemyList:
if red_enemy.x > 0 and red_enemy.x + red_enemy.img_width < WIDTH:
red_enemy.x += red_enemy.speed
if red_enemy.x + red_enemy.img_width >= WIDTH or red_enemy.x <= 0:
red_enemy.speed = -red_enemy.speed
red_enemy.x += red_enemy.speed
for green_enemy in greenEnemyList:
if green_enemy.x > 0 and green_enemy.x + green_enemy.img_width < WIDTH:
green_enemy.x += green_enemy.speed
if green_enemy.x + green_enemy.img_width >= WIDTH or green_enemy.x <= 0:
green_enemy.speed = -green_enemy.speed
green_enemy.x += green_enemy.speed
if green_enemy.hp == 0:
greenEnemyList.remove(green_enemy)
# PLAYER'S BULLETS BEHAVIOR
for bullet in p_bulletList:
bullet.y -= P_BULLET_SPEED
if bullet.y <= 0:
p_bulletList.remove(bullet)
if bullet.rect.colliderect(green_enemy.rect):
green_enemy.hp -= 1
p_bulletList.remove(bullet)
# PLAYER MOVEMENT
key_pressed = pg.key.get_pressed()
if key_pressed[pg.K_UP] and (player_rect.y > 0):
dy = -P_SPEED
player_rect.y += dy
if key_pressed[pg.K_DOWN] and (player_rect.y < HEIGHT - player_rect.height):
dy = P_SPEED
player_rect.y += dy
if key_pressed[pg.K_LEFT] and (player_rect.x > 0):
dx = -P_SPEED
player_rect.x += dx
if key_pressed[pg.K_RIGHT] and (player_rect.x < WIDTH - player_rect.width):
dx = P_SPEED
player_rect.x += dx
# DISPLAY HANDLER
window.fill(BLACK)
bg1.draw_bg(window)
for red_enemy in redEnemyList:
red_enemy.draw_enemy(window)
for green_enemy in greenEnemyList:
green_enemy.draw_enemy(window)
draw(window, player_scaled, player_rect)
for bullet in p_bulletList:
bullet.draw_bullet(window)
pg.display.update()
pg.quit()
THIS IS MY Static.py:
import pygame as pg
import random
# ------------- COLORS ------------- #
BLACK = 0, 0, 0
WHITE = 255, 255, 255
RED = 255, 0, 0
GREEN = 0, 255, 0
BLUE = 0, 0, 255
# ------------- SCREEN SETTINGS ------------- #
WIDTH = 1200
HEIGHT = 800
window = pg.display.set_mode((WIDTH, HEIGHT))
FPS = 60
# ------------- IMAGES ------------- #
bg_img1 = pg.image.load('images/backgrounds/background_0.png')
bg_img1scaled = pg.transform.scale(bg_img1, (WIDTH, HEIGHT)).convert_alpha()
player_img = pg.image.load('images/player/player_ship.png')
player_scaled = pg.transform.scale(player_img,
(player_img.get_width() * 0.5, player_img.get_height() * 0.5)).convert_alpha()
# ------------- PLAYER SETTINGS ------------- #
player_rect = player_scaled.get_rect()
player_rect.center = (WIDTH // 2, HEIGHT - player_rect.height // 2)
p_width = player_rect.width
p_heigh = player_rect.height
P_SPEED = 6
dx = 0
dy = 0
P_BULLET_SPEED = 10
max_p_bullets = 3
p_bulletList = []
# ------------- CLASSES ------------- #
class Background():
def __init__(self, image):
self.img = image
self.x = 0
self.y = 0
def draw_bg(self, screen_var_name):
screen_var_name.blit(self.img, (self.x, self.y))
class P_Bullet():
def __init__(self):
self.img = pg.image.load(
'images/player/player_bullet2.png').convert_alpha()
self.img_width = self.img.get_width()
self.img_height = self.img.get_height()
self.rect = self.img.get_rect()
self.rect.x = player_rect.x + player_rect.width // 2 - self.img_width // 2
self.rect.y = player_rect.y - self.img_height
self.x = self.rect.x
self.y = self.rect.y
def draw_bullet(self, screen_var_name):
screen_var_name.blit(self.img, (self.x, self.y))
class RedEnemy():
def __init__(self):
self.img = pg.image.load('images/enemies/red_alien.png')
self.img_scaled = pg.transform.scale(self.img,
(player_rect.width, player_rect.height)).convert_alpha()
self.img_width = self.img_scaled.get_width()
self.img_height = self.img_scaled.get_height()
self.rect = self.img_scaled.get_rect()
self.rect.x = random.randint(1, WIDTH - self.img_width)
self.rect.y = random.randint(0, 170)
self.x = self.rect.x
self.y = self.rect.y
self.speed = random.randint(3, 6)
self.hp = 3
def draw_enemy(self, screen_var_name):
screen_var_name.blit(self.img_scaled, (self.x, self.y))
class GreenEnemy(RedEnemy):
def __init__(self):
self.img = pg.image.load('images/enemies/green_alien.png')
self.img_scaled = pg.transform.scale(self.img,
(player_rect.width, player_rect.height)).convert_alpha()
self.img_width = self.img_scaled.get_width()
self.img_height = self.img_scaled.get_height()
self.rect = self.img_scaled.get_rect()
self.rect.x = random.randint(1, WIDTH - self.img_width)
self.rect.y = random.randint(270, 370)
self.x = self.rect.x
self.y = self.rect.y
self.speed = random.randint(2, 4)
self.hp = 2
# ------------- DEFs ------------- #
def draw(screen_var_name, img, rect: pg.Rect):
screen_var_name.blit(img, rect)
Why do you need the .x
and .y
attributes? You have rect.x
and rect.y
. Anyway, when you change x
, and y
you also need to change rect.x
, and rect.y
. Note, bullet.rect.colliderect(green_enemy.rect):
uses green_enemy.rect
, but green_enemy.x
and green_enemy.y
. rect
is not tied to x
and y
, rect.x
and rect.y
don't magically update when you change x
and y
.
Update the rect
attribute before the collision test:
while run:
# [...]
for bullet in p_bulletList:
bullet.y -= P_BULLET_SPEED
if bullet.y <= 0:
p_bulletList.remove(bullet)
else:
# update bullet.rect and green_enemy.rect
bullet.rect.topleft = bullet.x, bullet.y
green_enemy.rect.topleft = green_enemy.x, green_enemy.y
if bullet.rect.colliderect(green_enemy.rect):
green_enemy.hp -= 1
p_bulletList.remove(bullet)
See also How do I detect collision in pygame?.