Skip to content

Refactor main.py: Fix Event Loop, Collision Checks, and Random Usage Bugs #4

@GitJohnFis

Description

@GitJohnFis

The main.py file contains several bugs and structural issues that hinder the game's functionality. Below is a list of the identified bugs and a proposed refactored code snippet to illustrate the required changes:

Identified Bugs:

  1. Undefined Variable:

    • The reference to players.containers is invalid since players is not defined anywhere in the code.
  2. Incorrect Collision Checks:

    • The code uses player.collides_with(player) to check collisions with asteroids. It should instead compare the player with each asteroid (i.e., player.collides_with(asteroid)).
    • Similarly, shot.collides_with(shot) is used within the shot loop, which is incorrect. It should be checking the shot against asteroids (i.e., shot.collides_with(asteroid)).
  3. Powerup Handling Errors:

    • The incorrect reference of power_up.power_type is used instead of powerup.power_type.
    • There are typos with "sheild" instead of "shield" and the incorrect method name activate_sheild() instead of activate_shield().
  4. Random Module Usage:

    • The random.choice function is misused with two separate arguments: random.choice(["shield"], ["speed"]) instead of random.choice(["shield", "speed"]).
    • Ensuring proper use of random.random() for determining a 20% chance of spawning a powerup.
  5. Pre-Game Loop Code Execution:

    • The powerup update/draw block is executed before the game loop starts, using dt before it has been assigned.
  6. Structural Issues in the Game Loop:

    • The event loop, updates, collision checks, and drawing logic are not well-organized, leading to potential runtime errors and poor maintainability.

Proposed Refactored Code Snippet:

import pygame
import sys
import random

from player import Player
from constants import *
from asteroid import Asteroid
from asteroidfield import AsteroidField
from shoot import Shot
from powerups import PowerUp

def main():
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    clock = pygame.time.Clock()

    # Initialize sprite groups
    updatable = pygame.sprite.Group()
    drawable = pygame.sprite.Group()
    asteroids = pygame.sprite.Group()
    shots = pygame.sprite.Group()
    powerups = pygame.sprite.Group()

    # Set container references
    Asteroid.containers = (asteroids, updatable, drawable)
    Shot.containers = (shots, updatable, drawable)
    AsteroidField.containers = updatable
    PowerUp.containers = (powerups, updatable, drawable)

    asteroid_field = AsteroidField()
    player = Player(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)

    dt = 0
    running = True
    while running:
        # Event handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
        
        # Update all objects
        updatable.update(dt)
        
        # Check for player-asteroid collisions
        for asteroid in asteroids:
            if player.collides_with(asteroid):
                print("Game Over!")
                pygame.quit()
                sys.exit()

        # Check for player-powerup collisions
        for powerup in powerups:
            if player.collides_with(powerup):
                if powerup.power_type == "shield":
                    player.activate_shield()
                elif powerup.power_type == "speed":
                    player.activate_speed_boost()
                powerups.remove(powerup)

        # Check for shot-asteroid collisions
        for shot in shots:
            for asteroid in asteroids:
                if shot.collides_with(asteroid):
                    shot.kill()
                    asteroid.split()
                    if random.random() <= 0.2:
                        power_type = random.choice(["shield", "speed"])
                        spawn_powerup = PowerUp(asteroid.position.x, asteroid.position.y, power_type)
                        powerups.add(spawn_powerup)

        # Drawing
        screen.fill("black")
        for obj in drawable:
            obj.draw(screen)
        player.draw(screen)
        pygame.display.flip()
        dt = clock.tick(60) / 1000
    pygame.quit()

if __name__ == "__main__":
    main()

// Please review this draft issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions