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' zhey
Everyone 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
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.
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.