Python actual combat [Alien Invasion] game and adapted it into [Messi vs Ronaldo] (fans live) – build environment, source code, read the highest score and generate executable .exe file

Please add image description

Article directory

  • Preface
  • Install Pygame
  • Game implementation
    • Read, write and store the highest score in [Alien Invasion] game
    • Game source code
      • alien_invasion.py
      • game_functions.py
      • ship.py
      • alien.py
      • bullet.py
      • button.py
      • scoreboard.py
      • game_stats.py
      • settings.py
      • .bmp type files for spaceships and aliens
  • Organize game programs into .exe files
      • Step 1: Install the Pyinstaller library in pycharm
      • Step 2: Generate .exe executable program
      • error handling
  • Change [Alien Invasion] to [Messi vs Ronaldo] and other interesting adaptation methods

Foreword

This article will introduce the environment installation of the python game [Alien Invasion] code. will introduce in detail how to write the highest score of the game into a file and read and generate .exe at the next startup. Executable file, how to change the game interestingly. All the source code related to the game has been in the Game Implementation----Game Source Code section of the article.

game introduction:

The player controls a spaceship that appears at the bottom of the screen. Use the left and right keys to move the spacecraft left and right, and use the space bar to fire bullets. The player’s task is to shoot down every alien that moves down from the top of the screen. When the alien The spaceship is destroyed when a person touches the spaceship or the bottom of the screen. Each player can own a spaceship. When all three spaceships are destroyed, the game ends and the highest score is obtained.

Since I can’t upload a video, I’ll show you the game picture effect.
There are three backup spaceships. The number in the middle is the highest score, which will be loaded every time you open the game. The top number on the right is the current score, and the number below is the current level.

Install Pygame

First, use pip to install Pygame (most of the currently downloaded compilers come with pip. If it is an older version, you can search for related installation methods, which is not difficult). Since the Python compiler is installed During the process, most people didn’t actually know python at that time. Then when installing Pygame, they found that the path to the compiler was different or could not be found, and the terminal commands were useless, which was very difficult. So we use Pycharm directly to install Pygame. At this time, the advantages of Pycharm are reflected. For this kind of installation, it is more reliable to watch video tutorials. I recommend a short and very useful installation video to everyone.
I used method 2.1 to install Pygame, and it worked in my own test.

Game implementation

Since there are many tutorials on the [Alien Invasion] mini-game on the Internet, I won’t go into details about the principles. What I explain is not necessarily better than others. The code will be given directly after this module. It mainly explains how to the game. The highest score obtained is written to a file and read the next time the game is run.

Read, write and store [Alien Invasion] game high scores

This project contains multiple python files. If you want to write the highest score to a file, you need to create an additional blank .pkl file file in the folder under this project. This file is responsible for reading, writing and playing games. The highest score obtained at the time. To achieve reading, the pickel module needs to be imported into the python program that reads and writes the highest score file. Each time it is detected that the game is about to exit, the current highest score is saved.

The circled part is the code that needs to be added to the python file that mainly performs reading and writing of the highest score. At the same time, don’t forget to create a blank .pkl file in the folder, otherwise an error will be reported. FileNotFoundError: [Errno 2] No such file or directory: 'high_score.pkl' zheyEveryone must pay attention to this.
The picture below shows the .pkl file added to the project file. The name of this file must be the same as the file name used to read and write files in the code.

In the Recognize click on the wrong number and exit part of the code, a function that saves the highest score must also be called save_high_score()

In this way, it is perfectly possible to save the highest score into the file and read the highest score the next time the game is run.
Reference blog: Python – Pygame implements Alien Invasion using the pickle class to save the highest score locally. This blog is quite clear, but because it does not mention that a .pkl file must be created, many people will make mistakes here.

Game source code

alien_invasion.py

import pygame
from settings import Settings #Import appearance settings class
from ship import Ship
from alien import alien
import game_functions as gf # as gf is the designated alias for convenience
from pygame.sprite import Group
from game_stats import GameStates
from button import Button
from scoreboard import Scoreboard

