Reference link: Logic gate in Python
introduction
The python language has been on fire recently. In addition to its usefulness in the field of scientific computing, python also shines in games and backends. This blog post will teach you how to write a python game in accordance with the formal project development process. The project comes from "Python programming from entry to practice" (this article will modify and improve some of the errors in the original project, PS: I strongly recommend this book, it is really good), to feel the interesting points. The game developed this time is called alien invasion.
Install pygame and create a spaceship that can move left and right
Install pygame
My computer is windows 10, python3.6, pygame download address: Portal Please download the corresponding python version of pygame and run the following command
$ pip install wheel
$ pip install pygame‑1.9.3‑cp36‑cp36m‑win_amd64.whl
Create Pygame window and respond to user input
Create a new folder alien_invasion, and create a new alien_invasion.py file in the folder, enter the following code.
import sys
import pygame
def run_game():
#initialize game and create a dispaly object
pygame.init()
screen = pygame.display.set_mode((1200,800))
pygame.display.set_caption("Alien Invasion")
# set backgroud color
bg_color = (230,230,230)
# game loop
while True:
# supervise keyboard and mouse item
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# fill color
screen.fill(bg_color)
# visualiaze the window
pygame.display.flip()
run_game()
Running the above code, we can get a window with a gray interface:
$ python alien_invasion.py
Create settings class
In order to easily create some new functions in the process of writing the game, an additional settings module is written below, which contains a Settings class to store all settings in one place. This makes it easier to modify the appearance of the game when the project increases in the future. We first modify the screen size and screen color in alien_invasion.py. First, create a new python file settings.py under the alien_invasion folder, and add the following code to it:
class Settings(object):
"""docstring for Settings"""
def init(self):
# initialize setting of game
# screen setting
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230,230,230)
Then import the Settings class in alien_invasion.py, and use the related settings, modify as follows:
import sys
import pygame
from settings import Settings
def run_game():
#initialize game and create a dispaly object
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
# set backgroud color
bg_color = (230,230,230)
# game loop
while True:
# supervise keyboard and mouse item
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# fill color
screen.fill(ai_settings.bg_color)
# visualiaze the window
pygame.display.flip()
run_game()
Add spaceship image
Next, we need to add the spaceship to the game. To draw the player's ship on the screen, we will load an image and draw it using the Pygame() method blit(). Almost all types of image files can be used in the game, but the use of bitmap (.bmp) files is the easiest, because Pygame loads bitmaps by default. Although other types of images can be loaded, additional libraries need to be installed. We recommend looking for images on a free photo material website: Portal. We create a new folder called images in the main project folder (alien_invasion), and put the following bmp pictures into it. Next, we create the ship class ship.py:
import pygame
class Ship():
def init(self,screen):
#initialize spaceship and its location
self.screen = screen
# load bmp image and get rectangle
self.image = pygame.image.load('image/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
#put spaceship on the bottom of window
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
def blitme(self):
#buld the spaceship at the specific location
self.screen.blit(self.image,self.rect)
Finally, we draw the spaceship on the screen, that is, call the blitme method in the alien_invasion.py file:
import sys
import pygame
from settings import Settings
from ship import Settings
def run_game():
#initialize game and create a dispaly object
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
ship = Ship(screen)
pygame.display.set_caption("Alien Invasion")
# set backgroud color
bg_color = (230,230,230)
# game loop
while True:
# supervise keyboard and mouse item
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# fill color
screen.fill(ai_settings.bg_color)
ship.blitme()
# visualiaze the window
pygame.display.flip()
run_game()
Refactoring: module game_functions
In large projects, it is often necessary to refactor existing code before adding new code. The purpose of refactoring is to simplify the structure of the code and make it easier to extend. We will implement a game_functions module, which will store a large number of functions that allow the game Alien invasion to run. By creating the module game_functions, alien_invasion.py can be avoided from being too long and its logic easier to understand.
Function check_events()
First, we move the code that manages events to a function called check_events(), the purpose is to isolate the event loop
import sys
import pygame
def check_events():
#respond to keyboard and mouse item
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
Then we modify the alien_invasion.py code, import the game_functions module, and replace the event loop with a call to the function check_events():
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#initialize game and create a dispaly object
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
ship = Ship(screen)
pygame.display.set_caption("Alien Invasion")
# set backgroud color
bg_color = (230,230,230)
# game loop
while True:
# supervise keyboard and mouse item
gf.check_events()
# fill color
screen.fill(ai_settings.bg_color)
ship.blitme()
# visualiaze the window
pygame.display.flip()
run_game()
Function update_screen()
Move the code for updating the screen to a function named update_screen(), and put this function in the module game_functions:
def update_screen(ai_settings,screen,ship):
# fill color
screen.fill(ai_settings.bg_color)
ship.blitme()
# visualiaze the window
pygame.display.flip()
The alien_invasion is modified as follows:
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#initialize game and create a dispaly object
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
ship = Ship(screen)
pygame.display.set_caption("Alien Invasion")
# set backgroud color
bg_color = (230,230,230)
# game loop
while True:
# supervise keyboard and mouse item
gf.check_events()
gf.update_screen(ai_settings,screen,ship)
run_game()
From the above set of processes, we found that: in the actual development process, we initially wrote the code as simple as possible, and refactored as the project became more and more complex. Next we begin to deal with the dynamic aspects of the game.
Pilot a spaceship
What we want to achieve here is to enable the player to control the left and right movement of the spaceship through the left and right arrow keys.
Respond to the button
Because in pygame, every keypress is registered as a KEYDOWN event. In check_events(), we need to further determine which keypress is after detecting the KEYDOWN event through event.type. code show as below:
def check_events(ship):
#respond to keyboard and mouse item
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
#move right
ship.rect.centerx +=1
Allow constant movement
When the player presses the right arrow and does not move, we want the spacecraft to move continuously until the player releases it. Here we judge by the KETUO event. Therefore, we set a moving_right flag to achieve continuous movement. The principle is as follows:
When the spacecraft is not moving, the moving_right flag will be false. When the player presses the right arrow, we set this flag to True; when the player releases it, we reset the flag to False.
This moving attribute is a kind of spaceship attribute, we use the ship class to control, so we add an attribute name to this class, moving_right, and an update() method to check the status of the moving_right flag. ship
self.moving_right = False
def update(self):
if self.moving_right:
self.rect.centerx +=1
game_functions
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
#move right
ship.moving_right = True
elif event.type == pygame.KEYUP:
if event.key = pygame.K_RIGHT:
ship.moving_right = False
Finally, call the update() method in alien_invasion
while True:
# supervise keyboard and mouse item
gf.check_events(ship)
ship.update()
Move left and right
We moved to the right before, and then moved to the left. The logic is similar, and the code is not posted.
Adjust the speed of the spacecraft
Currently, each time the while loop is executed, the spaceship moves at most one pixel. We can add ship_speed_factor to Settings to control the speed of the spacecraft. We will determine how much distance the spaceship can move at each cycle based on this attribute. Settings:
class Settings(object):
"""docstring for Settings"""
def init(self):
# initialize setting of game
# screen setting
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230,230,230)
self.ship_speed_factor = 1.5
Ship:
class Ship():
def init(self,ai_settings,screen):
#initialize spaceship and its location
self.screen = screen
self.ai_settings = ai_settings
Limit the range of spacecraft
If the player presses the arrow for too long, the spaceship will disappear, so how to stop the spaceship when it reaches the edge of the screen? Here we only need to modify the update method in the Ship class to add a logical judgment.
Refactor
Here we mainly talk about the refactoring of the check_events() function, dividing part of the code into two parts, one for processing KEYDOWN events, and the other for processing KEYUP events. game_functions:
def check_keydown_events(event,ship):
if event.key == pygame.K_RIGHT:
#move right
ship.moving_right = True
elif event.key == pygame.K_LEFT:
#move right
ship.moving_left = True
def check_keyup_events(event,ship):
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
#move right
ship.moving_left = False
def check_events(ship):
#respond to keyboard and mouse item
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event,ship)
elif event.type == pygame.KEYUP:
check_keyup_events(event,ship)
shooting
Next, add a shooting function, so that when the player presses the space bar, a bullet will be fired. The bullet will travel up the screen and disappear when it reaches the screen.
Add bullet settings
Add some bullet properties to the Settings class. Here we create a dark gray bullet with a width of 3 pixels and a height of 15 pixels. The speed of the bullet is slightly lower than that of the spacecraft.
Create the Bullet class
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
"""A class to manage bullets fired from the ship."""
def init(self, ai_settings, screen, ship):
"""Create a bullet object, at the ship's current position."""
super().init()
self.screen = screen
# Create bullet rect at (0, 0), then set correct position.
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
# Store a decimal value for the bullet's position.
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
"""Move the bullet up the screen."""
# Update the decimal position of the bullet.
self.y -= self.speed_factor
# Update the rect position.
self.rect.y = self.y
def draw_bullet(self):
"""Draw the bullet to the screen."""
pygame.draw.rect(self.screen, self.color, self.rect)
Store bullets in group
After defining the Bullet class and the necessary settings above, you can write the code to fire a bullet every time the player presses the space bar. First, we create a group in alien_invasion to store all valid bullets.
def run_game():
#initialize game and create a dispaly object
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
ship = Ship(ai_settings,screen)
bullets = Group()
pygame.display.set_caption("Alien Invasion")
# set backgroud color
bg_color = (230,230,230)
# game loop
while True:
# supervise keyboard and mouse item
gf.check_events(ai_settings, screen, ship,bullets)
ship.update()
bullets.update()
gf.update_screen(ai_settings, screen, ship,bullets)
Fire
Here we modify the check_keydown_events() function to monitor the event of the player pressing the space bar. Here we need to modify the update_screen() function to ensure that every bullet can be redrawn every time the screen is updated. Let's look at the effect:
Delete the missing bullet
Delete the missing bullets in alien_invasion.
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
def run_game():
#initialize game and create a dispaly object
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
ship = Ship(ai_settings,screen)
bullets = Group()
pygame.display.set_caption("Alien Invasion")
# set backgroud color
bg_color = (230,230,230)
# game loop
while True:
# supervise keyboard and mouse item
gf.check_events(ai_settings, screen, ship,bullets)
ship.update()
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom <=0:
bullets.remove(bullet)
gf.update_screen(ai_settings, screen,ship,bullets)
run_game()
Limit the number of bullets
In order to encourage players to shoot with targets, we stipulate that only 3 bullets can exist on the screen at the same time. We only need to check whether the number of bullets that have not disappeared is less than 3 before creating a bullet.
Create update_bullets() function
In order to make the code in alien_invasion easier, we will check the bullet management code and move it to the game_functions module:
def update_bullets(bullets):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom<=0:
bullets.remove(bullet)
Create fire_bullet() function
Here we move the code that fires the bullet into a separate function:
def fire_bullet(ai_settings,screen,ship,bullets):
if len(bullets) < ai_settings.bullets_allowed:
new_bullet = Bullet(ai_settings,screen,ship)
bullets.add(new_bullet)
Add aliens and detect collisions
Before we complete the new task, we first add a shortcut key Q to end the game:
Create the first alien
Here is the same method as creating a spaceship
class Alien(Sprite):
"""A class to represent a single alien in the fleet."""
def init(self, ai_settings, screen):
"""Initialize the alien, and set its starting position."""
super().init()
self.screen = screen
self.ai_settings = ai_settings
# Load the alien image, and set its rect attribute.
self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect()
# Start each new alien near the top left of the screen.
self.rect.x = self.rect.width
self.rect.y = self.rect.height
# Store the alien's exact position.
self.x = float(self.rect.x)
def blitme(self):
"""Draw the alien at its current location."""
self.screen.blit(self.image, self.rect)
Create a group of aliens
Here we first determine how many aliens can fit in a line and how many lines to draw. There are many changes to the code here, just look at the effect:
Mobile alien
Previously we created static aliens, and now we need to make aliens move. Here we set the speed of alien movement in the Settings class, and then move through the update method in the Alien class
Shoot aliens
If you want to shoot aliens, you must first detect whether there is a collision between two group members. In the game, collision is the overlapping of game elements. Here we use sprite.groupcollide() to detect the collision between the members of two groups. When a bullet hits an alien, it needs to be known immediately, and at the same time the alien that was collided will disappear immediately, so we need to detect the collision immediately after updating the position of the bullet.
End Game
Here we also need to know when to end the game, there are several situations:
The spacecraft is completely destroyed and the aliens reach the bottom of the screen
actual effect:
Scoring
Finally, we will add a Play button to the game to start the game as needed and restart the game after the game is over. We will also implement a scoring system that will speed up the pace as the player level increases.
Add Play button
Here we can initialize the game to inactive state first, when we click the button, the game will start. Because there is no built-in method for creating buttons in Pygame. So we can create a solid rectangle with its own label by creating a Button class. We determine whether a click event has occurred by detecting whether the coordinates after the mouse click collides with the button we draw.
Level up
In order to make the game more difficult and interesting after the player eliminates the enemy, we can modify it in the Settings class to increase the static initial value and the dynamic initial value.
Scoring, level, remaining ships
Packaged into exe executable file
The above game is developed, then you need to convert it into an exe executable file. We use pyinstaller, installation steps reference: portal
Project code
github address: portal
Recommended Posts