Shoot a bullet with space bar?

Issue

I am having difficulty programming a game using pygame. The player disappears when I press the space bar, the while self.shooting: loop does not break when y reaches a certain point, and the loop breaks when I move the mouse quickly or press multiple buttons at once.

import pygame, os

os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()

win = pygame.display
d = win.set_mode((1200, 600))

class player:
    def __init__(self, x, y, height, width):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.speed = 2

    def draw(self):
        pygame.draw.rect(d, (0, 0, 0), (self.x, self.y, self.width, self.height))

    def move_left(self):
        self.x -= self.speed

    def move_right(self):
        self.x += self.speed


class bullet:
    def __init__(self):
        self.radius = 10
        self.speed = 20

    def shoot(self):
        x = p.x
        y = p.y
        self.shooting = True
        while self.shooting:
            d.fill((98, 98, 98))
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()

            y -= self.speed
            pygame.draw.circle(d, (255, 0, 0), (x, y), self.radius)
            pygame.time.Clock().tick(100)
            win.update()

            if y <= 0:
                self.shooting = False


b = bullet()
p = player(600, 500, 50, 30)
while True:
    d.fill((98, 98, 98))
    p.draw()
    for event in pygame.event.get():
        pass

    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_SPACE:
            b.shoot()
        if event.key == pygame.K_LEFT:
            p.move_left()
        if event.key == pygame.K_RIGHT:
            p.move_right()

    win.update()

Answer

The issue is with the indentation of the for loop in the while self.shooting: loop, it should be properly indented. To fix the other issues, add a break statement after self.shooting = False to break out of the while self.shooting: loop, and add pygame.time.delay(10) after win.update() to prevent the loop from breaking when the mouse is moved too quickly or multiple buttons are pressed at once. Here is the corrected code:

import pygame, os

os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()

win = pygame.display
d = win.set_mode((1200, 600))

class player:
    def __init__(self, x, y, height, width):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.speed = 2

    def draw(self):
        pygame.draw.rect(d, (0, 0, 0), (self.x, self.y, self.width, self.height))

    def move_left(self):
        self.x -= self.speed

    def move_right(self):
        self.x += self.speed


class bullet:
    def __init__(self):
        self.radius = 10
        self.speed = 20

    def shoot(self):
        x = p.x
        y = p.y
        self.shooting = True
        while self.shooting:
            d.fill((98, 98, 98))
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()

            y -= self.speed
            pygame.draw.circle(d, (255, 0, 0), (x, y), self.radius)
            pygame.time.Clock().tick(100)
            win.update()

            if y <= 0:
                self.shooting = False
                break

    b = bullet()
    p = player(600, 500, 50, 30)
    while True:
        d.fill((98, 98, 98))
        p.draw()
        for event in pygame.event.get():
            pass

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                b.shoot()
            if event.key == pygame.K_LEFT:
                p.move_left()
            if event.key == pygame.K_RIGHT:
                p.move_right()

        win.update()
        pygame.time.delay(10)