Python实现飞机大战-第二部分(附源码、素材、超详细教程)

飞机大战第二部分

        • 1.前言
        • 2.飞机射击
          • 2.1.添加子弹的相关设置
          • 2.2.创建文件bullet.py
          • 2.3.修改game_functions.py
          • 2.4.修改mian.py
          • 2.5.射击效果
          • 2.6.关于子弹连发
          • 2.6 删除已消失子弹
            • 2.6.1.创建函数delete_bullet()
        • 3.敌方飞机
          • 3.1.生成一个敌机
          • 3.2.生成一行敌机
          • 3.3.重构create_enemys()函数
          • 3.3.生成一屏幕敌机
          • 3.4.敌机移动
        • 4.射杀敌机
        • 5.游戏结束

1.前言

第二部分:飞机射击、子弹、和敌方飞机。

第一部分的实现过程点击下方链接
Python实现飞机大战-第一部分(附源码、素材、超详细教程)

2.飞机射击

实现飞机射击,首先需要有子弹,为了方便后期对子弹的长度、宽度、颜色和速度的改变,需要在settings.py内添加子弹这些信息。紧接着创建一个Bullet类,用来存放子弹的属性和方法。

2.1.添加子弹的相关设置

为了方便设置,在Settings类中添加子弹信息的相关设置,速度、长度、宽度、颜色。

settings.py

class Settings():
    '''游戏设置的类'''
    def __init__(self):
    --跳过其他代码--
		'''子弹设置'''
        # 子弹速度
        self.bullet_speed = 1.5
        # 子弹宽度
        self.bullet_width = 3
        # 子弹高度
        self.bullet_height = 10
        # 子弹颜色
        self.bullet_color = 0, 0, 255

2.2.创建文件bullet.py
import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
    '''控制子弹射击的类'''
    def __init__(self, player_settings, screen, player_plane):
        # super()函数,既可以继承父类的所有属性、方法,又可添加或重写父类的方法、属性。
        super().__init__()
        self.screen = screen
        # 创建矩形
        self.rect = pygame.Rect(0, 0, player_settings.bullet_width, player_settings.bullet_height)
        # 子弹的centerx = 飞机的centerx 目的是让子弹从飞机的top发出
        self.rect.centerx = player_plane.rect.centerx
        self.rect.top = player_plane.rect.top
        # 子弹图像的矩形方框的位置
        self.y = float(self.rect.y)
        # 子弹的速度
        self.bullet_speed = player_settings.bullet_speed
        # 子弹的颜色
        self.bullet_color = player_settings.bullet_color

    def update(self):
        '''子弹自动上移'''
		# 原理是让子弹的矩形图像的y左边每次刷新都减去子弹的速度
        self.y -= self.bullet_speed
        # 更新当前坐标
        self.rect.y = self.y
    def draw_bullet(self):
        '''绘制子弹'''
        pygame.draw.rect(self.screen, self.bullet_color, self.rect)
2.3.修改game_functions.py

用空格键控制飞机发射子弹,需要修改check_keyboard函数,和update_screen函数

--省略部分代码--
from bullet import Bullet


def check_keyboard(players_plane, screen, player_settings, bullets):

	    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        # KEYDOWN检测键盘是否按下
        elif event.type == pygame.KEYDOWN:
      --省略部分代码--
      # 空格是否按下
        elif event.key == pygame.K_SPACE:
            print("空格键按下")
            new_bullet = Bullet(player_settings, screen, players_plane)
            bullets.add(new_bullet)
         --省略部分代码--
def update_screen(player_settings,players_plane, screen, bullets):
	--省略部分代码--
	for bullet in bullets.sprites():
    bullet.draw_bullet()
2.4.修改mian.py
def start_game():
--省略部分代码--
	# 用于存放子弹
	bullets = Group()
	while True:
    '''游戏主循环'''
    # 调用文件game_functions内的check_keyboard函数,是一个响应键鼠的函数
    game_functions.check_keyboard(players_plane, screen, player_settings, bullets)
    players_plane.change_position()
    bullets.update()
    # 调用update_screen函数,更新窗口
    game_functions.update_screen(player_settings, players_plane, screen, bullets)
2.5.射击效果

Python实现飞机大战-第二部分(附源码、素材、超详细教程)_第1张图片

2.6.关于子弹连发

子弹连发的原理其实和飞机连续移动的原理相同。不过效果好像不是那么理想,看一下。
Python实现飞机大战-第二部分(附源码、素材、超详细教程)_第2张图片
简单解释一下,代码一共需要修改五个地方:

  1. 在Plane类中添加一个射击标志。
class Plane():

    '''玩家的飞机的类'''
    def __init__(self, screen, player_settings):
    	--省略部分代码--
    	self.sign_launch = False
  1. 在game_functions.py中添加一个控制射击的方法launch_bullet()。
def launch_bullet(players_plane, screen, player_settings, bullets):
    if  players_plane.sign_launch:
        new_bullet = Bullet(player_settings, screen, players_plane)
        bullets.add(new_bullet)
  1. 空格按下修改射击标志的布尔值为True。
elif event.type == pygame.KEYDOWN:	
	--省略部分代码--
	elif event.key == pygame.K_SPACE:
    	print("空格键按下")
        players_plane.sign_launch = True
  1. 空格松开修改射击标志的布尔值为Flase。
elif event.type == pygame.KEYUP:
	--省略部分代码--
	elif event.key == pygame.K_SPACE:
    	print("空格键松开")
        players_plane.sign_launch = False
  1. 在main.py中调用控制射击的方法launch_bullet()
    while True:
        '''游戏主循环'''
        # 调用文件game_functions内的check_keyboard函数,是一个响应键鼠的函数
        game_functions.check_keyboard(players_plane, screen, player_settings, bullets)
        game_functions.launch_bullet(players_plane, screen, player_settings, bullets)
        players_plane.change_position()
        bullets.update()
        # 调用update_screen函数,更新窗口
        game_functions.update_screen(player_settings, players_plane, screen, bullets)

效果不是太好,小伙伴们有更好的方法,欢迎不吝赐教。

2.6 删除已消失子弹

创建的子弹被存放在Group()当中,当子弹到达屏幕的顶端,实际上子弹依旧存在于Group,只不过是超出屏幕范围无法绘制它们。为了避免计算做这些无用功,就需要把超出屏幕的子弹删除。

2.6.1.创建函数delete_bullet()

game_functions.py中新建一个删除子弹的函数


def delete_bullet(bullets):
    '''删除超出屏幕的子弹'''
    bullets.update()

    for bullet in bullets.copy:
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)

main.py
调用函数delete_bullet()

    while True:
        '''游戏主循环'''
        # 调用文件game_functions内的check_keyboard函数,是一个响应键鼠的函数
        game_functions.check_keyboard(players_plane, screen, player_settings, bullets)
        #game_functions.launch_bullet(players_plane, screen, player_settings, bullets)
        players_plane.change_position()
        
        # 刷新子弹位置,子弹超出屏幕后将其删除。
        game_functions.delete_bullet(bullets)
        
        # 调用update_screen函数,更新窗口
        game_functions.update_screen(player_settings, players_plane, screen, bullets)


start_game()

3.敌方飞机
3.1.生成一个敌机

同样新建一个enemy_plane.py的文件,用于存放敌方飞机的类。

import pygame
from pygame.sprite import Sprite

class Enemy(Sprite):
    '''敌方飞机的类'''

    def __init__(self, screen, player_settings):
        
        super().__init__()
        self.screen = screen
        self.player_settings = player_settings

        # 获取敌方飞机图像、rect属性
        self.image = pygame.image.load('image/enemy1.png')
        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)

然后实例化这个类,其中需要传递参数enemy_plane给update_screen()函数,后面绘制图像时需要用到。
注意:实例化类的时候一定要按顺序传递参数。

main.py

def start_game():
	--省略部分代码--
	# 实例化敌方飞机,
    enemy_plane = Enemy(screen, player_settings)

	while True:
	--省略部分代码--
	# 调用update_screen函数,更新窗口
    	game_functions.update_screen(player_settings, players_plane, screen, bullets, enemy_plane)

因为需要在屏幕上显示敌方飞机的图像,所以需要在game_functions.py中的update_screen()添加代码。

game_functions.py

def update_screen(player_settings,players_plane, screen, bullets, enemy_plane):
    '''更新窗口图像'''
    --省略部分代码--
    # 绘制玩家飞机
    players_plane.blitme()
    # 绘制敌方飞机
    enemy_plane.blitme()
    
    pygame.display.flip()

那么如何生成一行敌机呢

3.2.生成一行敌机

每个敌机都是有宽度、高度的,那就可以计算出一行可以放下几个敌机。

game_functions
首先添加一个生成敌机机群的函数

def create_enemys(player_settinngs, screen, enemys):
    '''创建敌方机群'''
    # 实例化敌机
    enemy = Enemy(screen, player_settinngs)
    # 计算一行可以容下几个敌机
    enemy_width = enemy.rect.width
    available_space_x = player_settinngs.screen_weight - 2 * enemy_width
    number_enemys_x = int(available_space_x / (2 * enemy_width))

    # 创建一行敌机
    for enemy_number in range(number_enemys_x):
        enemy = Enemy(screen, player_settinngs)
        enemy.x = enemy_width + 2 * enemy_width * enemy_number
        enemy.rect.x = enemy.x
        enemys.add(enemy)

修改函数update_screen

def update_screen(player_settings,players_plane, screen, bullets, enemys):
--省略部分代码--
    # 绘制玩家飞机
    players_plane.blitme()
    # 绘制敌方飞机
    #enemy_plane.blitme()
    enemys.draw(screen)
    pygame.display.flip()

main.py

def start_game():
	--省略部分代码--
    # 实例化飞机类,对象为players_plane
    players_plane = Plane(screen, player_settings)
    # 存放子弹
    bullets = Group()
    # 实例化敌方飞机,
    enemy_plane = Enemy(screen, player_settings)
    # 存放敌机
    enemys = Group()
    # 创建敌机群
    game_functions.create_enemys(player_settings, screen, enemys)
    while True:
    	--省略部分代码--
    	# 调用update_screen函数,更新窗口
        game_functions.update_screen(player_settings, players_plane, screen, bullets, enemys)
3.3.重构create_enemys()函数

为了是函数结构更清晰,这里对create_enemys()函数重构,分为三个函数,
create_enemys:重复调用create_enemy,创建一行飞机。

def create_enemys(player_settings, screen, enemys):
    '''创建敌方机群'''
    # 实例化敌机
    enemy = Enemy(screen, player_settings)
    number_enemys_x = get_number_enemys_x(player_settings, enemy.rect.width)
    # 创建一行敌机
    for enemy_number in range(number_enemys_x):
        create_enemy(player_settings, screen, enemys, enemy_number)

create_enemy:创建一个飞机

def create_enemy(player_settings, screen, enemys, enemy_number):
    '''创建一个敌机'''
    enemy = Enemy(screen, player_settings)
    enemy_width = enemy.rect.width
    enemy.x = enemy_width + 2 * enemy_width * enemy_number
    enemy.rect.x = enemy.x
    enemys.add(enemy)

get_number_enemys_x:计算出一行容纳飞机个数

def get_number_enemys_x(player_settings, enemy_width):
    '''计算出每行可生成几个敌机'''
    available_space_x = player_settings.screen_weight - 2 * enemy_width
    number_enemys_x = int(available_space_x / (2 * enemy_width))
    return number_enemys_x
3.3.生成一屏幕敌机

前面生成了一行飞机,原理相同,需要计算出屏幕垂直方向上可以放几行飞机。先创建一个计算垂直方向容纳飞机数的函数。
game_functions

def get_number_enemys_y(player_settings, players_plane_height, enemy_height):
    '''获取屏幕可生成多少行'''
    available_space_y = (player_settings.screen_height - (3 * enemy_height) - players_plane_height)
    number_y = int(available_space_y / (2 * enemy_height))
    return number_y
    
def create_enemy(player_settings, screen, enemys, enemy_number, row_number):
    '''创建一个敌机'''
    enemy = Enemy(screen, player_settings)
    enemy_width = enemy.rect.width
    enemy.x = enemy_width + 2 * enemy_width * enemy_number
    enemy.rect.x = enemy.x
    enemy.rect.y = enemy.rect.height + 2* enemy.rect.height * row_number
    enemys.add(enemy)

def create_enemys(player_settings, screen,  players_plane, enemys):
    '''创建敌方机群'''
    # 实例化敌机
    enemy = Enemy(screen, player_settings)
    number_enemys_x = get_number_enemys_x(player_settings, enemy.rect.width)
    number_rows = get_number_enemys_y(player_settings, players_plane.rect.height, enemy.rect.height)
    # 创建一pingmu敌机
    for row_number in range(number_rows):
        for enemy_number in range(number_enemys_x):
            create_enemy(player_settings, screen, enemys, enemy_number, row_number)

main.py

def start_game():
	--省略部分代码--
	game_functions.create_enemys(player_settings, screen, players_plane,enemys)

运行代码:
Python实现飞机大战-第二部分(附源码、素材、超详细教程)_第3张图片

3.4.敌机移动

main.py

	--省略部分代码--
    while True:
        '''游戏主循环'''
        # 调用文件game_functions内的check_keyboard函数,是一个响应键鼠的函数
        game_functions.check_keyboard(players_plane, screen, player_settings, bullets)
        #game_functions.launch_bullet(players_plane, screen, player_settings, bullets)
        players_plane.change_position()

        # 刷新子弹位置,子弹超出屏幕后将其删除。
        game_functions.delete_bullet(bullets)

        # 敌机移动
        game_functions.update_enemys(player_settings, enemys)

        # 调用update_screen函数,更新窗口
        game_functions.update_screen(player_settings,players_plane, screen, bullets, enemys)

enemy_plane.py

	--省略部分代码--
    def blitme(self):
        '''绘制敌方飞机'''
        self.screen.blit(self.image, self.rect)

    def change_position(self):
        '''敌机位置变化'''
        self.x += (self.player_settings.enemy_change_speed * self.player_settings.fleet_direction)
        self.rect.x = self.x

    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

game_functions

--省略部分代码--
def check_fleet_edges(player_settings, enemys):
    '''敌机触碰边缘响应'''
    for enemy in enemys.sprites():
        if enemy.check_edges():
            change_fleet_direction(player_settings, enemys)
            break
def change_fleet_direction(player_settings, enemys):
    for enemy in enemys.sprites():
        enemy.rect.y += player_settings.fleet_drop_speed
    player_settings.fleet_direction *= -1
def update_enemys(player_settings, enemys):
    '''更新敌机位置'''
    check_fleet_edges(player_settings, enemys)
    enemys.update()

settings.py

        '''敌机设置'''
        # 敌机速度
        self.enemy_change_speed = 1
        self.fleet_drop_speed = 10
        # fleet_direction为1表示向右,为-1表示向左
        self.fleet_direction = 1
4.射杀敌机

main.py

    while True:
        '''游戏主循环'''
        # 调用文件game_functions内的check_keyboard函数,是一个响应键鼠的函数
        game_functions.check_keyboard(players_plane, screen, player_settings, bullets)
        #game_functions.launch_bullet(players_plane, screen, player_settings, bullets)
        players_plane.change_position()

        # 刷新子弹位置,子弹超出屏幕后将其删除。
        game_functions.delete_bullet(player_settings, screen, players_plane, enemys,bullets)

        # 敌机移动
        game_functions.update_enemys(player_settings, enemys)

        # 调用update_screen函数,更新窗口
        game_functions.update_screen(player_settings,players_plane, screen, bullets, enemys)

game_functions

def delete_bullet(player_settings, screen, players_plane, enemys, bullets):
    '''删除超出屏幕的子弹'''
    bullets.update()

    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    # 子弹碰到敌人就消失
    collisions = pygame.sprite.groupcollide(bullets, enemys, True, True)
    if len(enemys) == 0:
        bullets.empty()
        create_enemys(player_settings, screen, players_plane, enemys)


5.游戏结束

你可能感兴趣的:(Python,python,pygame,飞机大战,详细源码)