def run_game():
    pygame.init()
    #Create an instance of the Settings class to access and modify the contents of the Settings class
    ai_settings = Settings()
    #Create a display window named screen, and the following parameters are to set the screen properties in the class
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    ship = Ship(ai_settings, screen)
    pygame.display.set_caption("Alien invasion")
    # create play button
    play_button = Button(ai_settings, screen, "Play")
    stats = GameStates(ai_settings)
    sb = Scoreboard(ai_settings, screen, stats)
    bullets = Group()
    aliens = Group()
    gf.create_fleet(ai_settings, screen, ship, aliens)
    # Start the main game loop
    while True:
        gf.check_events(ai_settings,screen,stats,play_button,ship,aliens,bullets,sb)
        if stats. game_active:
            #Redraw (update the bullets and spaceships on the screen)
            ship. update()
            gf.update_bullets(ai_settings, screen, stats,sb,ship, aliens, bullets)
            gf.update_aliens(ai_settings, ship, aliens, stats, screen, bullets,sb)
        gf.update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button)
run_game()

game_functions.py

import sys
import pygame
from bullet import Bullet
from alien import alien
from time import sleep


def check_keydown_events(event, ai_settings, screen, ship, bullets):
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        fire_bullet(ai_settings, screen, ship, bullets)


def check_keyup_events(event, ship):
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
    elif event.key == pygame.K_q:
        sys. exit()


def check_events(ai_settings, screen, stats, play_button, ship, aliens, bullets, sb):
    for event in pygame.event.get():
        # When the user clicks on the wrong number, it will be recognized and exit the game (exit the program)
        if event.type == pygame.QUIT:
            stats. save_high_score()
            sys. exit()
        # Press the arrow key to trigger the KEYDOWN event
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event, ai_settings, screen, ship, bullets)
        # Release the arrow key to trigger the KEYUP event
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, ship)
        elif event.type==pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y, sb)
def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y, sb ):
    button_clicked=play_button.rect.collidepoint(mouse_x,mouse_y)
    if button_clicked and not stats. game_active:
        # reset game settings
        ai_settings.initialize_dynamic_settings()
        # hide cursor
        pygame.mouse.set_visible(False)
        # reset game stats
        stats. reset_stats()
        stats.game_active=True
        # Clear the alien list and bullet list
        sb. prep_score()
        sb.prep_high_score()
        sb. prep_level()
        sb. prep_ships()
        aliens. empty()
        bullets.empty()
        #Create a group of new aliens and center the spaceship
        create_fleet(ai_settings,screen,ship,aliens)
        ship.center_ship()



def update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button):
    # Refresh the screen every time the loop finishes, and fill the screen with the background color
    screen.fill(ai_settings.bg_color)
    # Redraw bullets behind spaceships and aliens
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    # Use the blitme method in the Ship class to draw the ship at the bottom
    ship.blitme()
    aliens.draw(screen)
    sb.show_score()
    #If the game is inactive
    if not stats.game_active:
        play_button.draw_button()
    # Make the most recently drawn screen visible
    pygame. display. flip()


def update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets):
    bullets.update()
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets)


def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets):
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
    if collisions:
        stats.score + =ai_settings.alien_points
        sb.prep_score()
        for aliens in collisions.values():
            stats.score + =ai_settings.alien_points*len(aliens)
            sb.prep_score()
        check_high_score(stats, sb)
    # Check if the aliens have been destroyed
    if (len(aliens) == 0):
        bullets.empty()
        ai_settings.increase_speed()
        create_fleet(ai_settings, screen, ship, aliens)
        #increase level
        stats.level + =1
        sb.prep_level()
        create_fleet(ai_settings, screen, ship, aliens)
# check if it is the highest score
def check_high_score(stats, sb):
    if stats.score > stats.high_score:
        stats.high_score = stats.score
        sb.prep_high_score()


def fire_bullet(ai_settings, screen, ship, bullets):
    # If the player presses space, create a bullet instance and add it to the group bullets
    if len(bullets) < ai_settings.bullets_allowed:
        new_bullet = Bullet(ai_settings, screen, ship)
        bullets. add(new_bullet)


def get_number_aliens_x(ai_settings, alien_width):
    available_space_x = ai_settings. screen_width - 2 * alien_width
    number_aliens_x = int(available_space_x / (2 * alien_width))
    return number_aliens_x


def create_alien(ai_setting, screen, aliens, alien_number, row_number):
    alien = Alien(ai_setting, screen)
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * alien_number
    alien.rect.x = alien.x
    alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
    aliens. add(alien)


def create_fleet(ai_settings, screen, ship, aliens):
    alien = Alien(ai_settings, screen)
    number_aliens_x = get_number_aliens_x(ai_settings, alien. rect. width)
    number_rows = get_number_rows(ai_settings, ship.rect.height,
                                  alien.rect.height)
    for row_number in range(number_rows):
        for alien_number in range(number_aliens_x):
            create_alien(ai_settings, screen, aliens, alien_number, row_number)


# Count how many rows aliens have
def get_number_rows(ai_settings, ship_height, alien_height):
    available_space_y = (ai_settings.screen_height -
                         (3 * alien_height) - ship_height)
    number_rows = int(available_space_y / (2 * alien_height))
    return number_rows


def check_fleet_edges(ai_seetings, aliens):
    for alien in aliens. sprites():
        if alien.check_edges():
            change_fleet_direction(ai_seetings, aliens)
            break


# Move the overall aliens down, and change their orientation
def change_fleet_direction(ai_seetings, aliens):
    for alien in aliens. sprites():
        alien.rect.y += ai_seetings.fleet_drop_speed
    ai_seetings.fleet_direction *= -1


# Check if any aliens are at the edge of the screen and update the position of the entire group of aliens
def update_aliens(ai_settings, ship, aliens, stats, screen, bullets,sb):
    check_fleet_edges(ai_settings, aliens)
    aliens. update()
    if pygame.sprite.spritecollideany(ship, aliens):
        ship_hit(ai_settings, stats, screen, ship, aliens, bullets,sb)
    check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets,sb)


def ship_hit(ai_settings, stats, screen, ship, aliens, bullets,sb):
    if stats.ships_left > 0:
        # Corresponding to the flying being hit by the alien, reduce ship_left by 1
        stats.ships_left -= 1
        sb. prep_ships()
        # Empty bullets and aliens
        aliens. empty()
        bullets. empty()
        #Create a new group of aliens and place the ship in the bottom center of the screen
        create_fleet(ai_settings, screen, ship, aliens)
        ship. center_ship()
        # pause
        sleep(0.5)
    else:
        stats.game_active = False
        pygame.mouse.set_visible(True)


def check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets,sb):
    # Check if any aliens have reached the bottom of the screen
    screen_rect = screen. get_rect()
    for alien in aliens. sprites():
        if alien.rect.bottom >= screen_rect.bottom:
            # The same method as the spaceship is hit
            ship_hit(ai_settings, stats, screen, ship, aliens, bullets,sb)
            break

ship.py

import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
    def __init__(self, ai_settings, screen):
        super(Ship, self).__init__()
        self.screen=screen
        self.ai_settings = ai_settings
        self.image=pygame.image.load('ship.bmp') #Load images in the same path
        self.rect = self.image.get_rect()
        self.screen_rect=screen.get_rect() #Get the outer rectangle of the spacecraft image
        # Place the new spaceship at the bottom center of the screen
        self.rect.centerx=self.screen_rect.centerx
        self.rect.bottom=self.screen_rect.bottom
        self. center = float(self. rect. centerx)
        self.moving_right=False
        self.moving_left = False
    def update(self):
        # Move the spacecraft left and right
        if self.moving_right and self.rect.right<self.screen_rect.right:
            self.center + =self.ai_settings.ship_speed_factor
        if self.moving_left and self.rect.left>0:
            self.center-=self.ai_settings.ship_speed_factor

        self.rect.centerx=self.center

    def blitme(self):
        self. screen. blit(self. image, self. rect)
    def center_ship(self):
        self.center=self.screen_rect.centerx

alien.py

import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
    def __init__(self, ai_settings, screen):
        super(Alien, self).__init__()
        self.ai_settings = ai_settings
        self.screen=screen
        self.image = pygame.image.load('alien.bmp')
        self.rect = self.image.get_rect()
        self.rect.x=self.rect.width
        self.rect.y = self.rect.height
        self.x = float(self.rect.x)
    def blitme(self):
        self. screen. blit(self. image, self. rect)
    def update(self):
        #Move the alien left or right (reverse movement after hitting the wall)
        self.x + =(self.ai_settings.alien_speed_factor*
                    self.ai_settings.fleet_direction)
        self.rect.x=self.x
    #If the alien hits the edge of the screen, return True
    def check_edges(self):
        screen_rect=self.screen.get_rect()
        if self.rect.right>=screen_rect.right:
            return True
        elif self.rect.left<=0:
            return True

