Pygame Bullet Rain Collision and Afterimage

Viewed 49

I was making a simple game where there is an enemy where you can shoot at and you can move left to right to a certain extent. After doing that I wanted to be when the enemy has > 70 health it rains a wave of bullets you have to dodge. There are 3 problems with it I see though, one it has an afterimage, its not a single bullet coming down it like draw it all the way down. Two I have text displayed and if hit it is supposed to change that text to You Lost and that doesn't work. Three even though I put in the code it should trigger at >+ 70 health at 70 health it spawns the bullets and they stay at the top then when I try to shoot is when they come down. Sorry if this is alot but I don't know how to fix it. Here is my code:

import pygame
import time
pygame.font.init()
WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Boss Fight")
FPS = 60
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
BLUE = (0, 0, 255)
RED = (255,0,0)
FLOOR = pygame.Rect(0, 400, 900, 100)
SPEED = 1
BULLET_SPEED = 1
player = pygame.Rect(50, 350, 50, 50)
numJumps = []
MAXBULLETS = 2
BOSS = pygame.Rect(700, 300, 100, 100)
FONT = pygame.font.SysFont('comicsans', 30)
BOSSHEALTH = 100
winText = ""
RESTART = pygame.USEREVENT + 1
LOST = pygame.USEREVENT + 2


def draw_window(playerBullets, rainBullets):
    WIN.fill(WHITE)
    pygame.draw.rect(WIN, BLACK, FLOOR)
    pygame.draw.rect(WIN, BLUE, player)
    pygame.draw.rect(WIN, RED, BOSS)
    boss_health = FONT.render("BOSS HEALTH: " + str(BOSSHEALTH), 1,BLACK)
    WIN.blit(boss_health, (450, 50))
    won = FONT.render(winText,1,BLACK)
    WIN.blit(won, (100, 50))
    for bullet in playerBullets:
        pygame.draw.rect(WIN, BLACK, bullet)
    for b in rainBullets:
        pygame.draw.rect(WIN, BLACK, b)
    pygame.display.update()




def movement(p):
    keys_helds = pygame.key.get_pressed()
    if keys_helds[pygame.K_a] and p.x + SPEED > 0:
        p.x -= SPEED
    if keys_helds[pygame.K_d] and p.x < 400 + p.width:
        p.x += SPEED

def p_bullet_movement(playerBullets, boss, raining, player, rainBullets):
    for bullet in playerBullets:
        bullet.x += BULLET_SPEED
        if boss.colliderect(bullet):
            global BOSSHEALTH
            BOSSHEALTH-= 10
            playerBullets.remove(bullet)
        if BOSSHEALTH <= 70:
            global winText
            winText = "Bullet Rain!"
            raining = True
            for b in rainBullets:
                b.y += 1
                if player.colliderect(b):
                    pygame.event.post(pygame.event.Event(LOST))
                    rainBullets.remove(b)
                if b.y + BULLET_SPEED > HEIGHT:
                    rainBullets.remove(b)
            bullet1 = pygame.Rect(20, 0, 40, 25)
            bullet2 = pygame.Rect(170, 0, 40, 25)
            bullet3 = pygame.Rect(370, 0, 40, 25)
            bullet4 = pygame.Rect(570, 0, 40, 25)
            rainBullets.append(bullet1)
            rainBullets.append(bullet2)
            rainBullets.append(bullet3)
            rainBullets.append(bullet4)

        if BOSSHEALTH == 0:
            winText = "You Won!"





def main():
    playerBullets = []
    raining = False
    rainBullets = []
    clock = pygame.time.Clock()
    run = True
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE and not(raining):
                    bullet = pygame.Rect(player.x, player.y, 40, 25)
                    playerBullets.append(bullet)
            if event.type == LOST:
                global winText
                wintext = "You Lost!"
                 

        draw_window(playerBullets, rainBullets)
        movement(player)
        p_bullet_movement(playerBullets, BOSS, raining, player, rainBullets)
        clock.tick(FPS)



if __name__ == '__main__':
    main() 
2 Answers

one it has an afterimage, its not a single bullet coming down it like draw it all the way down.

That's because you create 4 new bullets every frame for each playerBullets.

Two I have text displayed and if hit it is supposed to change that text to You Lost and that doesn't work.

That's because you set wintext, not winText here:

    if event.type == LOST:
        global winText
        wintext = "You Lost!"

Three even though I put in the code it should trigger at >+ 70 health at 70 health ...

No, you check for <= 70, not > 70:

...
if BOSSHEALTH <= 70:
   ...

it spawns the bullets and they stay at the top then when I try to shoot is when they come down.

Look at the way you indented your code here:

def p_bullet_movement(playerBullets, boss, raining, player, rainBullets):
    for bullet in playerBullets:
        bullet.x += BULLET_SPEED
        if boss.colliderect(bullet):
            global BOSSHEALTH
            BOSSHEALTH-= 10
            playerBullets.remove(bullet)
        if BOSSHEALTH <= 70:
            global winText
            winText = "Bullet Rain!"
            raining = True
            for b in rainBullets:
                b.y += 1
                ...

You move each object in rainBullets for every bullet in playerBullets if BOSSHEALTH <= 70.

So if BOSSHEALTH <= 70 is not true or there are no objects in playerBullets, the for b in rainBullets: line will never be reached.

Since p_bullet_movement is called in the main loop, you need to add some kind of a condition that will limit how many bullets get appened to the list. Since the numbers of bullets that can be added is unlimited right now, it continues to keep adding bullets every frame, which you called after image.

A way to fix it is to only add the bullets if the list is empty.

    if not rainBullets:
        rainBullets.append(bullet1)
        rainBullets.append(bullet2)
        rainBullets.append(bullet3)
        rainBullets.append(bullet4)
Related