python realizes the airplane battle game (pygame version)

Posted by sfarid on Tue, 04 Feb 2020 13:43:34 +0100

Catalog

 

brief introduction

Implementation process

epilogue

brief introduction

Using python to realize pygame version of the aircraft war game;

Environment: Windows system + python3.8.0

Rules of the game:

1. Click "PLAY" or press "P" to start the game;

2. The enemy aircraft is generated from the top random position according to the set frequency, and then moves downward;

3. The airship is generated in the middle of the bottom. Players use the up and down keys to control the movement of the airship and hit the space bar to launch bullets;

4. When the bullet hits the enemy aircraft, it will produce explosive effect and accumulate scores to the upper right corner;

5. After killing 10 aircrafts, the level increases, the generation frequency of enemy aircrafts becomes faster and the falling speed becomes faster;

6. When all three lives are gone, the game is over.

The effect of the game is as follows:

Implementation process

  1. Create a new file "file.py" to store information to the file and read the information of the file. This example is used to store and read the highest score;
    import pickle
    # filename = 'file/stats.pkl'
    # Store information to file
    def save_file(obj, filename):
        statsObj = load_file(filename)
        if statsObj == 0:
            # Save dictionary directly when no file exists
            with open(filename, 'wb') as f:
                pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL)
        else:
            # When a file exists, only the highest score in the file is modified
            for key, val in statsObj.items():
                # Get the highest score value of the file (used when there is more than one file field)
                if key == 'highScore':
                    statsObj[key] = obj['highScore']
            obj = statsObj
        with open(filename, 'wb') as f:
            pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL)
        
    # Read information
    def load_file(filename):
        try:
            with open(filename, 'rb') as f:
                return pickle.load(f)
        except FileNotFoundError:
            # Enter error message if no file exists
            msg = "Sorry, the file " + filename + " does not exist."
            print(msg)
            return 0
     
    # obj = {'highScore': 20, 'points': 5}
    # obj = {'highScore': 50}
    # save_file(obj, filename)
    # filedata = load_file(filename)
    # print(filedata)

     

  2. Create a new file, settings.py, to define some necessary basic properties and initial values;
    import file as f
    class Settings():
        def __init__(self):
            self.screen_width = 480
            self.screen_height = 660
            self.bg_color = (230, 230, 230)
            # Bullet settings (width, height, color, maximum number)        
            self.bullet_width = 5
            self.bullet_height = 15
            self.bullet_color = 255, 255, 255
            # Enemy aircraft moving frequency
            self.enemy_frequency = 0
            # Speed up the game
            self.speedup_scale = 1.1
            # Speed of score increase
            self.score_scale = 1.5
     
            self.initialize_settings()
            # Initialize statistics
            self.reset_stats()
            # Statistics file path
            self.filename = 'file/stats.pkl'
            # The game was inactive when it was first started
            self.game_active = False
            # Read the highest score of the file, in no case should the highest score be reset
            statsObj = f.load_file(self.filename)
            if statsObj == 0:
                # If no file exists, the maximum score is 0
                highScore = 0
            else:
                for key, val in statsObj.items():
                    # Get the highest score value of the file (used when there is more than one file field)
                    if key == 'highScore':
                        highScore = val
            self.high_score = highScore
             
        def initialize_settings(self):
            """Initialize settings that change as the game progresses"""
            self.player_move_speed = 2.5
            self.bullet_speed = 3
            self.enemy_move_speed = 1
            # Score
            self.one_points = 50
        def increase_speed(self):
            """Increase speed settings"""
            # self.player_move_speed *= self.speedup_scale
            self.bullet_speed *= self.speedup_scale
            self.enemy_move_speed *= self.speedup_scale
            self.one_points = int(self.one_points * self.score_scale)
        def reset_stats(self):
            """Initialize statistics that may change during the game run"""
            # Number of shooting loss
            self.player_limit = 3
            # Firing fraction
            self.score = 0
            # Grade
            self.level = 1
            # Hit how many rectangles to upgrade
            self.level_number = 10
            # Generate enemy frequency interval
            self.enemy_frequency_space = 50

     

  3. Create a new file, enemy.py, to define the enemy aircraft class (randomly generated by position topleft) and the declaration method move;
    import pygame
    import random
    from pygame.sprite import Sprite
    class Enemy(Sprite):
        def __init__(self, enemy_down_imgs, settings):
            super(Enemy, self).__init__()
            self.image = pygame.image.load('images/enemy1.png')
            self.rect = self.image.get_rect() 
            self.rect.topleft = [random.randint(0, settings.screen_width - self.rect.width), 0]
            self.down_imgs = enemy_down_imgs
            self.speed = settings.enemy_move_speed
            self.down_index = 0
    
        # Enemy aircraft movement, boundary judgment and deletion are handled in the main cycle of the game
        def move(self):
            self.rect.top += self.speed

     

  4. Create a new file, player.py, to define the player class (which can be moved up, down, left, right) and corresponding methods;
    import pygame
    from pygame.sprite import Sprite
    class Player(Sprite):
        def __init__(self, settings, screen):
            super(Player, self).__init__()
            self.settings = settings
            self.screen = screen
            self.screen_rect = self.screen.get_rect()
            # Bring in a picture of the ship and locate it
            self.image = pygame.image.load('images/player.png')        
            self.rect = self.image.get_rect()
            self.rect.centerx = self.screen_rect.centerx
            self.rect.bottom = self.screen_rect.bottom
     
            # Mobile logo
            self.move_left = False
            self.move_right = False
            self.move_down = False
            self.move_up = False
        def rotate(self, angle):
            # pictures rotating
            self.image = pygame.transform.rotate(self.image, angle)
        def scale(self, multiple):
            # Image scaling
            self.image = pygame.transform.smoothscale(self.image, (multiple, multiple))
        def update(self):
        	if self.move_left and self.rect.left > self.screen_rect.left:
        		self.rect.centerx -= self.settings.player_move_speed
        	if self.move_right and self.rect.right < self.screen_rect.right:
        		self.rect.centerx += self.settings.player_move_speed
        	if self.move_down and self.rect.bottom < self.screen_rect.bottom:
        		self.rect.centery += self.settings.player_move_speed
        	if self.move_up and self.rect.top > 0:
        		self.rect.centery -= self.settings.player_move_speed
        def draw_player(self):
            """Draw spacecraft to screen"""
            self.screen.blit(self.image, self.rect)

     

  5. A new file "bullet.py" is created to define the bullet class (located at the top of the spacecraft and moved upward) and corresponding methods;
    import pygame
    from pygame.sprite import Sprite
    class Bullet(Sprite):
        """ A class that manages the bullets fired by a spaceship """
        def __init__(self, settings, screen, player):
            """ Create a bullet object where the ship is located """
            super(Bullet, self).__init__()
            self.screen = screen
            #  Create a rectangle representing the bullet at (0,0) and set the correct position
            self.rect = pygame.Rect(0, 0, settings.bullet_width, settings.bullet_height)
            self.rect.centerx = player.rect.centerx
                # Top of spacecraft
            self.rect.bottom = player.rect.top
            # Store bullet position in decimal
            self.y = float(self.rect.y)
            self.color = settings.bullet_color
            self.speed = settings.bullet_speed
        def update(self):
            """Move the bullet up"""
            # Update the small value indicating the bullet position (bullet to the right)
            self.y -= self.speed
            # Update the location of the rect that represents the bullet
            self.rect.y = self.y
        def draw_bullet(self):
            """Draw bullets on the screen"""
            pygame.draw.rect(self.screen, self.color, self.rect)

     

  6. Create a new file "button.py" to define button classes and corresponding methods. This example is used to draw "PLAY" buttons;
    import pygame.font
    class Button():
        def __init__(self, screen, msg):
            """Initialize button properties"""
            self.screen = screen
            self.screen_rect = screen.get_rect()
            # Set button size and other properties
            self.width, self.height = 100, 30
            self.button_color = (216, 30, 6)
            self.text_color = (255, 255, 255)
            self.font = pygame.font.SysFont(None, 36)
            # Create and center the button's rect object
            self.rect = pygame.Rect(0, 0, self.width, self.height)
            self.rect.center = self.screen_rect.center
            # The label of the button needs to be created only once
            self.prep_msg(msg)
        def prep_msg(self, msg):
            """take msg Render as image and center it on the button"""
            self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
            self.msg_image_rect = self.msg_image.get_rect()
            self.msg_image_rect.center = self.rect.center
        def draw_button(self):
            # Draw a color filled button, and then draw the text
            self.screen.fill(self.button_color, self.rect)
            self.screen.blit(self.msg_image, self.msg_image_rect)

     

  7. Create a new file "scoreboard.py" to define the scoreboard. This example is used to draw the spaceship (life number) in the upper left corner, the "highest score" in the middle of the top, the "integral" and "level" in the upper right corner;
    import pygame.font
    from pygame.sprite import Group
    from player import Player
    class Scoreboard():
        """Category displaying score information"""
        def __init__(self, settings, screen):
            """Attribute involved in initializing display score"""
            self.screen = screen
            self.screen_rect = screen.get_rect()
            self.settings = settings
            # Font settings used to display score information
            self.text_color = (255, 255, 255)
            self.font = pygame.font.SysFont(None, 30)
            # Spacecraft scale value
            self.scaleValue = 20
            # Prepare initial score image \ maximum score \ level
            self.prep_score()
            self.prep_high_score()
            self.prep_level()
            self.prep_players()
        def prep_score(self):
            """Convert score to rendered image"""
            rounded_score = int(round(self.settings.score, -1))
            score_str = '{:,}'.format(rounded_score)
            self.score_image = self.font.render(score_str, True, self.text_color)
            # Put the score in the top right corner of the screen
            self.score_rect = self.score_image.get_rect()
            self.score_rect.right = self.screen_rect.right -20
            self.score_rect.top = 10
        def prep_high_score(self):
            """ Convert highest score to rendered image """
            high_score = int(round(self.settings.high_score, -1))
            high_score_str = "{:,}".format(high_score)
            self.high_score_image = self.font.render(high_score_str, True, self.text_color)
            # Center the highest score on the top of the screen
            self.high_score_rect = self.high_score_image.get_rect()
            self.high_score_rect.centerx = self.screen_rect.centerx
            self.high_score_rect.top = self.score_rect.top
        def prep_level(self):
            """Convert levels to rendered images"""
            self.level_image = self.font.render(str(self.settings.level), True, self.text_color)
            # Put the grade below the score
            self.level_rect = self.level_image.get_rect()
            self.level_rect.right = self.score_rect.right
            self.level_rect.top = self.score_rect.bottom + 10
        def prep_players(self):
            """ Show how many ships are left """
            self.players = Group()
            for player_number in range(self.settings.player_limit):
                player = Player(self.settings, self.screen)
     
                # Scale ball size and assign position
                player.scale(self.scaleValue)
                player.rect.x = 10 + player.rect.width * player_number * 0.5
                player.rect.y = self.score_rect.top
                self.players.add(player)
        def show_score(self):
            """Show score on screen"""
            self.screen.blit(self.score_image, self.score_rect)
            self.screen.blit(self.high_score_image, self.high_score_rect)
            self.screen.blit(self.level_image, self.level_rect)
            #  Mapping spacecraft
            self.players.draw(self.screen)

     

  8. Create a new file "game_functions.py" to store all business logic functions related to the game (the code has detailed annotation information);
    import sys
    import pygame
    from bullet import Bullet
    from enemy import Enemy
    import file as f
     
    # Event
    def check_events(settings, screen, player, play_button, scoreboard, bullets, fireSound):
        """ Respond to key and mouse events """
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                save_file(settings)
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                check_keydown_events(event, settings, screen, player, scoreboard, bullets, fireSound)
            elif event.type == pygame.KEYUP:
                check_keyup_events(event, player)
            elif event.type == pygame.MOUSEBUTTONDOWN:
                mouse_x, mouse_y = pygame.mouse.get_pos()
                check_play_button(settings, play_button, scoreboard, mouse_x, mouse_y)
    def check_keydown_events(event, settings, screen, player, scoreboard, bullets, fireSound):
        """ Response button """
        if event.key == pygame.K_DOWN:
            player.move_down = True
        elif event.key == pygame.K_UP:
            player.move_up = True
        elif event.key == pygame.K_LEFT:
            player.move_left = True
        elif event.key == pygame.K_RIGHT:
            player.move_right = True
        elif event.key == pygame.K_SPACE:
            fireSound.play()
            # Click the space bar to create a bullet
            fire_bullet(settings, screen, player, bullets)
        elif event.key == pygame.K_p:
            start_game(settings, scoreboard)
        elif event.key == pygame.K_q:
            save_file(settings)
            sys.exit()
    def check_keyup_events(event, player):
        """ Response loosening """
        if event.key == pygame.K_DOWN:
            player.move_down = False
        elif event.key == pygame.K_UP:
            player.move_up = False
        elif event.key == pygame.K_LEFT:
            player.move_left = False
        elif event.key == pygame.K_RIGHT:
            player.move_right = False
    def check_play_button(settings, play_button, scoreboard, mouse_x, mouse_y):
        """Click on the player Play Button to start a new game"""
        button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
        if button_clicked and not settings.game_active:
            start_game(settings, scoreboard)
    def start_game(settings, scoreboard):
        """Start the game"""
        # Reset game settings
        settings.initialize_settings()
        # hide cursor
        pygame.mouse.set_visible(False)
        # Reset game statistics
        settings.reset_stats()        
        settings.game_active = True
        # Reset scoreboard image
        scoreboard.prep_score()
        scoreboard.prep_high_score()
        scoreboard.prep_level()
        scoreboard.prep_players()
    def save_file(settings):
        # Keep files
        obj = {'highScore': settings.high_score}
        f.save_file(obj, settings.filename)
     
    # Enemy airplane
    def update_enemies(settings, screen, scoreboard, enemies, enemies_down, enemy_down_imgs, player, bullets, explosiveSound):  
        # To generate enemy aircraft, you need to control the generation frequency
        if settings.enemy_frequency % settings.enemy_frequency_space == 0:        
            enemy1 = Enemy(enemy_down_imgs, settings)
            enemies.add(enemy1)
        settings.enemy_frequency += 1
        if settings.enemy_frequency >= 100:
            settings.enemy_frequency = 0
        for enemy in enemies:
            # Mobile enemy aircraft
            enemy.move()
            # Collision effect processing between enemy aircraft and player aircraft circle detection between two elves
            if pygame.sprite.collide_circle(enemy, player):
                enemies_down.add(enemy)
                enemies.remove(enemy)
                settings.player_limit -= 1
                scoreboard.prep_players()
                break
            # Delete the aircraft after moving out of the screen
            if enemy.rect.top < 0:
                enemies.remove(enemy)
        # How to deal with the effect of enemy aircraft being hit by bullets
        # Add the hit enemy object to the destroy enemy Group to render the destroy animation
        # The method groupcollide() is used to detect the rectangular conflicts between two sprites in the sprite group
        enemies1_down = pygame.sprite.groupcollide(enemies, bullets, True, True)
        if enemies1_down:
            explosiveSound.play()
            # Calculate fractions and render
            for enemys in enemies1_down.values():
                settings.score += settings.one_points * len(enemys)
                scoreboard.prep_score()
            # Render top score
            check_high_score(settings, scoreboard)
            # Wait until you reach the level number to upgrade and render the new level
            settings.level_number -= 1
    
            if settings.level_number == 0:
                settings.increase_speed()
                settings.level += 1
                scoreboard.prep_level()
                # Revert to 4 (same as settings)
                settings.level_number = 10
                # Speed up the generation of enemy aircraft            
                if settings.enemy_frequency_space > 10:
                    settings.enemy_frequency_space -= 10
        # Collision enemy aircraft returned by traversing key value
        for enemy_down in enemies1_down:
            # Click the destroyed enemy aircraft to the list
            enemies_down.add(enemy_down)
        # Display of the effect of enemy aircraft being hit by bullets
        for enemy_down in enemies_down:
            if enemy_down.down_index == 0:
                pass
            if enemy_down.down_index > 7:
                enemies_down.remove(enemy_down)
                continue
            #Show clash picture
            screen.blit(enemy_down.down_imgs[enemy_down.down_index // 2], enemy_down.rect)
            enemy_down.down_index += 1
        # Display Wizard
        enemies.draw(screen)    
     
    # Bullet
    def fire_bullet(settings, screen, player, bullets):
        """Create a bullet"""
        new_bullet = Bullet(settings, screen, player)
        bullets.add(new_bullet)
    def update_bullets(screen, bullets):
        """Update the location of bullets and delete the disappeared bullets"""
        # Update bullet position
        bullets.update()
     
        # Delete the lost bullets and update the ship's life at the same time
        for bullet in bullets.copy():
            if bullet.rect.top < screen.get_rect().top:
                bullets.remove(bullet)
     
    # Fraction
    def check_high_score(settings, scoreboard):
        """Check to see if a new top score has been born"""
        if settings.score > settings.high_score:
            settings.high_score = settings.score
            scoreboard.prep_high_score()
     
    # screen
    def update_screen(settings, screen, player, play_button, scoreboard, enemies, bullets):
        """ Update the image on the screen and switch to the new screen """
        # Draw spacecraft to screen
        player.draw_player()
        # Draw bullets to screen 
        for bullet in bullets.sprites():
            bullet.draw_bullet()
        # Render scoreboard information
        scoreboard.show_score()
        # 
        if settings.player_limit == 0:
            settings.game_active = False
            settings.reset_stats()
            # Empty rectangle list and bullet list
            enemies.empty()
            bullets.empty()
    
            screen_rect = screen.get_rect()
            player.rect.centerx = screen_rect.centerx
            player.rect.bottom = screen_rect.bottom
        
        # If the game is inactive, draw the Play button
        if not settings.game_active:
            play_button.draw_button()
        # Make the most recently drawn screen visible
        pygame.display.flip()

     

  9. The main function is used to initialize the program and update the information of the program synchronously;
    import pygame
    from pygame.sprite import Group
    from settings import Settings
    from button import Button
    from player import Player
    import game_functions as gf
    from scoreboard import Scoreboard
     
    def run_game():
        pygame.init()
        # Initialize all audio and load blast music
        pygame.mixer.init()
            # Waiting for 1s
        pygame.time.delay(1000)
        pygame.mixer.music.load('file/bgsound.mp3')
            # -1 for infinite loop (background music)
        pygame.mixer.music.play(-1)
            # Explosions
        explosiveSound = pygame.mixer.Sound('file/explosiveSound.wav')
            # Shot
        fireSound = pygame.mixer.Sound('file/fireSound.wav')
        # Game cycle frame rate setting
        clock = pygame.time.Clock()
     
        settings = Settings()
        screen = pygame.display.set_mode((settings.screen_width, settings.screen_height))
        # Full screen display
        # screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        pygame.display.set_caption('Aircraft Wars')
        # Top left Icon
        ic_launcher = pygame.image.load('images/ic_launcher.png').convert_alpha()
        pygame.display.set_icon(ic_launcher)
        # Background map
        background = pygame.image.load('images/background.png').convert_alpha()
    
        # Enemy aircraft pictures
        enemy_img1= pygame.image.load('images/enemy1.png')
        enemy_img2= pygame.image.load('images/enemy2.png')
        enemy_img3= pygame.image.load('images/enemy3.png')
        enemy_img4= pygame.image.load('images/enemy4.png')
        # A list of pictures of enemy aircraft in different states. Multiple pictures are displayed as animation effects
        enemy_down_imgs = []
        enemy_down_imgs.append(enemy_img1)
        enemy_down_imgs.append(enemy_img2)
        enemy_down_imgs.append(enemy_img3)
        enemy_down_imgs.append(enemy_img4)
        # Enemy aircraft storage
        enemies = Group()
        # Store destroyed aircraft for rendering destroyed animation
        enemies_down = Group()    
    
        # Create Play button
        play_button = Button(screen, 'Play')
     
        # Create spaceship
        player = Player(settings, screen)
        # Create bullet groups
        bullets = Group()
        # Create scoreboard
        scoreboard = Scoreboard(settings, screen)
     
        while True:
            # Drawing background
            screen.blit(background, (0, 0))
            # Control the maximum frequency of the game
            clock.tick(60)
    
            # Check player input (if not added, it will be loaded all the time)
            gf.check_events(settings, screen, player, play_button, scoreboard, bullets, fireSound)
            if settings.game_active:
                # Update ship position
                player.update()
                # Update enemy planes
                gf.update_enemies(settings, screen, scoreboard, enemies, enemies_down, enemy_down_imgs, player, bullets, explosiveSound)
                # Update bullet position
                gf.update_bullets(screen, bullets)
            # Update screen information
            gf.update_screen(settings, screen, player, play_button, scoreboard, enemies, bullets)
     
    run_game(), 

     

  10. In the directory path of the file shootingenemy.py, execute the command "python shootingenemy.py" pop-up window to operate and play.

epilogue

The game includes background music, shooting sound, explosion sound and explosion effect of bullets hitting enemy aircraft, life number, score, level, maximum score, start button and other elements. You can also add other fun elements by yourself.

32 original articles published, 20 praised, 10000 visitors+
Private letter follow

Topics: Python Mobile Windows Attribute