bullet.py

import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
    def __init__(self, ai_settings, screen, ship):
        super().__init__()
        self.screen=screen
        # Create a bullet representing a rectangle at (0,0)
        self.rect=pygame.Rect(0,0,ai_settings.bullet_width,
                              ai_settings.bullet_height)
        self.rect.centerx=ship.rect.centerx
        self.rect.top=ship.rect.top
        self.y=float(self.rect.y)
        self.color=ai_settings.bullet_color
        self.speed_factor=ai_settings.bullet_speed_factor
    def update(self):
        #Update the decimal value representing the bullet
        self.y-=self.speed_factor
        #Update the rect position of the bullet
        self.rect.y=self.y
    def draw_bullet(self):
        # draw the bullet on the screen
        pygame.draw.rect(self.screen,self.color,self.rect)

button.py

import pygame.font
classButton():
    def __init__(self, ai_settings, screen, msg):
        self.screen=screen
        self.screen_rect=screen.get_rect()
        #Set the size and other properties of the button
        self.width,self.height=200,50
        self.button_color=(0,255,0)
        self.text_color=(255,255,255)
        self.font=pygame.font.SysFont(None,48)
        #Create the rect object of the button and center it
        self.rect=pygame.Rect(0,0,self.width,self.height)
        self.rect.center=self.screen_rect.center
        #Button labels only need to be created once
        self.prep_msg(msg)
    def prep_msg(self,msg):
        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):
        self.screen.fill(self.button_color,self.rect)
        self.screen.blit(self.msg_image,self.msg_image_rect)

scoreboard.py

import pygame.ftfont
from ship import Ship
from pygame.sprite import Group
class Scoreboard():
    def __init__(self,ai_settings,screen,stats):
        self.screen=screen
        self.screen_rect=screen.get_rect()
        self.ai_settings=ai_settings
        self.stats=stats
        # Font when displaying scores
        self.text_color=(30,30,30)
        self.font=pygame.font.SysFont("arial",48)
        self.prep_score()
        self.prep_high_score()
        self.prep_level()
        self. prep_ships()
    def prep_score(self):
        rounded_score=int(round(self.stats.score,-1))
        score_str="{:,}".format(rounded_score)
        self.score_image = self.font.render(score_str, True, self.text_color,
                                          self.ai_settings.bg_color)
        self.score_rect=self.score_image.get_rect()
        self.score_rect.right=self.screen_rect.right-20
        self.score_rect.top=20

    def prep_high_score(self):
        high_score=int(round(self.stats.high_score,-1))
        high_score_str = "{:,}".format((high_score))
        self.high_score_image=self.font.render(high_score_str,True,
                                               self.text_color, self.ai_settings.bg_color)
        self.high_score_rect=self.high_score_image.get_rect()
        self.high_score_rect.centerx=self.screen_rect.centerx
        self.high_score_rect.top=20
    def prep_level(self):
        self.level_image=self.font.render(str(self.stats.level),True,
                                          self.text_color, self.ai_settings.bg_color)
        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_ships(self):
        self.ships=Group()
        for ship_number in range(self.stats.ships_left):
            ship=Ship(self.ai_settings,self.screen)
            ship.rect.x=10 + ship_number*ship.rect.width
            ship.rect.y=10
            self.ships.add(ship)
    def show_score(self):
        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)
        self.ships.draw(self.screen)

game_stats.py

import pickle
class GameStates():
    def __init__(self, ai_settings):
        self.ai_settings = ai_settings
        self.reset_stats()
        self.game_active=False
        self.high_score=0

    def reset_stats(self):
        #Initialize statistics that may change during the game
        self.ships_left=self.ai_settings.ship_limit
        self.score = 0
        self.level = 1
        self.load_high_score()
    def save_high_score(self):
        f=open("high_score.pkl",'wb')
        pickle.dump(str(self.high_score),f,0)
        f. close()
    def load_high_score(self):
        f=open("high_score.pkl",'rb')
        try:
            str_high_score=pickle.load(f)
            self.high_score=int(str_high_score)
        except EOFError:
            self.high_score=0
        finally:
            f. close()

settings.py

class Settings():
    def __init__(self):
        self.screen_width=1350
        self.screen_height=780
        self.bg_color=(230,230,230)
        #shipsettings
        self.ship_limit=3
        #bullet settings
        self.bullet_width=300
        self.bullet_height=15
            #darkgraybullet
        self.bullet_color=60,60,60
        self.bullets_allowed=4
        # alien settings
        self.fleet_drop_speed=25

        self.speedup_scale=1.1
        #The speed at which alien points increase
        self.score_scale=1.5
        self.initialize_dynamic_settings()
    def initialize_dynamic_settings(self):
        self.ship_speed_factor=1
        self.bullet_speed_factor=3
        self.alien_speed_factor = 0.7
        # fleet_direction is 1 means moving to the right, -1 means moving to the left
        self.fleet_direction = 1
        #score
        self.alien_points=30
    def increase_speed(self):
        self.ship_speed_factor*=self.speedup_scale
        self.bullet_speed_factor*=self.speedup_scale
        self.alien_speed_factor*=self.speedup_scale

        self.alien_points=int(self.alien_points*self.score_scale)

Spaceship and alien .bmp files

Please add a picture description
Please add a picture description

Organize game programs into .exe files

Step 1: Install the Pyinstaller library in pycharm

If there is a Chinese plug-in, open the upper left file – Settings – Project – python interpreter – click the plus sign, search for Pyinstaller, and install it.



At the bottom of pycharm, it will show that the installation is in progress. After the installation is completed, the process will disappear, which means the installation is successful.

Step 2: Generate .exe executable program

Enter pyinstaller -F alien_invasion.py in the pycharm terminal. If your game main program is not alien_invasion.py, you can also use it
pyinstaller -F main program.py form

Hit Enter after typing in the terminal



After this command is run, a dist folder will be generated under the project, which contains an executable program .exe file. This .exe file cannot be run currently. You must also add the files required by the program into dist, such as The bmp map of aliens and spaceships, if you created the file with the highest reading score, add this file to this file.
In this way, the exe program can run normally.

Error handling

Let me first state that not all devices will cause errors. If the above operations are correct and the .exe file crashes, there may be a problem with the font. Change the font in the code from None to a font that comes with the system. Such as "arial"

Then delete all the files generated above and enter pyinstaller -F alien_invasion.py in the terminal again. After generating the dist file, copy the relevant files into the dist file.
If you want to send an executable program to a friend, you need to put all the files mentioned in this module into a folder and compress it into a .zip file. The friend can click the .exe file in the file to run the game. The friend does not need to download anything. compiler.

Change [Alien Invasion] to [Messi vs Ronaldo] and other interesting adaptation methods

I believe that students who have learned about this game will know how to modify it and the effect after modification.
Find a picture of two characters with relatively high quality on the Internet, first cut out and zoom the picture (the size must be about the same size as the pictures of aliens and spaceships), and then use the drawing function of the computer to draw the two pictures together. The picture is converted to .bmp format, and these two pictures are added to the project.
Here I give you two pictures, you can save them directly. If you want to create other characters, you can follow my steps above.
Please add a picture descriptionPlease add a picture description

This can set who is an ‘alien’ and who is a ‘spaceship’, so I set Messi as an alien and Ronaldo as a spaceship (for entertainment only)
If I name one file CR7.bmp and one file name MESSI.bmp
Then replace ship.bmp in the code of the ship.py file with CR7.bmp

Replace alien.bmp in the alien file code with MESSI.bmp

Of course, since the background color of the cutout is white, and the RGB value (230, 230, 230) set in our code is a light gray background color, it looks like the picture is placed on the screen, which is ugly. So we need to change this parameter to (255,255,255). The RGB value (255,255,255) is pure white and can be completely integrated with the background color of the cutout.

Finally, change the name of the game to Messi vs Ronaldo (you don’t need to change it)

In this way, [Messi vs Ronaldo] is ready.