User Tools

Site Tools


p5bg:bullet_game

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
p5bg:bullet_game [2024/09/04 08:54] appledogp5bg:bullet_game [2024/09/11 06:42] (current) – removed appledog
Line 1: Line 1:
-= Bullet Game 
-Bullet Game is our near-end stage pygame 2d game framework example. We've already done at least 6 or 7 other games using pygame. So this will document the patterns we have learned. 
  
-We began by "just writing" a game, then the second part was refactoring the game. I wanted to make refactoring it's own project. What are the goals of this refactoring? 
- 
-* Refactoring 
-** Encapsulation 
-** Light Commentary (code commentary) ex. IN and OUT for functions. 
- 
-The primary goal is encapsulation. So, we're going to break up the old main into several new classes. 
- 
-== PyGame Framework 
-The first part of this is the use of [[pygame framework]]. We'll describe the additions here. 
- 
-== Bullet Game 
-Here is the code we added, starting with main.py: 
- 
-=== main.py 
-<Code:Python> 
-from Window import * 
-from Game import * 
- 
-def main(): 
-    window = Window() 
-    window.setCaption("Bullet Game") 
-    window.setSize(Screen.WIDTH, Screen.HEIGHT) 
-    window.setFont("assets/ps2p.ttf", 32) 
- 
-    game = Game(window) 
-    game.start() 
- 
-if __name__ == "__main__": 
-    main() 
-</Code> 
- 
-=== Screen,py 
-<Code:Python> 
- 
-class Screen: 
-    WIDTH = 800 
-    HEIGHT = 600 
-    FPS = 60 
- 
-    MARGIN = 96 
-    GAMETOP = MARGIN 
-    GAMEBOT = HEIGHT - MARGIN 
-</Code> 
- 
- 
-=== Game.py 
-<Code:Python> 
-import pygame 
-import random 
-import pickle 
- 
-from Screen import * 
-from Window import * 
-from Bullet import * 
-from Color import * 
-from Screen import * 
-from Zombie import * 
-from SpaceShip import * 
-from Sound import * 
-from Player import * 
-from Constants import * 
-from Level import * 
-from Star import * 
- 
- 
-class Game: 
-    def __init__(self, window): 
-        self.window = window 
-        self.sound = Sound() 
- 
-        # Initialize Game World Data 
-        # The Player & Level 
-        self.player = Player() 
-        self.player.hiscore = self.load_hiscore("score.txt") 
- 
-        self.level = Level(1, self.player) 
- 
-        # Bullet list 
-        self.bullets = pygame.sprite.Group() 
- 
-        # Zombies list 
-        self.zombies = pygame.sprite.Group() 
-        self.spaceships = pygame.sprite.Group() 
- 
-        # 30 random stars. 
-        self.stars = [] 
-        for n in range(30): 
-            x = random.randint(0, Screen.WIDTH) 
-            y = random.randint(0, Screen.HEIGHT) 
-            self.stars.append((x, y)) 
- 
-        # All member variables are now globals: 
-        # Try commenting it out to see what happens! 
-        globals().update(self.__dict__) 
- 
-    ################################# 
-    ##          Main Loop          ## 
-    ################################# 
- 
-    def start(self): 
- 
-        # Clock for controlling the frame rate 
-        clock = pygame.time.Clock() 
- 
-        # Main game loop 
-        running = True 
-        frame_counter = 0 
- 
-        ################## 
-        # GAME LOOP ORDER OF EVENTS: 
-        ################## 
-        sound.play("start") 
-        # pygame.mixer.init() 
-        # pygame.mixer.music.load('assets/sound/waveafterwave.mp3') 
-        # pygame.mixer.music.play() 
- 
-        # Start of Game Loop 
-        time_start = time.time() * 1000 
-        LEVEL_DELAY = 3000 
-        while running: 
-            time_clock = (time.time() * 1000) - time_start 
-            frame_counter += 1 
-            if frame_counter > 60: 
-                frame_counter = 1 
- 
-            ######################## 
-            # 1. EVENT HANDLING 
-            ######################## 
-            for event in pygame.event.get(): 
-                if event.type == pygame.QUIT: 
-                    running = False 
-                    quit_game() 
-                if event.type == pygame.KEYDOWN: 
-                    if event.key == pygame.K_z: 
-                        self.create_spaceship() 
-                    if event.key == pygame.K_ESCAPE: 
-                        self.quit_game() 
-                    if event.key == pygame.K_q: 
-                        self.quit_game() 
- 
-                    if event.key == pygame.K_w: 
-                        x = self.player.rect.x + self.player.SIZE / 2 
-                        y = self.player.rect.y + self.player.SIZE / 2 
-                        self.create_bullet(x, y, 0, -1) 
- 
-            # Continuous (frame-by-frame) Key press handling 
-            keys = pygame.key.get_pressed() 
-            if keys[pygame.K_LEFT]: 
-                self.player.rect.x -= self.player.SPEED 
-            if keys[pygame.K_RIGHT]: 
-                self.player.rect.x += self.player.SPEED 
- 
-            ####################### 
-            # 2. RULES SECTION 
-            ####################### 
-            ### Level-specifc stuff: 
-            if time_clock > LEVEL_DELAY: 
-                commands = self.level.tick_hook() 
- 
-                for cmd in commands: 
-                    if cmd == "create zombie": 
-                        self.create_zombie() 
- 
-                    if cmd == "create spaceship": 
-                        self.create_spaceship() 
- 
-                    if cmd == "go to level2": 
-                        self.kill_enemies() 
-                        time_start = time.time() * 1000 
-                        self.level = Level(2, player) 
- 
-                    if cmd == "go to level3": 
-                        self.kill_enemies() 
-                        time_start = time.time() * 1000 
-                        self.level = Level(3, self.player) 
-                    if cmd == "go to level4": 
-                        self.kill_enemies() 
-                        time_start = time.time() * 1000 
-                        self.level = Level(4, self.player) 
- 
-            # 2b. rules for bullets 
-            # 2b.1. Update the bullets position. 
-            self.bullets.update() 
- 
-            # Update all stars. 
-            for i in range(len(self.stars)): 
-                (x, y) = self.stars[i] 
-                y = y + 1 
- 
-                if y > Screen.HEIGHT: 
-                    x = random.randint(0, Screen.WIDTH) 
-                    y = 0 
- 
-                self.stars[i] = (x, y) 
- 
-            if time_clock > LEVEL_DELAY: 
-                # 2a rules for the square 
-                # Keep the square within bounds 
-                self.player.update() 
- 
-                # 2c. rules for zombies 
-                # 2c.1. Update the zombies position. 
-                self.zombies.update() 
-                self.spaceships.update() 
- 
-            # Clear the screen 
-            self.window.screen.fill(Color.BLACK) 
- 
-            # Draw stars first (because its a background) 
-            for s in self.stars: 
-                pygame.draw.rect(self.window.screen, "white", pygame.Rect(s[0], s[1], 2, 2)) 
- 
-            # Draw the square 
-            # pygame.draw.rect(screen, square_color, (square_x, square_y, square_size, square_size)) 
-            self.window.screen.blit(self.player.image, self.player.rect) 
- 
-            if time_clock > LEVEL_DELAY: 
-                # Draw the zombies. 
-                self.zombies.draw(self.window.screen) 
-                self.spaceships.draw(self.window.screen) 
- 
-                # ships make a sound, if... 
-                if self.spaceships: 
-                    if frame_counter == 30: 
-                        self.sound.play("pellet") 
- 
-            # Draw the bullets. 
-            self.bullets.draw(self.window.screen) 
- 
-            # write score. 
-            if frame_counter < 30: 
-                s = "1UP" 
-                text_surface = self.window.font.render(s, True, "white") 
-                self.window.screen.blit(text_surface, (96, 10)) 
- 
-            s = f"{self.player.score:02}" 
-            text_surface = self.window.font.render(s, True, "red") 
-            self.window.screen.blit(text_surface, (160, 42)) 
- 
-            # do high score. 
-            s = "HIGH SCORE" 
-            text_surface = self.window.font.render(s, True, "white") 
-            self.window.screen.blit(text_surface, (320, 10)) 
- 
-            s = f"{self.player.hiscore:02}" 
-            text_surface = self.window.font.render(s, True, "red") 
-            self.window.screen.blit(text_surface, (512, 42)) 
- 
-            s = f"{self.level.level_number}" 
-            text_surface = self.window.font.render(s, True, "red") 
-            self.window.screen.blit(text_surface, (700, 42)) 
- 
-            if time_clock < LEVEL_DELAY: 
-                s = f"Level {self.level.level_number}" 
-                text_surface = self.window.font.render(s, True, "white") 
-                tr = text_surface.get_rect() 
-                tr.center = (Screen.WIDTH // 2, Screen.HEIGHT // 2 - 100) 
-                self.window.screen.blit(text_surface, tr) 
- 
-            # Update the display 
-            pygame.display.flip() 
- 
-            if time_clock > LEVEL_DELAY: 
-                # 3. INTERSPRITE COLLISION 
-                # 3a. bullets kill zombies 
-                collisions = pygame.sprite.groupcollide(self.bullets, self.zombies, True, True) 
-                collisions2 = pygame.sprite.groupcollide(self.bullets, self.spaceships, True, True) 
- 
-                if collisions: 
-                    self.player.score = self.player.score + len(collisions) 
-                    if self.player.score > self.player.hiscore: 
-                        self.player.hiscore = self.player.score 
- 
-                if collisions or collisions2: 
-                    n = random.randint(1, 2) 
-                    if n == 1: 
-                        self.sound.play("boom") 
-                    else: 
-                        self.sound.play("boom7") 
- 
-                if collisions2: 
-                    self.player.score = self.player.score + (len(collisions2) * 10) 
-                    if self.player.score > self.player.hiscore: 
-                        self.player.hiscore = self.player.score 
- 
-                # Players may not touch zombies: 
-                collided_enemies = pygame.sprite.spritecollide(self.player, self.zombies, False) 
- 
-                if collided_enemies: 
-                    print("You are DEAD!") 
-                    print(" High score: " + str(self.player.hiscore)) 
-                    print(" Your score: " + str(self.player.score)) 
-                    self.quit_game() 
- 
-            # Control the frame rate 
-            clock.tick(60) 
- 
-    ################################# 
-    ##      Support Functions      ## 
-    ################################# 
- 
-    def create_bullet(self, x, y, dx, dy): 
-        self.bullet = Bullet(x, y, dx, dy) 
-        self.bullets.add(self.bullet) 
-        self.sound.play("laser") 
-        if Constants.VERBOSE: 
-            print("bullet created") 
- 
-    def create_zombie(self): 
-        sx = random.randint(50, Screen.WIDTH - 50) 
-        sy = 0 + Screen.MARGIN 
-        dx = 0 
-        dy = 1 
-        z = Zombie(sx, sy, dx, dy) 
-        self.zombies.add(z) 
-        if Constants.VERBOSE: 
-            print("zombie created") 
- 
-    def create_spaceship(self): 
-        sx = Screen.WIDTH 
-        sy = 0 + Screen.MARGIN 
-        dx = -1 
-        dy = 0 
- 
-        if random.randint(1, 2) == 1: 
-            dx = 1 
-            sx = 0 
- 
-        s = SpaceShip(sx, sy, dx, dy) 
-        self.spaceships.add(s) 
-        if Constants.VERBOSE: 
-            print("spaceship created") 
- 
-    def kill_enemies(self): 
-        for z in self.zombies: 
-            z.kill() 
-        for s in self.spaceships: 
-            s.kill() 
- 
-    # Save the score to a text file. 
-    def save_hiscore(self, filename, score): 
-        with open(filename, 'w') as file: 
-            file.write(str(score)) 
- 
-    # Load the score from a text file. 
-    def load_hiscore(self, filename): 
-        try: 
-            with open(filename, 'r') as file: 
-                score = int(file.read()) 
-                return score 
-        except: 
-            print(f"Error. Resetting high score to 0.") 
-            return 0 
- 
-    def quit_game(): 
-        self.save_hiscore("score.txt", str(self.player.hiscore)) 
-        pygame.quit() 
-        quit() 
-</Code> 
- 
-=== Level.py 
-<Code:Python> 
-import random 
- 
-class Level: 
- 
-    def __init__(self, n, p): 
-        self.level_number = n 
-        self.player = p 
- 
-        match self.level_number: 
-            case 1: 
-                self.tick_hook = self.level1 
- 
-            case 2: 
-                self.tick_hook = self.level2 
- 
-            case 3: 
-                self.tick_hook = self.level3 
- 
-            case 4: 
-                self.tick_hook = self.level4 
- 
-            case default: 
-                print("Unknown Level Number: " + str(n)) 
-                print("Defaulting to Level 1!") 
-                self.tick_hook = self.level1 
- 
-        return 
- 
- 
-##### Tick Hooks 
-    def level1(self): 
-        commands = [] 
- 
-        if random.randint(1,45) == 1: 
-            commands.append("create zombie") 
- 
-        if self.player.score >= 20: 
-            commands.append("go to level2") 
- 
-        return commands 
- 
- 
-    def level2(self): 
-        commands = [] 
- 
-        if random.randint(1, 35) == 1: 
-            commands.append("create zombie") 
- 
-        if self.player.score >= 40: 
-            commands.append("go to level3") 
- 
-        return commands 
- 
-    def level3(self): 
-        commands = [] 
- 
-        if random.randint(1, 30) == 1: 
-            commands.append("create zombie") 
- 
-        if random.randint(1, 500) == 1: 
-            commands.append("create spaceship") 
- 
-        if self.player.score >= 80: 
-            commands.append("go to level4") 
- 
-        return commands 
- 
-    def level4(self): 
-        commands = [] 
- 
-        if random.randint(1, 20) == 1: 
-            commands.append("create zombie") 
- 
-        if random.randint(1, 350) == 1: 
-            commands.append("create spaceship") 
- 
-        #if self.player.score > 320: 
-        #    commands.append("go to level5") 
- 
-        return commands 
-</Code> 
- 
-=== Object.py 
-<Code:Python> 
-import pygame 
- 
-class Object(pygame.sprite.Sprite): 
-    def __init__(self, x, y, width, height, name=None): 
-        super().__init__() 
-        self.rect = pygame.Rect(x, y, width, height) 
-        self.image = pygame.Surface((width, height), pygame.SRCALPHA) 
-        self.width = width 
-        self.height = height 
-        self.name = name 
- 
-    def draw(self, win, offset_x, offset_y): 
-        win.blit(self.image, (self.rect.x - offset_x, self.rect.y + offset_y)) 
- 
-</Code> 
- 
-=== Player.py 
-<Code:Python> 
-import pygame 
-import time 
-from Color import * 
-from Screen import * 
- 
-# Define the Bullet Sprite class 
-class Player(pygame.sprite.Sprite): 
-    SPEED = 5 
-    SIZE = 20 
-    COLOR = Color.WHITE 
- 
-    def __init__(self): 
-        super().__init__() 
-        self.ticks = 0 
-        self.loops = 0 
- 
-        # Create a surface for the bullet 
-        self.image = pygame.Surface((self.SIZE, self.SIZE)) 
- 
-        # Fill the surface with a color 
-        self.image.fill(self.COLOR) 
- 
-        # Get the rectangle for positioning 
-        self.rect = self.image.get_rect() 
- 
-        # Set the initial position 
-        self.rect.center = (Screen.WIDTH//2, Screen.HEIGHT-50) 
- 
-        self.score = 0 
-        self.hiscore = 0 
- 
-    def update(self): 
-        # Restrict to screen. 
-        if self.rect.x < 0: 
-            self.rect.x = 0 
-        if self.rect.x > Screen.WIDTH - self.SIZE: 
-            self.rect.x = Screen.WIDTH - self.SIZE 
-        if self.rect.y < 0: 
-            self.rect.y = 0 
-        if self.rect.y > Screen.HEIGHT - self.SIZE: 
-            self.rect.y = Screen.HEIGHT - self.SIZE 
- 
-        # Easier to read, but, slower. 
-        #self.rect.x = max(0, min(self.rect.x, Screen.WIDTH - self.SIZE)) 
-        #self.rect.y = max(0, min(self.rect.y, Screen.HEIGHT - self.SIZE)) 
-</Code> 
- 
-=== Sound.py 
-<Code:Python> 
-import pygame as a 
- 
-class Sound: 
-    def __init__(self): 
-        a.mixer.init() 
-        dir = 'assets/sound/' 
-        self.sounds = {} 
- 
-        self.sounds["laser"] = a.mixer.Sound(dir+'laser1.wav') 
-        self.sounds["laser"].set_volume(0.15) 
-        self.sounds["boom"] = a.mixer.Sound(dir+'boom6.wav') 
-        self.sounds["boom7"] = a.mixer.Sound(dir+'boom7.wav') 
-        self.sounds["start"] = a.mixer.Sound(dir+'start4.wav') 
-        self.sounds["pellet"] = a.mixer.Sound(dir+'pellet.wav') 
- 
-    def play(self, sound): 
-        if sound in self.sounds: 
-            self.sounds[sound].play() 
-        else: 
-            print(f"There is no {sound} sound!") 
-</Code> 
p5bg/bullet_game.1725440099.txt.gz · Last modified: 2024/09/04 08:54 by appledog

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki