一、Pygame
1、通过pip导入pygame的包
pip install pygame
2、导入飞机大战需要的资源文件到项目根路径下
3、Pygame的基本使用
import time
# 导入pygame的包
import pygame
# 初始化pygame,让计算机硬件做准备
pygame.init()
# 创建一个窗口对象,并指定宽和高
pygame.display.set_mode([500, 700])
# 导入磁盘上的图片资源文件,返回一个图片对象
image = pygame.image.load("res/app.ico")
# 设置窗口显式的图标
pygame.display.set_icon(image)
# 设置窗口名称
pygame.display.set_caption("飞机大战v1.0")
time.sleep(5)
4、pygame的图片基本处理
# 导入pygame的包
import pygame
import time
# 初始化pygame,让计算机硬件做准备
pygame.init()
# 初始化窗口对象的宽高属性
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
# 创建一个窗口对象,并指定宽和高,返回一个窗口对象
window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
# 加载图片资源文件,返回图片对象
# 背景图
bg_image = pygame.image.load("res/img_bg_level_1.jpg")
# 飞机图片
plane_image = pygame.image.load("res/hero2.png")
# 绘制图片,将图片的坐标原点放到窗口的指定位置,参数1:图片对象;参数2:窗口的坐标(窗口左上角为原点(0,0))
# 先绘制背景图,再绘制飞机图,否则背景图会覆盖飞机图,导致不显示飞机图
window.blit(bg_image, (0, 0))
window.blit(plane_image, (100, 200))
# 刷新窗口,让图片加载到窗口中
pygame.display.update()
time.sleep(3)
5、pygame的图片移动处理 -- rect矩形对象
# 导入pygame的包
import pygame
import time
# 初始化pygame,让计算机硬件做准备
pygame.init()
# 初始化窗口对象的宽高属性
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
bg_image = pygame.image.load("res/img_bg_level_1.jpg")
window.blit(bg_image, (0, 0))
plane_image = pygame.image.load("res/hero2.png")
"""
创建这个图片的矩形对象,这个对象其实就是一个元组
(图片原点在x轴坐标, 图片原点在y轴坐标, 图片的宽, 图片的高)
默认x,y轴的坐标都是0
"""
plane_rect = plane_image.get_rect()
# print(plane_rect) # <rect(0, 0, 120, 78)>
"""
通过矩形对象的 move_ip(x, y) 这个方法,可以将矩形对象相对于当前位置移动指定的偏移量
if 按下键盘上键:
plane_rect.move_ip(0, -偏移量)
if 按下键盘下键:
plane_rect.move_ip(0, +偏移量)
if 按下键盘左键:
plane_rect.move_ip(-偏移量, 0)
if 按下键盘右键:
plane_rect.move_ip(+偏移量, 0)
"""
# 将飞机图片移动到屏幕中间爱你
plane_rect.move_ip(WINDOW_WIDTH / 2 - plane_rect[2] / 2, WINDOW_HEIGHT / 2 - plane_rect[3] / 2)
# print(plane_rect) # <rect(196, 345, 120, 78)>
# 根据矩形对象设置飞机图片位置
window.blit(plane_image, (plane_rect[0], plane_rect[1]))
# 动态让飞机图片每次向上偏移1
while True:
plane_rect.move_ip(0, -1)
window.blit(bg_image, (0, 0))
window.blit(plane_image, (plane_rect[0], plane_rect[1]))
# 刷新窗口,让图片加载到窗口中
pygame.display.update()
time.sleep(3)
6、pygame的事件处理
import sys # sys是处理和程序相关的操作
import pygame
pygame.init()
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
bg_image = pygame.image.load("res/img_bg_level_1.jpg")
plane_image = pygame.image.load("res/hero2.png")
plane_rect = plane_image.get_rect()
plane_rect.move_ip(WINDOW_WIDTH / 2 - plane_rect[2] / 2, WINDOW_HEIGHT / 2 - plane_rect[3] / 2)
# 设置飞机移动速度
speed = 1
while True:
window.blit(bg_image, (0, 0))
window.blit(plane_image, (plane_rect[0], plane_rect[1]))
"""
pygame.event.get() 获取所有的单次事件,并将所有的事件放入一个列表,并返回
"""
# 获取事件列表
evenList = pygame.event.get()
# 遍历事件列表,获取每个事件
for event in evenList:
# 判断事件如果是点击退出事件
if event.type == pygame.QUIT:
# 如果是,就结束程序
sys.exit() # 直接结束程序的运行(线程)
pygame.quit() # 退出pygame包的运行程序
# 判断是否是键盘按下事件
if event.type == pygame.KEYDOWN:
# 判断按键是什么
if event.key == pygame.K_ESCAPE:
# 如果是退出键,就退出程序
sys.exit()
pygame.quit()
if event.key == pygame.K_SPACE or event.key == pygame.K_j:
# 按下的是空格或者J键,用来发射子弹
print("发射子弹")
if event.key == pygame.K_DOWN:
# 按的是上键,向上移动飞机
pass
"""
pygame.key.get_pressed() : 获取键盘上一直被按下的键,返回一个元组
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0 ...)
该元组是没个键对应的ASCII码表的元组,值为1的地方,即表示当前索引代表的元素的按键被一直按下
"""
# 获取键盘中的连续按键(一直按着键盘不松)
pressed_key = pygame.key.get_pressed()
# 判断按下的键是什么
# pygame.K_UP 得到的是上键的数字,对应数字(索引)在元组中如果是1,则if判断成立,即表示上键一直被按着
if pressed_key[pygame.K_UP]:
# 上键一直被按着,向上移动
# 向上移动前需要先判断飞机是否超出屏幕区域,如果超出,则不移动
if plane_rect[1] <= 0:
pass
else:
plane_rect.move_ip(0, -speed)
if pressed_key[pygame.K_DOWN]:
# 向下移动之前判断是否超出屏幕区域,超出不移动
if plane_rect[1] >= WINDOW_HEIGHT - plane_rect[3]:
pass
else:
plane_rect.move_ip(0, speed)
if pressed_key[pygame.K_LEFT]:
# 向做移动之前判断飞机是否超出屏幕区域,超出不移动
if plane_rect[0] <= 0:
pass
else:
plane_rect.move_ip(-speed, 0)
if pressed_key[pygame.K_RIGHT]:
# 向右移动之前判断是否超出屏幕区域,超出不移动
if plane_rect[0] >= WINDOW_WIDTH - plane_rect[2]:
pass
else:
plane_rect.move_ip(speed, 0)
window.blit(bg_image, (0, 0))
window.blit(plane_image, (plane_rect[0], plane_rect[1]))
pygame.display.update()
7、背景图(地图)滚动效果处理
import pygame
pygame.init()
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
bg1_image = pygame.image.load("res/img_bg_level_1.jpg")
bg2_image = pygame.image.load("res/img_bg_level_1.jpg")
bg1_rect = bg1_image.get_rect()
bg2_rect = bg2_image.get_rect()
# 设置第一次绘制背景图时y轴坐标的位置
bg1_rect[1] = -WINDOW_HEIGHT
bg2_rect[1] = 0
# 设置变量,作为绘制的y轴的坐标值,每次循环(滚动)之后会增加
bg1_y = bg1_rect[1]
bg2_y = bg2_rect[1]
# 定义背景滚动速度
speed = 1
while True:
pygame.event.get()
# x轴坐标不变,每次按照偏移y轴坐标量进行绘制
window.blit(bg1_image, (bg1_rect[0], bg1_y))
window.blit(bg2_image, (bg2_rect[0], bg2_y))
# 如果第一张图的y轴到达坐标0的时候,需要重新将第一张图的y轴设置为初始值
if bg1_y >= 0:
bg1_y = -WINDOW_HEIGHT
# 如果第二张图的y轴到达屏幕最下端的时候,需要重新将第二张图的y轴设置为初始值
if bg2_y >= WINDOW_HEIGHT:
bg2_y = 0
# 每次循环,y轴的偏移量都增加一个速率
bg1_y += speed
bg2_y += speed
# 更新window
pygame.display.update()
8、pygame实现飞机大战的基本框架
# 导入pygame
import pygame
# 导入sys
import sys
# 导入random
import random
# 初始化pygame环境
pygame.init()
# 设定屏幕宽高常量
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
# 构建窗口对象
window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
# ------------------------------定义背景图片自动滚动的效果 start--------------------------------------
bg1_image = pygame.image.load("res/img_bg_level_1.jpg")
bg2_image = pygame.image.load("res/img_bg_level_1.jpg")
# 获取两张背景图片的矩形对象
bg1_rect = bg1_image.get_rect()
bg2_rect = bg2_image.get_rect()
# 设置第一次绘制背景图时,两张图片y轴的起始位置
bg1_rect[1] = -WINDOW_HEIGHT
bg2_rect[1] = 0
# 设置变量,用来接收每次滚动时,两张图片 y 轴的坐标值,初始值为两张图片y轴的初始值
bg1_y = bg1_rect[1]
bg2_y = bg2_rect[1]
# ------------------------------定义背景图片自动滚动的效果 end--------------------------------------
# ------------------------------定义飞机移动的效果 start--------------------------------------
# 初始化英雄飞机对象
hero_plane = pygame.image.load("res/hero.png")
# 获取英雄飞机的矩形对象
hero_rect = hero_plane.get_rect()
# 设置英雄飞机矩形对象的偏移量(即首次登场时候所在的位置)
hero_rect.move_ip(WINDOW_WIDTH / 2 - hero_rect[2] / 2, WINDOW_HEIGHT - hero_rect[3])
# 随机初始化敌机对象
enemy_num = str(random.randint(1, 7))
enemy_plane = pygame.image.load("res/img-plane_" + enemy_num + ".png")
# 获取敌机的矩形对象
enemy_rect = enemy_plane.get_rect()
# 设置敌机首次出现的位置(在屏幕上方,最左边不能小于0,最右边不能大于屏幕长度-敌机度, y轴从-敌机高开始)
enemy_rect.move_ip(random.randint(0, WINDOW_WIDTH - enemy_rect[2]), -enemy_rect[3])
# 设置飞机移动速度以及背景图片移动速度
plane_speed = 3
bg_speed = 1
# ------------------------------定义飞机移动的效果 start--------------------------------------
# 定义退出游戏操作的函数
def game_over():
sys.exit()
pygame.quit()
# 定义显示分数操作的函数
def show_score():
# 设置起始分数
score = 10
# 设置字体的样式和大小,返回字体对象
font = pygame.font.SysFont('SimHei', 42)
# 设置字体属性 render(文本内容,抗锯齿,颜色(RBG数值)), 返回文字对象
text_obj = font.render("得分:%s" % score, 1, (255, 255, 255))
# 获取文字矩形对象,并且设置矩形对象的位置
text_rect = text_obj.get_rect()
text_rect.move_ip(10, 10)
# 在指定的位置绘制文字对象
# 游戏开始,进行循环
while True:
# ------------------------------处理背景图片自动滚动的效果 start--------------------------------------
# x轴不变,按照y轴变量进行背景图片绘制
window.blit(bg1_image, (bg1_rect[0], bg1_y))
window.blit(bg2_image, (bg2_rect[0], bg2_y))
# 如果第一张图片的y轴到大屏幕最下端,重新设置y轴为初始值
if bg1_y >= 0:
bg1_y = -WINDOW_HEIGHT
# 如果第二张图片的y轴原点到大屏幕最下端,重新设置y轴为初始值
if bg2_y >= WINDOW_HEIGHT:
bg2_y = 0
# 每次循环,变量增加
bg1_y += bg_speed
bg2_y += bg_speed
# ------------------------------处理背景图片自动滚动的效果 end--------------------------------------
# ------------------------------处理飞机移动的效果 start--------------------------------------
# 绘制敌我飞机起始位置
window.blit(hero_plane, (hero_rect[0], hero_rect[1]))
window.blit(enemy_plane, (enemy_rect[0], enemy_rect[1]))
# 设置地方飞机每次的偏移量
enemy_rect.move_ip(0, plane_speed) # 敌方飞机目前只能向 y 轴飞
# 设置地方飞机的活动范围
if enemy_rect[1] >= WINDOW_HEIGHT: # 如果地方飞机飞出屏幕区域,从新设置地方飞机的起始位置(地方飞机时随机 x 轴起始位置)
enemy_rect.move_ip(-enemy_rect[0], -enemy_rect[1]) # 将目前飞机的偏移量都减掉,回到首次偏移之前的位置
enemy_rect.move_ip(random.randint(0, WINDOW_WIDTH-enemy_rect[2]), -enemy_rect[3])
# 处理键盘和鼠标的单击事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
game_over()
if event.key == pygame.K_SPACE:
print("发射子弹~~")
if event.key == pygame.K_UP:
if hero_rect[1] > 0:
hero_rect.move_ip(0, -plane_speed)
if event.key == pygame.K_DOWN:
if hero_rect[1] < WINDOW_HEIGHT - hero_rect[3]:
hero_rect.move_ip(0, plane_speed)
if event.key == pygame.K_LEFT:
if hero_rect[0] > 0:
hero_rect.move_ip(-plane_speed, 0)
if event.key == pygame.K_RIGHT:
if hero_rect[0] < WINDOW_WIDTH - hero_rect[2]:
hero_rect.move_ip(plane_speed, 0)
# 处理键盘的持续按下事件
pressed_keys = pygame.key.get_pressed()
if pressed_keys[pygame.K_SPACE] or pressed_keys[pygame.K_j]:
print("持续发射子弹~~")
if pressed_keys[pygame.K_UP]:
if hero_rect[1] > 0:
hero_rect.move_ip(0, -plane_speed)
if pressed_keys[pygame.K_DOWN]:
if hero_rect[1] < WINDOW_HEIGHT - hero_rect[3]:
hero_rect.move_ip(0, plane_speed)
if pressed_keys[pygame.K_LEFT]:
if hero_rect[0] > 0:
hero_rect.move_ip(-plane_speed, 0)
if pressed_keys[pygame.K_RIGHT]:
if hero_rect[0] < WINDOW_WIDTH - hero_rect[2]:
hero_rect.move_ip(plane_speed, 0)
# 显示字体
show_score()
# 刷新窗口
pygame.display.update()
二、使用面向对象的思想进行飞机大战的实现
1、飞机大战的基本游戏窗口
# 导入pygame
import pygame
import sys
# 设置基本的窗口信息
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
# 创建游戏窗口
class GameWindow(object):
def __init__(self):
# 初始化pygame
pygame.init()
# 设置窗口参数
self.window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
# 启动游戏,游戏就是一个大的循环
def run(self):
while True:
# 移动矩形对象
self.active()
# 根据移动过后的矩形对象坐标绘制图片
self.draw()
# 处理点击事件
self.event()
# 重新加载窗口对象
self.update()
# 处理各个矩形对象的坐标移动
def active(self):
pass
# 根据矩形对象的坐标,重新对元素进行绘制
def draw(self):
pass
# 处理键盘点击事件
def event(self):
# 遍历单击事件
for event in pygame.event.get():
# 判断时候时退出操作
if event.type == pygame.QUIT:
self.gameover()
# 判断是否时键盘按下操作
if event.type == pygame.KEYDOWN:
# 如果时ESC键
if event.key == pygame.K_ESCAPE:
self.gameover()
# 如果
# 更新窗口
def update(self):
pygame.display.update()
# 退出游戏
def gameover(self):
pygame.quit()
sys.exit()
# 定义main函数,作为程序运行的入口
def main():
game = GameWindow()
game.run()
if __name__ == "__main__":
main()
2、飞机大战的背景图片添加
# 导入pygame
import pygame
import sys
import random
# 设置基本的窗口信息
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
# 创建地图对象
class GameMap(object):
def __init__(self):
# 初始化地图数据
self.num = str(random.randint(1,5))
self.bg1_image = pygame.image.load("res/img_bg_level_" + self.num + ".jpg")
self.bg2_image = pygame.image.load("res/img_bg_level_" + self.num + ".jpg")
# 设置两张背景图的y轴初始值
self.bg1_y = -WINDOW_HEIGHT
self.bg2_y = 0
# 设置地图滚动速度
self.bg_speed = 1
# 定义地图滚动的方法
def map_scroll(self):
if self.bg1_y >= 0:
self.bg1_y = -WINDOW_HEIGHT
if self.bg2_y >= WINDOW_HEIGHT:
self.bg2_y = 0
self.bg1_y += self.bg_speed
self.bg2_y += self.bg_speed
# 创建游戏窗口
class GameWindow(object):
def __init__(self):
# 初始化pygame
pygame.init()
# 设置窗口参数
self.window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
# 创建地图对象
self.map = GameMap()
# 启动游戏,游戏就是一个大的循环
def run(self):
while True:
# 移动矩形对象
self.active()
# 根据移动过后的矩形对象坐标绘制图片
self.draw()
# 处理点击事件
self.event()
# 重新加载窗口对象
self.update()
# 处理各个矩形对象的坐标移动
def active(self):
self.map.map_scroll()
# 根据矩形对象的坐标,重新对元素进行绘制
def draw(self):
# 绘制背景图
self.window.blit(self.map.bg1_image, (0, self.map.bg1_y))
self.window.blit(self.map.bg2_image, (0, self.map.bg2_y))
# 处理键盘点击事件
def event(self):
# 遍历单击事件
for event in pygame.event.get():
# 判断时候时退出操作
if event.type == pygame.QUIT:
self.gameover()
# 判断是否时键盘按下操作
if event.type == pygame.KEYDOWN:
# 如果时ESC键
if event.key == pygame.K_ESCAPE:
self.gameover()
# 如果
# 更新窗口
def update(self):
pygame.display.update()
# 退出游戏
def gameover(self):
pygame.quit()
sys.exit()
# 定义main函数,作为程序运行的入口
def main():
game = GameWindow()
game.run()
if __name__ == "__main__":
main()
3、英雄飞机的添加和移动
# 导入pygame
import pygame
import sys
import random
# 设置基本的窗口信息
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
"""
创建飞机类
"""
class HeroPlane(object):
def __init__(self):
# 初始化飞机图片
self.hero_plane_image = pygame.image.load("res/hero2.png")
# 获得飞机的矩形对象
self.hero_plane_rect = self.hero_plane_image.get_rect()
# 设置飞机的初始位置
self.hero_plane_rect.move_ip(WINDOW_WIDTH / 2 - self.hero_plane_rect[2] / 2, WINDOW_HEIGHT - self.hero_plane_rect[3])
# 定义飞机移动速度
self.hero_plane_speed = 2
# 定义飞机移动的方法
def move_up(self):
if self.hero_plane_rect[1] > 0:
self.hero_plane_rect.move_ip(0, -self.hero_plane_speed)
def move_down(self):
if self.hero_plane_rect[1] < WINDOW_HEIGHT - self.hero_plane_rect[3]:
self.hero_plane_rect.move_ip(0, self.hero_plane_speed)
def move_left(self):
if self.hero_plane_rect[0] > 0:
self.hero_plane_rect.move_ip(-self.hero_plane_speed, 0)
def move_right(self):
if self.hero_plane_rect[0] < WINDOW_WIDTH - self.hero_plane_rect[2]:
self.hero_plane_rect.move_ip(self.hero_plane_speed, 0)
# 定义发射子弹的方法
def shot(self):
print("发射子弹")
# 创建地图对象
class GameMap(object):
def __init__(self):
# 初始化地图数据
self.num = str(random.randint(1,5))
self.bg1_image = pygame.image.load("res/img_bg_level_" + self.num + ".jpg")
self.bg2_image = pygame.image.load("res/img_bg_level_" + self.num + ".jpg")
# 设置两张背景图的y轴初始值
self.bg1_y = -WINDOW_HEIGHT
self.bg2_y = 0
# 设置地图滚动速度
self.bg_speed = 1
# 定义地图滚动的方法
def map_scroll(self):
if self.bg1_y >= 0:
self.bg1_y = -WINDOW_HEIGHT
if self.bg2_y >= WINDOW_HEIGHT:
self.bg2_y = 0
self.bg1_y += self.bg_speed
self.bg2_y += self.bg_speed
# 创建游戏窗口
class GameWindow(object):
def __init__(self):
# 初始化pygame
pygame.init()
# 设置窗口参数
self.window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
# 创建地图对象
self.map = GameMap()
# 创建英雄飞机对象
self.hero_plane = HeroPlane()
# 启动游戏,游戏就是一个大的循环
def run(self):
while True:
# 移动矩形对象
self.active()
# 根据移动过后的矩形对象坐标绘制图片
self.draw()
# 处理点击事件
self.event()
# 重新加载窗口对象
self.update()
# 处理各个矩形对象的坐标移动
def active(self):
# 让背景图滚动
self.map.map_scroll()
# 根据矩形对象的坐标,重新对元素进行绘制
def draw(self):
# 绘制背景图
self.window.blit(self.map.bg1_image, (0, self.map.bg1_y))
self.window.blit(self.map.bg2_image, (0, self.map.bg2_y))
# 绘制英雄飞机图
self.window.blit(self.hero_plane.hero_plane_image, (self.hero_plane.hero_plane_rect[0], self.hero_plane.hero_plane_rect[1]))
# 处理键盘点击事件
def event(self):
# 遍历单击事件
for event in pygame.event.get():
# 判断是否是退出操作
if event.type == pygame.QUIT:
self.gameover()
# 判断是否是键盘按下操作
if event.type == pygame.KEYDOWN:
# 如果时ESC键
if event.key == pygame.K_ESCAPE:
self.gameover()
# 如果是发射子弹
if event.key == pygame.K_SPACE or event.key == pygame.K_j:
self.hero_plane.shot()
# 获取连续按下事件
pressed_keys = pygame.key.get_pressed()
plane = self.hero_plane
# 判断是什么连续按下事件
if pressed_keys[pygame.K_UP]:
if plane.hero_plane_rect[1] > 0:
plane.hero_plane_rect.move_ip(0, -plane.hero_plane_speed)
if pressed_keys[pygame.K_DOWN]:
if plane.hero_plane_rect[1] < WINDOW_HEIGHT - plane.hero_plane_rect[3]:
plane.hero_plane_rect.move_ip(0, plane.hero_plane_speed)
if pressed_keys[pygame.K_LEFT]:
if plane.hero_plane_rect[0] > 0:
plane.hero_plane_rect.move_ip(-plane.hero_plane_speed, 0)
if pressed_keys[pygame.K_RIGHT]:
if plane.hero_plane_rect[0] < WINDOW_WIDTH - plane.hero_plane_rect[2]:
plane.hero_plane_rect.move_ip(plane.hero_plane_speed, 0)
if pressed_keys[pygame.K_SPACE] or pressed_keys[pygame.K_j]:
self.hero_plane.shot()
# 更新窗口
def update(self):
pygame.display.update()
# 退出游戏
def gameover(self):
pygame.quit()
sys.exit()
# 定义main函数,作为程序运行的入口
def main():
game = GameWindow()
game.run()
if __name__ == "__main__":
main()
4、英雄飞机装备子弹并发射
# 导入pygame
import pygame
import sys
import random
# 设置基本的窗口信息
WINDOW_WIDTH = 512
WINDOW_HEIGHT = 768
"""
创建子弹类
"""
class Bullet(object):
def __init__(self):
# 初始化子弹图片
self.bullet_image = pygame.image.load("res/bullet_10.png")
# 获取子弹矩形对象
self.bullet_rect = self.bullet_image.get_rect()
# 给子弹设置发射状态,True代表已经发射,False代表为发射,默认时Flase
# 如果子弹时为发射状态,不做绘制,不做位置移动计算,也不做碰撞检测
# 如果时发射状态,就做绘制,做位置移动计算,做碰撞检测
self.is_shot = False
# 设置子弹的移动速度
self.bullet_speed = 5
# 子弹移动的方法:子弹发射之后,是x轴不变,y轴一直在减少
def move(self):
self.bullet_rect.move_ip(0, -self.bullet_speed)
# 当子弹超出屏幕范围,状态设置为False
if self.bullet_rect[1] <= -self.bullet_rect[3]:
self.is_shot = False
"""
创建飞机类
"""
class HeroPlane(object):
def __init__(self):
# 初始化飞机图片
self.hero_plane_image = pygame.image.load("res/hero2.png")
# 获得飞机的矩形对象
self.hero_plane_rect = self.hero_plane_image.get_rect()
# 设置飞机的初始位置
self.hero_plane_rect.move_ip(WINDOW_WIDTH / 2 - self.hero_plane_rect[2] / 2, WINDOW_HEIGHT - self.hero_plane_rect[3])
# 定义飞机移动速度
self.hero_plane_speed = 2
# 创建有十发子弹的列表
self.bullet_list = [Bullet() for _ in range(10)]
# 定义飞机移动的方法
def move_up(self):
if self.hero_plane_rect[1] > 0:
self.hero_plane_rect.move_ip(0, -self.hero_plane_speed)
def move_down(self):
if self.hero_plane_rect[1] < WINDOW_HEIGHT - self.hero_plane_rect[3]:
self.hero_plane_rect.move_ip(0, self.hero_plane_speed)
def move_left(self):
if self.hero_plane_rect[0] > 0:
self.hero_plane_rect.move_ip(-self.hero_plane_speed, 0)
def move_right(self):
if self.hero_plane_rect[0] < WINDOW_WIDTH - self.hero_plane_rect[2]:
self.hero_plane_rect.move_ip(self.hero_plane_speed, 0)
# 定义发射子弹的方法,每次只发射一发子弹
def shot(self):
for bullet in self.bullet_list:
# 判断子弹是否时发射状态,如果不是,就取出子弹
if not bullet.is_shot:
# 设置子弹发射时候的 x 轴默认位置
bullet.bullet_rect[0] = self.hero_plane_rect[0] + self.hero_plane_rect[2] / 2 - bullet.bullet_rect[2] / 2
# 设置子弹发射时候的 y 轴默认位置
bullet.bullet_rect[1] = self.hero_plane_rect[1] - bullet.bullet_rect[3] - 3
# 子弹发射之后,修改在单的发射状态
bullet.is_shot = True
# 每次空格只发射一次子弹,发射之后,就停止循环
break
# 创建地图对象
class GameMap(object):
def __init__(self):
# 初始化地图数据
self.num = str(random.randint(1,5))
self.bg1_image = pygame.image.load("res/img_bg_level_" + self.num + ".jpg")
self.bg2_image = pygame.image.load("res/img_bg_level_" + self.num + ".jpg")
# 设置两张背景图的y轴初始值
self.bg1_y = -WINDOW_HEIGHT
self.bg2_y = 0
# 设置地图滚动速度
self.bg_speed = 1
# 定义地图滚动的方法
def map_scroll(self):
if self.bg1_y >= 0:
self.bg1_y = -WINDOW_HEIGHT
if self.bg2_y >= WINDOW_HEIGHT:
self.bg2_y = 0
self.bg1_y += self.bg_speed
self.bg2_y += self.bg_speed
# 创建游戏窗口
class GameWindow(object):
def __init__(self):
# 初始化pygame
pygame.init()
# 设置窗口参数
self.window = pygame.display.set_mode([WINDOW_WIDTH, WINDOW_HEIGHT])
# 创建地图对象
self.map = GameMap()
# 创建英雄飞机对象
self.hero_plane = HeroPlane()
# 启动游戏,游戏就是一个大的循环
def run(self):
while True:
# 移动矩形对象
self.active()
# 根据移动过后的矩形对象坐标绘制图片
self.draw()
# 处理点击事件
self.event()
# 重新加载窗口对象
self.update()
# 处理各个矩形对象的坐标移动
def active(self):
# 让背景图滚动
self.map.map_scroll()
# 遍历英雄飞机类中的子弹列表,如果状态时发射状态,就移动图片
for bullet in self.hero_plane.bullet_list:
if bullet.is_shot:
# 执行子弹移动的方法
bullet.move()
# 根据矩形对象的坐标,重新对元素进行绘制
def draw(self):
# 绘制背景图
self.window.blit(self.map.bg1_image, (0, self.map.bg1_y))
self.window.blit(self.map.bg2_image, (0, self.map.bg2_y))
# 绘制英雄飞机图
self.window.blit(self.hero_plane.hero_plane_image, (self.hero_plane.hero_plane_rect[0], self.hero_plane.hero_plane_rect[1]))
# 绘制子弹图
# 遍历子弹列表,判断子弹是否为发射状态,如果是,就绘制
for bullet in self.hero_plane.bullet_list:
if bullet.is_shot:
# 绘制子弹图片
self.window.blit(bullet.bullet_image, (bullet.bullet_rect[0], bullet.bullet_rect[1]))
# 处理键盘点击事件
def event(self):
# 遍历单击事件
for event in pygame.event.get():
# 判断是否是退出操作
if event.type == pygame.QUIT:
self.gameover()
# 判断是否是键盘按下操作
if event.type == pygame.KEYDOWN:
# 如果时ESC键
if event.key == pygame.K_ESCAPE:
self.gameover()
# 如果是发射子弹
if event.key == pygame.K_SPACE or event.key == pygame.K_j:
self.hero_plane.shot()
# 获取连续按下事件
pressed_keys = pygame.key.get_pressed()
plane = self.hero_plane
# 判断是什么连续按下事件
if pressed_keys[pygame.K_UP]:
if plane.hero_plane_rect[1] > 0:
plane.hero_plane_rect.move_ip(0, -plane.hero_plane_speed)
if pressed_keys[pygame.K_DOWN]:
if plane.hero_plane_rect[1] < WINDOW_HEIGHT - plane.hero_plane_rect[3]:
plane.hero_plane_rect.move_ip(0, plane.hero_plane_speed)
if pressed_keys[pygame.K_LEFT]:
if plane.hero_plane_rect[0] > 0:
plane.hero_plane_rect.move_ip(-plane.hero_plane_speed, 0)
if pressed_keys[pygame.K_RIGHT]:
if plane.hero_plane_rect[0] < WINDOW_WIDTH - plane.hero_plane_rect[2]:
plane.hero_plane_rect.move_ip(plane.hero_plane_speed, 0)
if pressed_keys[pygame.K_SPACE] or pressed_keys[pygame.K_j]:
pass
# 更新窗口
def update(self):
pygame.display.update()
# 退出游戏
def gameover(self):
pygame.quit()
sys.exit()
# 定义main函数,作为程序运行的入口
def main():
game = GameWindow()
game.run()
if __name__ == "__main__":
main()