python实现飞机大战游戏(pygame版)

简介

使用python实现pygame版的飞机大战游戏;

环境:Windows系统+python3.8.0

游戏规则:

1.点击“PLAY”或者按键“P”开始游戏;

2.敌机根据设置频率从顶部随机位置生成,生成后向下移动;

3.飞船在底部中间生成,玩家使用上下左右键控制飞船移动,敲击空格键发射子弹;

4.子弹打到敌机,该敌机产生爆炸效果并累计分数到右上角;

5.消灭10只飞机后,等级升高,敌机生成频率变快,下落速度也变快;

6.当三条命都消失了,游戏结束。

游戏运行效果如下:

实现过程

1.新建文件“file.py”,用来存储信息到文件和读取文件的信息,本例用来存储和读取最高分;

import pickle

# filename = 'file/stats.pkl'

# 存储信息到文件

def save_file(obj, filename):

statsObj = load_file(filename)

if statsObj == 0:

# 不存在文件时,直接保存字典

with open(filename, 'wb') as f:

pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL)

else:

# 存在文件时,只修改文件中的最高分

for key, val in statsObj.items():

# 获取文件最高分的值(当文件字段不止一个时候使用)

if key == 'highScore':

statsObj[key] = obj['highScore']

obj = statsObj

with open(filename, 'wb') as f:

pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL)

# 读取信息

def load_file(filename):

try:

with open(filename, 'rb') as f:

return pickle.load(f)

except FileNotFoundError:

# 不存在文件则输入错误信息

msg = "Sorry, the file " + filename + " does not exist."

print(msg)

return 0

# obj = {'highScore': 20, 'points': 5}

# obj = {'highScore': 50}

# save_file(obj, filename)

# filedata = load_file(filename)

# print(filedata)

2.k新建文件settings.py,用来定义一些必须的基本属性和初始值;

import file as f

class Settings():

def __init__(self):

self.screen_width = 480

self.screen_height = 660

self.bg_color = (230, 230, 230)

# 子弹设置(宽、高、颜色、最大数量)

self.bullet_width = 5

self.bullet_height = 15

self.bullet_color = 255, 255, 255

# 敌机移动频率

self.enemy_frequency = 0

# 加快游戏节奏的速度

self.speedup_scale = 1.1

# 分数的提高速度

self.score_scale = 1.5

self.initialize_settings()

# 初始化统计信息

self.reset_stats()

# 统计信息文件路径

self.filename = 'file/stats.pkl'

# 游戏刚启动时处于非活动状态

self.game_active = False

# 读取文件的最高分,在任何情况下都不应重置最高得分

statsObj = f.load_file(self.filename)

if statsObj == 0:

# 不存在文件则显示最高分0

highScore = 0

else:

for key, val in statsObj.items():

# 获取文件最高分的值(当文件字段不止一个时候使用)

if key == 'highScore':

highScore = val

self.high_score = highScore

def initialize_settings(self):

"""初始化随游戏进行而变化的设置"""

self.player_move_speed = 2.5

self.bullet_speed = 3

self.enemy_move_speed = 1

# 记分

self.one_points = 50

def increase_speed(self):

"""提高速度设置"""

# self.player_move_speed *= self.speedup_scale

self.bullet_speed *= self.speedup_scale

self.enemy_move_speed *= self.speedup_scale

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

def reset_stats(self):

"""初始化在游戏运行期间可能变化的统计信息"""

# 可射失的数量

self.player_limit = 3

# 射击分数

self.score = 0

# 等级

self.level = 1

# 打中多少矩形升一级

self.level_number = 10

# 生成敌机频率间隔

self.enemy_frequency_space = 50

3.新建文件enemy.py,用来定义敌机类(位置topleft随机生成)和声明方法move;

import pygame

import random

from pygame.sprite import Sprite

class Enemy(Sprite):

def __init__(self, enemy_down_imgs, settings):

super(Enemy, self).__init__()

self.image = pygame.image.load('images/enemy1.png')

self.rect = self.image.get_rect()

self.rect.topleft = [random.randint(0, settings.screen_width - self.rect.width), 0]

self.down_imgs = enemy_down_imgs

self.speed = settings.enemy_move_speed

self.down_index = 0

# 敌机移动,边界判断及删除在游戏主循环里处理

def move(self):

self.rect.top += self.speed

4.新建文件player.py,用来定义玩家类(可上下左右移动)和相应的方法;

import pygame

from pygame.sprite import Sprite

class Player(Sprite):

def __init__(self, settings, screen):

super(Player, self).__init__()

self.settings = settings

self.screen = screen

self.screen_rect = self.screen.get_rect()

# 引入飞船图片并定位

self.image = pygame.image.load('images/player.png')

self.rect = self.image.get_rect()

self.rect.centerx = self.screen_rect.centerx

self.rect.bottom = self.screen_rect.bottom

# 移动标志

self.move_left = False

self.move_right = False

self.move_down = False

self.move_up = False

def rotate(self, angle):

# 图片旋转

self.image = pygame.transform.rotate(self.image, angle)

def scale(self, multiple):

# 图片缩放

self.image = pygame.transform.smoothscale(self.image, (multiple, multiple))

def update(self):

if self.move_left and self.rect.left > self.screen_rect.left:

self.rect.centerx -= self.settings.player_move_speed

if self.move_right and self.rect.right < self.screen_rect.right:

self.rect.centerx += self.settings.player_move_speed

if self.move_down and self.rect.bottom < self.screen_rect.bottom:

self.rect.centery += self.settings.player_move_speed

if self.move_up and self.rect.top > 0:

self.rect.centery -= self.settings.player_move_speed

def draw_player(self):

"""绘制飞船到屏幕"""

self.screen.blit(self.image, self.rect)

5.新建文件“bullet.py”,用来定义子弹类(位置在飞船的顶部,并往上移动)和相应的方法;

import pygame

from pygame.sprite import Sprite

class Bullet(Sprite):

""" 一个对飞船发射的子弹进行管理的类 """

def __init__(self, settings, screen, player):

""" 在飞船所处的位置创建一个子弹对象 """

super(Bullet, self).__init__()

self.screen = screen

# 在 (0,0) 处创建一个表示子弹的矩形,再设置正确的位置

self.rect = pygame.Rect(0, 0, settings.bullet_width, settings.bullet_height)

self.rect.centerx = player.rect.centerx

# 飞船顶部

self.rect.bottom = player.rect.top

# 存储用小数表示的子弹位置

self.y = float(self.rect.y)

self.color = settings.bullet_color

self.speed = settings.bullet_speed

def update(self):

"""向上移动子弹"""

# 更新表示子弹位置的小数值(子弹往右)

self.y -= self.speed

# 更新表示子弹的rect的位置

self.rect.y = self.y

def draw_bullet(self):

"""在屏幕上绘制子弹"""

pygame.draw.rect(self.screen, self.color, self.rect)

6.新建文件“button.py”,用来定义按钮类和相应方法,本例使用于绘制“PLAY”按钮;

import pygame.font

class Button():

def __init__(self, screen, msg):

"""初始化按钮的属性"""

self.screen = screen

self.screen_rect = screen.get_rect()

# 设置按钮的尺寸和其他属性

self.width, self.height = 100, 30

self.button_color = (216, 30, 6)

self.text_color = (255, 255, 255)

self.font = pygame.font.SysFont(None, 36)

# 创建按钮的rect对象,并使其居中

self.rect = pygame.Rect(0, 0, self.width, self.height)

self.rect.center = self.screen_rect.center

# 按钮的标签只需创建一次

self.prep_msg(msg)

def prep_msg(self, msg):

"""将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)

7.新建文件“scoreboard.py”,用来定义记分板,本例使用于绘制左上角飞船(生命数)、顶部中间的“最高分”、右上角的“积分”和“等级”;

import pygame.font

from pygame.sprite import Group

from player import Player

class Scoreboard():

"""显示得分信息的类"""

def __init__(self, settings, screen):

"""初始化显示得分涉及的属性"""

self.screen = screen

self.screen_rect = screen.get_rect()

self.settings = settings

# 显示得分信息时使用的字体设置

self.text_color = (255, 255, 255)

self.font = pygame.font.SysFont(None, 30)

# 飞船缩放值

self.scaleValue = 20

# 准备初始得分图像\最高得分\等级

self.prep_score()

self.prep_high_score()

self.prep_level()

self.prep_players()

def prep_score(self):

"""将得分转换为渲染的图像"""

rounded_score = int(round(self.settings.score, -1))

score_str = '{:,}'.format(rounded_score)

self.score_image = self.font.render(score_str, True, self.text_color)

# 将得分放在屏幕右上角

self.score_rect = self.score_image.get_rect()

self.score_rect.right = self.screen_rect.right -20

self.score_rect.top = 10

def prep_high_score(self):

""" 将最高得分转换为渲染的图像 """

high_score = int(round(self.settings.high_score, -1))

high_score_str = "{:,}".format(high_score)

self.high_score_image = self.font.render(high_score_str, True, self.text_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 = self.score_rect.top

def prep_level(self):

"""将等级转换为渲染的图像"""

self.level_image = self.font.render(str(self.settings.level), True, self.text_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_players(self):

""" 显示还余下多少艘飞船 """

self.players = Group()

for player_number in range(self.settings.player_limit):

player = Player(self.settings, self.screen)

# 缩放球大小并赋值位置

player.scale(self.scaleValue)

player.rect.x = 10 + player.rect.width * player_number * 0.5

player.rect.y = self.score_rect.top

self.players.add(player)

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.players.draw(self.screen)

8.新建文件“game_functions.py”,存放跟游戏有关的所有业务逻辑函数(代码有详细的注释信息);

import sys

import pygame

from bullet import Bullet

from enemy import Enemy

import file as f

# 事件

def check_events(settings, screen, player, play_button, scoreboard, bullets, fireSound):

""" 响应按键和鼠标事件 """

for event in pygame.event.get():

if event.type == pygame.QUIT:

save_file(settings)

sys.exit()

elif event.type == pygame.KEYDOWN:

check_keydown_events(event, settings, screen, player, scoreboard, bullets, fireSound)

elif event.type == pygame.KEYUP:

check_keyup_events(event, player)

elif event.type == pygame.MOUSEBUTTONDOWN:

mouse_x, mouse_y = pygame.mouse.get_pos()

check_play_button(settings, play_button, scoreboard, mouse_x, mouse_y)

def check_keydown_events(event, settings, screen, player, scoreboard, bullets, fireSound):

""" 响应按键 """

if event.key == pygame.K_DOWN:

player.move_down = True

elif event.key == pygame.K_UP:

player.move_up = True

elif event.key == pygame.K_LEFT:

player.move_left = True

elif event.key == pygame.K_RIGHT:

player.move_right = True

elif event.key == pygame.K_SPACE:

fireSound.play()

# 点击空格键创建一颗子弹

fire_bullet(settings, screen, player, bullets)

elif event.key == pygame.K_p:

start_game(settings, scoreboard)

elif event.key == pygame.K_q:

save_file(settings)

sys.exit()

def check_keyup_events(event, player):

""" 响应松开 """

if event.key == pygame.K_DOWN:

player.move_down = False

elif event.key == pygame.K_UP:

player.move_up = False

elif event.key == pygame.K_LEFT:

player.move_left = False

elif event.key == pygame.K_RIGHT:

player.move_right = False

def check_play_button(settings, play_button, scoreboard, mouse_x, mouse_y):

"""在玩家单击Play按钮时开始新游戏"""

button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)

if button_clicked and not settings.game_active:

start_game(settings, scoreboard)

def start_game(settings, scoreboard):

"""开始游戏"""

# 重置游戏设置

settings.initialize_settings()

# 隐藏光标

pygame.mouse.set_visible(False)

# 重置游戏统计信息

settings.reset_stats()

settings.game_active = True

# 重置记分牌图像

scoreboard.prep_score()

scoreboard.prep_high_score()

scoreboard.prep_level()

scoreboard.prep_players()

def save_file(settings):

# 保持文件

obj = {'highScore': settings.high_score}

f.save_file(obj, settings.filename)

# 敌机

def update_enemies(settings, screen, scoreboard, enemies, enemies_down, enemy_down_imgs, player, bullets, explosiveSound):

# 生成敌机,需要控制生成频率

if settings.enemy_frequency % settings.enemy_frequency_space == 0:

enemy1 = Enemy(enemy_down_imgs, settings)

enemies.add(enemy1)

settings.enemy_frequency += 1

if settings.enemy_frequency >= 100:

settings.enemy_frequency = 0

for enemy in enemies:

# 移动敌机

enemy.move()

# 敌机与玩家飞机碰撞效果处理 两个精灵之间的圆检测

if pygame.sprite.collide_circle(enemy, player):

enemies_down.add(enemy)

enemies.remove(enemy)

settings.player_limit -= 1

scoreboard.prep_players()

break

# 移动出屏幕后删除飞机

if enemy.rect.top < 0:

enemies.remove(enemy)

# 敌机被子弹击中效果处理

# 将被击中的敌机对象添加到击毁敌机 Group 中,用来渲染击毁动画

# 方法groupcollide()是检测两个精灵组中精灵们的矩形冲突

enemies1_down = pygame.sprite.groupcollide(enemies, bullets, True, True)

if enemies1_down:

explosiveSound.play()

# 计算分数并渲染

for enemys in enemies1_down.values():

settings.score += settings.one_points * len(enemys)

scoreboard.prep_score()

# 渲染最高分

check_high_score(settings, scoreboard)

# 等达到等级数量升级并渲染新等级

settings.level_number -= 1

if settings.level_number == 0:

settings.increase_speed()

settings.level += 1

scoreboard.prep_level()

# 还原为4(同settings一致)

settings.level_number = 10

# 加快生成敌机

if settings.enemy_frequency_space > 10:

settings.enemy_frequency_space -= 10

# 遍历key值 返回的碰撞敌机

for enemy_down in enemies1_down:

# 点击销毁的敌机到列表

enemies_down.add(enemy_down)

# 敌机被子弹击中效果显示

for enemy_down in enemies_down:

if enemy_down.down_index == 0:

pass

if enemy_down.down_index > 7:

enemies_down.remove(enemy_down)

continue

#显示碰撞图片

screen.blit(enemy_down.down_imgs[enemy_down.down_index // 2], enemy_down.rect)

enemy_down.down_index += 1

# 显示精灵

enemies.draw(screen)

# 子弹

def fire_bullet(settings, screen, player, bullets):

"""创建子弹"""

new_bullet = Bullet(settings, screen, player)

bullets.add(new_bullet)

def update_bullets(screen, bullets):

"""更新子弹的位置,并删除已消失的子弹"""

# 更新子弹的位置

bullets.update()

# 删除已消失的子弹并同时更新飞船的生命

for bullet in bullets.copy():

if bullet.rect.top < screen.get_rect().top:

bullets.remove(bullet)

# 分数

def check_high_score(settings, scoreboard):

"""检查是否诞生了新的最高得分"""

if settings.score > settings.high_score:

settings.high_score = settings.score

scoreboard.prep_high_score()

# 屏幕

def update_screen(settings, screen, player, play_button, scoreboard, enemies, bullets):

""" 更新屏幕上的图像,并切换到新屏幕 """

# 绘制飞船到屏幕

player.draw_player()

# 绘制子弹到屏幕

for bullet in bullets.sprites():

bullet.draw_bullet()

# 渲染记分牌信息

scoreboard.show_score()

#

if settings.player_limit == 0:

settings.game_active = False

settings.reset_stats()

# 清空矩形列表和子弹列表

enemies.empty()

bullets.empty()

screen_rect = screen.get_rect()

player.rect.centerx = screen_rect.centerx

player.rect.bottom = screen_rect.bottom

# 如果游戏处于非活动状态,就绘制 Play 按钮

if not settings.game_active:

play_button.draw_button()

# 让最近绘制的屏幕可见

pygame.display.flip()

9.新建文件shootingenemy.py,主函数用来初始化程序,并同步更新程序的信息;

import pygame

from pygame.sprite import Group

from settings import Settings

from button import Button

from player import Player

import game_functions as gf

from scoreboard import Scoreboard

def run_game():

pygame.init()

# 初始化全部音频,并加载爆炸声音乐

pygame.mixer.init()

# 等待1s

pygame.time.delay(1000)

pygame.mixer.music.load('file/bgsound.mp3')

# -1代表无限循环(背景音乐)

pygame.mixer.music.play(-1)

# 爆炸声

explosiveSound = pygame.mixer.Sound('file/explosiveSound.wav')

# 枪声

fireSound = pygame.mixer.Sound('file/fireSound.wav')

# 游戏循环帧率设置

clock = pygame.time.Clock()

settings = Settings()

screen = pygame.display.set_mode((settings.screen_width, settings.screen_height))

# 全屏显示

# screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)

pygame.display.set_caption('飞机大战')

# 左上角图标

ic_launcher = pygame.image.load('images/ic_launcher.png').convert_alpha()

pygame.display.set_icon(ic_launcher)

# 背景图

background = pygame.image.load('images/background.png').convert_alpha()

# 敌机图片

enemy_img1= pygame.image.load('images/enemy1.png')

enemy_img2= pygame.image.load('images/enemy2.png')

enemy_img3= pygame.image.load('images/enemy3.png')

enemy_img4= pygame.image.load('images/enemy4.png')

# 敌机不同状态的图片列表,多张图片展示为动画效果

enemy_down_imgs = []

enemy_down_imgs.append(enemy_img1)

enemy_down_imgs.append(enemy_img2)

enemy_down_imgs.append(enemy_img3)

enemy_down_imgs.append(enemy_img4)

# 储存敌机

enemies = Group()

# 存储被击毁的飞机,用来渲染击毁动画

enemies_down = Group()

# 创建Play按钮

play_button = Button(screen, 'Play')

# 创建飞船

player = Player(settings, screen)

# 创建子弹的编组

bullets = Group()

# 创建记分牌

scoreboard = Scoreboard(settings, screen)

while True:

# 绘制背景

screen.blit(background, (0, 0))

# 控制游戏最大频率

clock.tick(60)

# 检查玩家输入(不加会导致一直加载)

gf.check_events(settings, screen, player, play_button, scoreboard, bullets, fireSound)

if settings.game_active:

# 更新飞船位置

player.update()

# 更新敌机

gf.update_enemies(settings, screen, scoreboard, enemies, enemies_down, enemy_down_imgs, player, bullets, explosiveSound)

# 更新子弹位置

gf.update_bullets(screen, bullets)

# 更新屏幕信息

gf.update_screen(settings, screen, player, play_button, scoreboard, enemies, bullets)

run_game(),

10.在文件shootingenemy.py目录路径下,执行命令“python shootingenemy.py”弹出窗口,即可对其操作游玩。

结语

该游戏加入了背景音乐、射击声、子弹射中敌机的爆炸声和爆炸效果、生命数、积分、等级、最高分和开始按钮等元素,大家也可以自行加入其它好玩的元素。

更多关于python游戏的精彩文章请点击查看以下专题:

python俄罗斯方块游戏集合

python经典小游戏汇总

python微信跳一跳游戏集合

更多有趣的经典小游戏实现专题,分享给大家:

C++经典小游戏汇总

JavaScript经典游戏 玩不停

java经典小游戏汇总

javascript经典小游戏汇总

以上是 python实现飞机大战游戏(pygame版) 的全部内容, 来源链接: utcz.com/z/361217.html

回到顶部