Python+pygame Airplane Wars - Source Code Analysis of the First Edition

Table of contents

1. Source code

2. Source code analysis:

(1) The main structure of the code

1. Reference the required modules

2. Defined classes

3. Define the main() function: the main program

(2) Code analysis harvest


The best way to learn is to learn other people's codes, and I used to like the game Raiden, so I started with Airplane Wars, downloaded the source code and picture materials from the Internet, and uploaded the source code first, and the ownership of the code belongs to the original author .

1. Source code

import pygame
from pygame.locals import *
from sys import exit
import time
import random

#创建子弹类,把子弹的图片转化为图像对象,设定固定的移动速度
class Bullet():
    def __init__(self,bulletfilename,bulletpos):  #定义初始化,参数是图的文件名和位置
        self.bulletimg = pygame.image.load(bulletfilename) #图像
        self.bullet_rect = self.bulletimg.get_rect()#获得rect
        self.bullet_image = self.bulletimg.subsurface(self.bullet_rect) #生成subsurface对象
        self.bullet_rect.midbottom = bulletpos  #设置rect位置
        self.speed = 2 #设置子弹速度
    def move(self):
        self.bullet_rect.top -= self.speed   #子弹的运动是不断的以速度值大小减小

#    创建玩家飞机类,用面向对象的思想来对待
class play_plane_fly():
    def __init__(self,play_image_filename,play_pos):
        self.image = pygame.image.load(play_image_filename)
        self.plane_rect = self.image.get_rect()
        self.play_image = self.image.subsurface(self.plane_rect)
        self.plane_rect.midtop = play_pos
        self.speed = 2
        #子弹是由玩家飞机发射的,所以创建列表,存储子弹对象,使该列表变为该类的属性
        self.bullets = [] #子弹空列表
        self.is_hitted = False #是否被击中

    #生成函数,完成发射子弹动作,同时将每个子弹对象存在列表中
    def shoot(self,bullet_filename):
        bulletobj = Bullet(bullet_filename,self.plane_rect.midtop) #利用Bullet生产
        self.bullets.append(bulletobj) #加入子弹列表

    #定义向上移动方法,当飞机移动到边框位置时,无法移动
    def moveup(self):
        if self.plane_rect.top <= 0:
            self.plane_rect.top = 0
        else:
            self.plane_rect.top -= self.speed

    # 定义向下移动方法,当飞机移动到边框位置时,无法移动
    def movedown(self):
        if self.plane_rect.top >= 700 - self.plane_rect.height:
            self.plane_rect.top = 700 - self.plane_rect.height
        else:
            self.plane_rect.top += self.speed

    #    向右移动,当飞机移动到边框位置时,无法移动
    def moveleft(self):
        if self.plane_rect.left <= -40:
            self.plane_rect.left = -40
        else:
            self.plane_rect.left -= self.speed

    #    向左移动,当飞机移动到边框位置时,无法移动
    def moveright(self):
        if self.plane_rect.left >= 700 - self.plane_rect.width:
            self.plane_rect.left = 700 - self.plane_rect.width
        else:
            self.plane_rect.left += self.speed

#    生成敌机类,设定固定的移动速度
class Enemy():
    def __init__(self,enemyfilename,enemypos):

        self.img = pygame.image.load(enemyfilename)
        self.enemy_rect = self.img.get_rect()
        self.enemy_image = self.img.subsurface(self.enemy_rect)
        self.enemy_rect.midbottom = enemypos
        self.speed = 1

    def move(self):
        self.enemy_rect.bottom += self.speed  #敌机向下运动

