Проблема в том, что событие нажатия на кнопку срабатывает только в момент нажатия. Так что если просто держать пробел, то в каждом последующем цикле событие нажатия не срабатывает, но флаг fire сбрасывается в False каждый цикл, поэтому стрельба останавливается.
Можно флаг fire привязать к самому кораблю как аттрибут, т.е. в __init__
self.fire = False
И в событиях работать именно с атрибутом класса, а не передавать отдельную переменную fire.
def check_keydown_events(event, ship, settings, screen, bullets):
    if event.key == pygame.K_LEFT:
        # left arrow keydown events
        ship.move_left = True  # moves ship left when key's keeping pressed
    if event.key == pygame.K_RIGHT:
        # right arrow keydown events
        ship.move_right = True  # moves ship right when key's keeping pressed
    if event.key == pygame.K_DOWN:
        # down arrow keydown events
        ship.move_down = True  # moves ship down when key's keeping pressed
    if event.key == pygame.K_UP:
        # up arrow keydown events
        ship.move_up = True  # moves ship up when key's keeping pressed
    if event.key == pygame.K_SPACE:
        ship.fire = True
Аналогично изменить в функции отпускания кнопки.
Но т.к. событие нажатия не срабатывает повторно каждый цикл, то и само создание новых пуль не будет работать в той функции, так что ее нужно перенести туда, где срабатывает каждый цикл, например в тот же check_events
def check_events(ship, settings, screen, bullets):
    """main event checker function"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            # working on keydown events
            check_keydown_events(event, ship, settings, screen, bullets)
            # function that checks keydown event type and works according event type
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, ship)
            # function that checks keyup event type and works according event type
    print(len(bullets))  # to check amount of bullets on screen
    if ship.fire and len(bullets) < settings.bullets_allowed:
        # continues firing until amount of bullets reaches limit
        new_bullet = Bullet(settings, ship, screen)  # creating new bullet
        bullets.add(new_bullet)  # adding created bullet to Group