《Python飞机大战》项目实战_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1nw411Y75L/
英雄飞机在创建之初,在子弹列表中我们预先创建好30个子弹,这个创建多少个由自己定义。发射子弹的思路是,每次发射三个子弹,从子弹列表中首先选出3颗未发射的子弹,也就是visible=False的子弹,如果子弹列表中都已经发射出去,则本次不发射任何子弹。
子弹在移动出屏幕之后,会自动将自己的状态设置为False状态。
英雄飞机仍然有两个最为重要的action函数和draw函数, draw每一帧循环都会绘制,但是action坐标计算,就需要拖动鼠标时候再重新设置坐标。所以这里需要处理下鼠标拖动事件,我们可以获取上次处理事件和本次处理事件之间的时间内的所有的事件,包括鼠标事件、窗口事件、键盘事件等等,它们都存储在pygame.event.get()返回的列表中,我们依次从列表中取出事件,判断其类型是否是我们要处理的键盘J键按下事件,如果是,则发射子弹,如果是鼠标拖动事件,我们就将鼠标移动位置的坐标作为飞机位置的坐标,重新给飞机设置坐标。
其中,我们还额外添加了一个事件处理,也就是窗口管理事件处理,其类型为pygame.QUIT、键盘按下事件类型为pygame.KEYDOWN、鼠标拖动事件类型为pygame.MOUSEMOTION.
# 飞机
class HeroPlane(object):
# 飞机初始化
def __init__(self, scene):
# 加载飞机资源
self.image = pygame.image.load("./res/hero2.png")
# 缓存主场景对象
self.main_scene = scene
# 飞机矩形
self.rect = self.image.get_rect()
# 矩形起始点
self.rect[0] = self.main_scene.size[0] / 2 - self.rect[2] / 2
self.rect[1] = self.main_scene.size[1] - self.rect[3] * 2
# 飞机子弹列表
self.bullets = [Bullet(self.main_scene) for _ in range(1, 30)]
# 获得飞机 self.mImage = pygame.image.load("./res/bullet_11.png")矩形
def rect(self):
return self.rect
# 发子弹
def shot(self):
# 每次发射三颗子弹
wait_for_shot = []
# 从子弹列表取出3颗目前尚未发射的子弹
# 如果子弹的visible为false,说明子弹尚未发射
for bullet in self.bullets:
# 如果子弹不可见,说明子弹闲置状态
if not bullet.visible:
wait_for_shot.append(bullet)
if len(wait_for_shot) >= 3:
break
# 子弹发射位置,从posx位置开始 向右排列三颗子弹
posx = self.rect[0] - 15
# 依次设置选择子弹的初始位置,并将其设置为发射状态、移动速度
for bullet in wait_for_shot:
bullet.visible = True
posx = posx + 30
bullet.set_speed(4)
bullet.set_pos(posx + 5, self.rect[1] - self.rect[3] / 2)
# 飞机动作
def action(self, x, y):
self.rect[0] = x - self.rect[2] / 2
self.rect[1] = y - self.rect[3] / 2
# 飞机绘制
def draw(self):
self.main_scene.scene.blit(
self.image, (self.rect[0], self.rect[1]))
我们现在将飞机加入到我们的舞台场景中:
# 主场景
class MainScene(object):
# 初始化主场景
def __init__(self):
# 场景尺寸
self.size = (512, 768)
# 场景对象
self.scene = pygame.display.set_mode([self.size[0], self.size[1]])
# 设置标题
pygame.display.set_caption("飞机大战-v1.0")
# 地图对象
self.map = GameBackground(self)
# 英雄对象
self.hero = HeroPlane(self)
# 绘制
def draw_elements(self):
# 绘制地图
self.map.draw()
# 绘制英雄飞机
self.hero.draw()
# 依次绘制英雄飞机每一颗发射出去的子弹
for bullet in self.hero.bullets:
if bullet.visible:
bullet.draw()
# 动作
def action_elements(self):
# 计算坐标地图
self.map.action()
# 依次计算英雄飞机每一颗发射子弹的坐标
for bullet in self.hero.bullets:
if bullet.visible:
bullet.action()
# 处理事件
def handle_event(self):
# 如果玩家点击右上角的X按钮,则关闭窗口
event_list = pygame.event.get()
# 遍历事件列表
for event in event_list:
# 如果判断用户点击了X按钮,则结束程序
if event.type == pygame.QUIT:
pygame.quit()
exit()
# 判断事件类型是否是键盘按下事件
if event.type == pygame.KEYDOWN:
# 如果是键盘按下,再判断玩家按下的是不是j键
if event.key == pygame.K_j:
self.hero.shot()
# 判断是否发生了鼠标拖动事件
if event.type == pygame.MOUSEMOTION:
# 获得鼠标点击三个按钮的点击情况(1,0,0)
# 如果第一个参数为1,表示左键被按下
# 如果第二个参数为1,表示滚轮被按下
# 如果第三个参数为1,表示右键被按下
buttons = pygame.mouse.get_pressed()
# 我们只处理左键被按下的情况
if buttons[0]:
# 获得拖动鼠标的拖动位置
position = pygame.mouse.get_pos()
# 飞机跟随坐标移动
# print(position)
self.hero.action(position[0], position[1])
# 碰撞检测
def detect_conlision(self):
pass
# 主循环,主要处理各种事件
def run_scene(self):
while True:
# 计算元素坐标
self.action_elements()
# 绘制元素图片
self.draw_elements()
# 处理事件
self.handle_event()
# 碰撞检测
self.detect_conlision()
# 刷新显示
pygame.display.update()
# 入口函数
if __name__ == "__main__":
# 创建主场景
mainScene = MainScene()
# 开始游戏
mainScene.run_scene()
这里注意,我们在_init__函数中创建了飞机对象,在draw函数中绘制飞机图片,飞机坐标的计算我们鼠标拖动事件中做计算。绘制飞机子弹时,我们以此从英雄飞机的子弹列表取出每一个子弹对象调用其action函数,计算其坐标,在draw_elements函数中,再次遍历子弹,如果子弹为发射状态则将子弹图片绘制到子弹的位置。
# 绘制
def draw_elements(self):
# 绘制地图
self.map.draw()
# 绘制英雄飞机
self.hero.draw()
# 依次绘制英雄飞机每一颗发射出去的子弹
for bullet in self.hero.bullets:
if bullet.visible:
bullet.draw()
# 动作
def action_elements(self):
# 计算坐标地图
self.map.action()
# 依次计算英雄飞机每一颗发射子弹的坐标
for bullet in self.hero.bullets:
if bullet.visible:
bullet.action()
那么此时运行代码,当我拖动鼠标,飞机会跟随鼠标移动,当我同时按下j键,那么会发射子弹,一次发射三颗,效果为: