Python-PyGame实现飞机大战游戏(1)
一、 环境配置
1、技术与环境
技术:Python+Pygame模块
环境:JetBrains PyCharm Community Edition 2019.1.3 x64,windows10
2、Pygame模块配置
见博客:
pygame模块配置(命令行配置、PyCharm配置、解决PyCharm新建项目需要重新配置问题
(https://blog.csdn.net/lyz21/article/details/96483543 )
二、实现步骤
1、显示界面
在进行游戏设计之前,先画出来一个界面,之后再在界面上进行操作。背景图片名为background.png,目录为项目resources\images\background.png下,本节完成结果显示如下:
代码:
import pygame
from sys import exit
'''初始化界面'''
# 窗口分辨率
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 640
# 载入背景图片
background_img = pygame.image.load('resources/images/background.png')
# 初始化pygame
pygame.init()
# 初始化窗口
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
# 设置窗口标题
pygame.display.set_caption('飞机大战')
'''事件循环'''
while True:
# 绘制背景
screen.blit(background_img, (0, 0))
# 更新屏幕
pygame.display.update()
# 处理按键
for event in pygame.event.get():
# 游戏退出
if event.type == pygame.QUIT:
pygame.quit()
exit()
2、添加飞机
界面显示出来,我们在上面添加玩家飞机。
首先封装一个玩家类:
class Hero():
def __init__(self, hero_surface, hero_init_position):
self.image = hero_surface
self.rect = self.image.get_rect() # get_rect返回一个矩形rect对象
self.rect.topleft = hero_init_position # 矩形位置(定左上角的位置)
添加玩家战斗机
'载入飞机图片'
# 玩家战斗机
player_plane_image = pygame.image.load('resources/images/feiji.png')
创建玩家
# 创建玩家
hero = Hero(player_plane_image, [200, 400])
在主事件循环中绘制玩家飞机
# 绘制玩家飞机
screen.blit(hero.image, hero.rect)
3、让飞机变成动态
为了让飞机看起来更形象,我们利用图片切割,对飞机进行动态处理。原理是把一张图片根据位置取出特定区域的图像,形成若干张不同的图片,加载图片时这几张图片循环加载,营造出动态的样子。这里为了简便,只切割两张图片切换。
加载并切割图片,切割好的图片用列表存储,方便进行切换:
'载入玩家战斗机'
# 玩家战斗机图片
player_plane_image = pygame.image.load('resources/images/feiji.png')
# 取出不带火焰的飞机部分
player_plane_imageA = player_plane_image.subsurface(pygame.Rect(0, 0, 102, 89))
# 取出带火焰的飞机部分
player_plane_imageB = player_plane_image.subsurface(pygame.Rect(0, 0, 102, 109))
# 用列表存储图像
player_plane_images = []
player_plane_images.append(player_plane_imageA)
player_plane_images.append(player_plane_imageB)
因为要切换图片,所以需要记录循环数,根据循环数进行图片切换:
# 计数,根据计数做一些定时操作
tick = 0
在主循环中进行图片切换:
# 根据计数切换飞机图片
if tick % 41 == 0:
hero.image = player_plane_images[tick % 2]
# 绘制玩家飞机
screen.blit(hero.image, hero.rect)
# 更新计数
tick = tick + 1
完成后的样子:
4、移动飞机
在Hero类设定移动速度:
self.speed = 2
并添加move方法:
def move(self, offset):
self.rect.left = self.rect.left + offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
self.rect.top = self.rect.top + offset[pygame.K_DOWN] - offset[pygame.K_UP]
用字典存储上、下、左、右四个按键,值为移动值
# 设置按键状态,用字典存储。字典中存储的键是前后左右四个按键值,后面数字对相应该方向移动距离
offset = {pygame.K_LEFT: 0, pygame.K_RIGHT: 0, pygame.K_UP: 0, pygame.K_DOWN: 0}
在按键监听中处理按键事件
# 按键按下
if event.type == pygame.KEYDOWN:
# 是否在offset字典中,即按下的是否是前后左右四个键
if event.key in offset:
# 在的话,将该方向的移动值设置为相应的值
offset[event.key] = hero.speed
# 按键松开
if event.type == pygame.KEYUP:
# 是否在offset字典中,即按下的是否是前后左右四个键
if event.key in offset:
# 在的话,将该方向的移动值归0
offset[event.key]=0
在主循环中调用Hero的移动方法:
# 调用移动方法
hero.move(offset)
5、设置飞机移动范围
更改move方法:
def move(self, offset):
x = self.rect.left + offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
y = self.rect.top + offset[pygame.K_DOWN] - offset[pygame.K_UP]
# 若最左边坐标小于0,即出左边界,设为0
if x < 0:
self.rect.left = 0
# 若最左边坐标大于界面宽度-飞机宽度,即出右边界,设为右边界值
elif x > SCREEN_WIDTH - self.rect.width:
self.rect.left = SCREEN_WIDTH - self.rect.width
# 其他即为正常情况
else:
self.rect.left = x
# 若最上边坐标小于0,即出上边界,设为0
if y < 0:
self.rect.top = 0
# 若最上边坐标大于界面高度-飞机高度,即出下边界,设为下边界值
elif y > SCREEN_HEIGHT - self.rect.height:
self.rect.top = SCREEN_HEIGHT - self.rect.height
# 其他视为正常情况
else:
self.rect.top = y
三、总结
1、目前完成界面状态
2、目前目录
3、目前代码
import pygame
from sys import exit
from Hero import Hero
# 计数,根据计数做一些定时操作
tick = 0
# 设置按键状态,用字典存储。字典中存储的键是前后左右四个按键值,后面数字对相应该方向移动距离
offset = {pygame.K_LEFT: 0, pygame.K_RIGHT: 0, pygame.K_UP: 0, pygame.K_DOWN: 0}
'''初始化界面'''
# 窗口分辨率
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 640
# 载入背景图片
background_img = pygame.image.load('resources/images/background.png')
'载入玩家战斗机'
# 玩家战斗机图片
player_plane_image = pygame.image.load('resources/images/feiji.png')
# 取出不带火焰的飞机部分
player_plane_imageA = player_plane_image.subsurface(pygame.Rect(0, 0, 102, 89))
# 取出带火焰的飞机部分
player_plane_imageB = player_plane_image.subsurface(pygame.Rect(0, 0, 102, 109))
# 用列表存储图像
player_plane_images = []
player_plane_images.append(player_plane_imageA)
player_plane_images.append(player_plane_imageB)
# 玩家飞机出现位置
hero_position = [200, 400]
# 创建玩家
hero = Hero(player_plane_image, hero_position)
# 初始化pygame
pygame.init()
# 初始化窗口
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
# 设置窗口标题
pygame.display.set_caption('飞机大战')
'''事件循环'''
while True:
# 绘制背景
screen.blit(background_img, (0, 0))
# 根据计数切换飞机图片
if tick % 41 == 0:
hero.image = player_plane_images[tick % 2]
# 绘制玩家飞机
screen.blit(hero.image, hero.rect)
# 更新计数
tick = tick + 1
# 更新屏幕
pygame.display.update()
# 处理按键
for event in pygame.event.get():
# 游戏退出
if event.type == pygame.QUIT:
pygame.quit()
exit()
# 按键按下
if event.type == pygame.KEYDOWN:
# 是否在offset字典中,即按下的是否是前后左右四个键
if event.key in offset:
# 在的话,将该方向的移动值设置为相应的值
offset[event.key] = hero.speed
# 按键松开
if event.type == pygame.KEYUP:
# 是否在offset字典中,即按下的是否是前后左右四个键
if event.key in offset:
# 在的话,将该方向的移动值归0
offset[event.key]=0
# 调用移动方法
hero.move(offset)
def move(self, offset):
x = self.rect.left + offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
y = self.rect.top + offset[pygame.K_DOWN] - offset[pygame.K_UP]
# 若最左边坐标小于0,即出左边界,设为0
if x < 0:
self.rect.left = 0
# 若最左边坐标大于界面宽度-飞机宽度,即出右边界,设为右边界值
elif x > SCREEN_WIDTH - self.rect.width:
self.rect.left = SCREEN_WIDTH - self.rect.width
# 其他即为正常情况
else:
self.rect.left = x
# 若最上边坐标小于0,即出上边界,设为0
if y < 0:
self.rect.top = 0
# 若最上边坐标大于界面高度-飞机高度,即出下边界,设为下边界值
elif y > SCREEN_HEIGHT - self.rect.height:
self.rect.top = SCREEN_HEIGHT - self.rect.height
# 其他视为正常情况
else:
self.rect.top = y