clock = pygame.time.Clock()
def main():
    #    初始化文字屏幕
    pygame.font.init()
    #    初始化图像屏幕
    pygame.init()
    #    设定游戏帧
    clock.tick(50)
    #    设定游戏屏幕大小
    screen = pygame.display.set_mode((660, 700))
    #    设定游戏名称
    pygame.display.set_caption('飞机大战')
    #    加载背景图片,生成图像对象
    background = pygame.image.load('image/background.png').convert()
    backgroundsurface = pygame.transform.scale(background,  (660,  700))
    #    加载游戏结束图片,生成图像对象
    gameover = pygame.image.load('image/gameover.png').convert()
    gameoversurface = pygame.transform.scale(gameover,(660,  700))

    playplanefilename = 'image/hero1.png'
    planepos = [330,600]
    player = play_plane_fly(playplanefilename,planepos) #定义play实例

    bulletfilename = 'image/bullet.png'

    # 按频率生成子弹,初始化数字为0
    bullet_frequency = 0

    enemyfilename = 'image/enemy0.png'
    #    按频率生成敌机,初始化数字为0
    enemy_frequency = 0

    # 定义enemys空列表
    enemys = []


    myfont = pygame.font.SysFont("font/Marker Felt.ttf", 40)

    textImage = myfont.render("Score ", True, (0,0,0))
    # 初始化得分为0
    Score = 0
    # 敌机被子弹击中时的动画,将每张图片的图像对象存在列表中
    enenys_down = []
    enemy0_down = pygame.image.load('image/enemy0_down1.png')
    enemy0_down_rect = enemy0_down.get_rect()
    enemydown0 = enemy0_down.subsurface(enemy0_down_rect)
    enenys_down.append(enemydown0)

    enemy1_down = pygame.image.load('image/enemy0_down2.png')
    enemy1_down_rect = enemy1_down.get_rect()
    enemydown1 = enemy1_down.subsurface(enemy1_down_rect)
    enenys_down.append(enemydown1)

    enemy2_down = pygame.image.load('image/enemy0_down3.png')
    enemy2_down_rect = enemy2_down.get_rect()
    enemydown2 = enemy2_down.subsurface(enemy2_down_rect)
    enenys_down.append(enemydown2)

    enemy3_down = pygame.image.load('image/enemy0_down4.png')
    enemy3_down_rect = enemy3_down.get_rect()
    enemydown3 = enemy3_down.subsurface(enemy3_down_rect)
    enenys_down.append(enemydown3)
    #以上存了四组击中后的图片,实现击中后的飞机爆炸

    while True:
        #    动态显示得分
        score = str(Score)
        myscore = pygame.font.SysFont("font/Marker Felt.ttf", 40)
        scoreImage = myscore.render(score, True, (0, 0, 0))
        # 判断事件,防止卡顿或者意外退出
        for event in pygame.event.get():
            if event.type == pygame.QUIT: #退出事件
                pygame.quit()
                exit()

        key_pressed = pygame.key.get_pressed() #接收输入键

        if key_pressed[K_UP] or key_pressed[K_w]:
            player.moveup()
        if key_pressed[K_DOWN] or key_pressed[K_s]:
            player.movedown()
        if key_pressed[K_LEFT] or key_pressed[K_a]:
            player.moveleft()
        if key_pressed[K_RIGHT] or key_pressed[K_d]:
            player.moveright()

        screen.blit(backgroundsurface, (0, 0)) #绑定背景图

        if not player.is_hitted:  #如果游戏对象没有被击中
            #    按频率生成子弹
            # 通过控制30这个数,来控制发射子弹的间隔,循环30次后发射一个子弹
            if bullet_frequency % 30 == 0:
                player.shoot(bulletfilename)
            bullet_frequency += 1
            if bullet_frequency >= 30:
                bullet_frequency = 0
            # print("bullet_frequency is {0}".format(bullet_frequency)) #试验用的,没有实际意义

            #    让子弹动起来
            for i in player.bullets:
                i.move()
                screen.blit(i.bullet_image,i.bullet_rect)
                #    当子弹飞出屏幕,删除子弹对象
                if i.bullet_rect.bottom <= 0:
                    player.bullets.remove(i)  #从列表中删除数据
            #    按频率生成敌机
            #原理同子弹频率一样
            if enemy_frequency % 100 == 0:
                enemypos = [random.randint(30, 630), 0]
                enemyplane = Enemy(enemyfilename, enemypos)
                #将敌机对象添加到列表中
                enemys.append(enemyplane)
            enemy_frequency += 1
            if enemy_frequency >= 100:
                enemy_frequency = 0
            #    让敌机动起来
            for i in enemys:
                i.move()
                screen.blit(i.enemy_image,i.enemy_rect)
                #    当敌机飞出屏幕,删除敌机对象
                if i.enemy_rect.bottom >= 700:
                    enemys.remove(i)
                #    遍历子弹对象,判断子弹是否击中敌机
                for j in player.bullets:
                    #    如果击中,分数增加,同时移除该子弹和敌机对象
                    if pygame.Rect.colliderect(j.bullet_rect,i.enemy_rect):  #运用的是rect对象的检测,测试两个矩形是否重叠
                        Score += 100
                        enemys.remove(i)
                        player.bullets.remove(j)
                        for k in enenys_down:
                            screen.blit(k,i.enemy_rect)
                #    遍历敌机对象,判断玩家是否和敌机相撞
                if pygame.Rect.colliderect(player.plane_rect,i.enemy_rect):
                    #    修改is_hitted的值,跳出该层循环
                    player.is_hitted = True
                    break


            screen.blit(player.play_image,player.plane_rect)
            screen.blit(textImage, (0,0))
            screen.blit(scoreImage, (110, 0))
            pygame.display.update()
        #    玩家退出时显示分数和游戏结束
        else:
            screen.blit(gameoversurface,(0,0))
            screen.blit(textImage, (0, 0))
            screen.blit(scoreImage,  (110, 0))
            pygame.display.update()
            time.sleep(2)
            break

main()

2. Source code analysis:

(1) The main structure of the code

1. Reference the required modules

import pygame
from pygame.locals import *
from sys import exit
import time
import random

2. Defined classes

(1) Bullet()-bullet class

The bullet image and position need to be initialized

Define class method move

(2) play_plane_fly(): Player aircraft class

Need to initialize the aircraft image and position

Define the class method shoot and four aspects of movement

(3) Enemy(): Enemy aircraft

The image and position of the enemy aircraft need to be initialized

Define class method move

3. Define the main() function: the main program

(1) Initialization and settings

# Initialize text screen
pygame.font.init()
# Initialize image screen
pygame.init()
# Set the game frame
clock.tick(50)
# Set the game screen size
screen = pygame.display.set_mode((660, 700))
# Set the game name
pygame.display.set_caption('Airplane War')
# Load the background image and generate an image object
background = pygame.image.load('image/background.png').convert()
backgroundsurface = pygame.transform.scale(background,  (660,  700))
# Load the game over image and generate an image object
gameover = pygame.image.load('image/gameover.png').convert()
gameoversurface = pygame.transform.scale(gameover,(660,  700))
#Set aircraft parameters
playplanefilename = 'image/hero1.png'
planepos = [330,600]
#define aircraft instance
player = play_plane_fly(playplanefilename,planepos) #Define play instance
#Set bullet parameters
bulletfilename = 'image/bullet.png'
# Generate bullets according to the frequency, the initialization number is 0
bullet_frequency = 0
#Set enemy plane parameters
enemyfilename = 'image/enemy0.png'
# Generate enemy planes according to the frequency, the initialization number is 0
enemy_frequency = 0

# define an empty list of enemies
enemys = []

# generate font object
myfont = pygame.font.SysFont("font/Marker Felt.ttf", 40)
# Generate Surface
textImage = myfont.render("Score ", True, (0,0,0))
# Initialize score to 0
Score = 0
# The animation when the enemy plane is hit by a bullet, save the image object of each picture in the list
enenys_down = []
enemy0_down = pygame.image.load('image/enemy0_down1.png')
enemy0_down_rect = enemy0_down.get_rect()
enemydown0 = enemy0_down.subsurface(enemy0_down_rect)
enenys_down.append(enemydown0)
enemy1_down = pygame.image.load('image/enemy0_down2.png')
enemy1_down_rect = enemy1_down.get_rect()
enemydown1 = enemy1_down.subsurface(enemy1_down_rect)
enenys_down.append(enemydown1)
enemy2_down = pygame.image.load('image/enemy0_down3.png')
enemy2_down_rect = enemy2_down.get_rect()
enemydown2 = enemy2_down.subsurface(enemy2_down_rect)
enenys_down.append(enemydown2)
enemy3_down = pygame.image.load('image/enemy0_down4.png')
enemy3_down_rect = enemy3_down.get_rect()
enemydown3 = enemy3_down.subsurface(enemy3_down_rect)
enenys_down.append(enemydown3)
#The above four groups of pictures after hitting are saved to realize the explosion of the plane after hitting

(2) Get events and respond one by one

while True:
    # Dynamically display the score
    score = str(Score)
    myscore = pygame.font.SysFont("font/Marker Felt.ttf", 40)
    scoreImage = myscore.render(score, True, (0, 0, 0))
    # Judge events to prevent stuck or unexpected exit
    for event in pygame.event.get():
        if event.type == pygame.QUIT: #Quit event
            pygame.quit()
            exit()

    key_pressed = pygame.key.get_pressed() #Receive input key

    if key_pressed[K_UP] or key_pressed[K_w]:
        player.moveup()
    if key_pressed[K_DOWN] or key_pressed[K_s]:
        player.movedown()
    if key_pressed[K_LEFT] or key_pressed[K_a]:
        player.moveleft()
    if key_pressed[K_RIGHT] or key_pressed[K_d]:
        player.moveright()

    screen.blit(backgroundsurface, (0, 0)) #Binding background image

    if not player.is_hitted: #If the game object is not hit
        # Generate bullets by frequency
        # Control the interval of firing bullets by controlling the number 30, and fire a bullet after 30 cycles
        if bullet_frequency % 30 == 0:
            player.shoot(bulletfilename)
        bullet_frequency += 1
        if bullet_frequency >= 30:
            bullet_frequency = 0
        

        # make the bullet move
        for i in player.bullets:
            i.move()
            screen.blit(i.bullet_image,i.bullet_rect)
            # When the bullet flies off the screen, delete the bullet object
            if i.bullet_rect.bottom <= 0:
                player.bullets.remove(i) #Remove data from the list
        # Generate enemy planes by frequency
        #The principle is the same as bullet frequency
        if enemy_frequency % 100 == 0:
            enemypos = [random.randint(30, 630), 0]
            enemyplane = Enemy(enemyfilename, enemypos)
            #Add the enemy object to the list
            enemys.append(enemyplane)
        enemy_frequency += 1
        if enemy_frequency >= 100:
            enemy_frequency = 0
        # Make the enemy move
        for i in enemys:
            i.move()
            screen.blit(i.enemy_image,i.enemy_rect)
            # When the enemy plane flies out of the screen, delete the enemy plane object
            if i.enemy_rect.bottom >= 700:
                enemys.remove(i)
            # Traverse the bullet object to determine whether the bullet hits the enemy plane
            for j in player.bullets:
                # If it hits, the score is increased, and both the bullet and the enemy object are removed
                if pygame.Rect.colliderect(j.bullet_rect,i.enemy_rect): 
 #Use the detection of the rect object to test whether the two rectangles overlap
                    Score += 100
                    enemys.remove(i)
                    player.bullets.remove(j)
                    for k in enenys_down:
                        screen.blit(k,i.enemy_rect)
            # Traversing the enemy plane object to determine whether the player has collided with the enemy plane
            if pygame.Rect.colliderect(player.plane_rect,i.enemy_rect):
                # Modify the value of is_hitted to jump out of the layer loop
                player.is_hitted = True
                break


        screen.blit(player.play_image,player.plane_rect)
        screen.blit(textImage, (0,0))
        screen.blit(scoreImage, (110, 0))
        pygame.display.update()
    # Show score and game over when player exits
    else:
        screen.blit(gameoversurface,(0,0))
        screen.blit(textImage, (0, 0))
        screen.blit(scoreImage, (110, 0))
        pygame.display.update()
        time.sleep(2)
        break

illustrate:

① Receive keyboard input

key_pressed = pygame.key.get_pressed() #Receive input key

② Control the firing frequency of bullets and enemy planes

# Control the interval of firing bullets by controlling the number 30, and fire a bullet after 30 cycles
if bullet_frequency % 30 == 0:
    player.shoot(bulletfilename)
bullet_frequency += 1
if bullet_frequency >= 30:
    bullet_frequency = 0

Increase the number by 1 each time the transmission frequency reaches the requirement every 30 times, shoot once

The frequency method of the enemy aircraft is the same

③Collision detection

Realized by collision detection between rects

For example:

if pygame.Rect.colliderect(player.plane_rect,i.enemy_rect):
    # Modify the value of is_hitted to jump out of the layer loop
    player.is_hitted = True
    break

(3) Update and Refresh

.....
screen.blit(player.play_image,player.plane_rect)
screen.blit(textImage, (0,0))
screen.blit(scoreImage, (110, 0))
pygame.display.update()

(2) Code analysis harvest

1. The code makes full use of classes and class methods, which greatly reduces the amount of code and has good reusability.

2. The idea of ​​transmitting frequency control can be used in other occasions.

3. Using the collision detection of the Rect object to realize the collision between the plane, the bullet and the enemy plane, the realization is better

4. Realize the effect of enemy aircraft explosion by switching the enenys_down list, which can be used for reference.

Guess you like

Origin blog.csdn.net/sygoodman/article/details/124361928