全网首份pyQt6飞机大战
该飞机大战具备较为完善的框架
可自动调整飞机与屏幕的位置
具备单点开火,半自动开火,全自动开火三种开火状态
每个作品作者花了不少头发,希望路过的大神多多留言点赞,对于不足的地方可以提出更完善的解决方法,我也会吸取教训,也会继续保持开源精神,奈何作者家境贫寒,需要不断的加班上班来养活自己,没有太多的时间精力去研究更多其他游戏,也欢迎有经济条件的大神也可以请我喝一瓶可乐,感激不尽。下面是飞机大战的图片及源码,图片素材是网上搜集的,如有侵权的请联系删除。


要运行该游戏需要安装python环境 并且在控制台输入pip install pyqt6进行安装环境
使用openGL 驱动需显卡支持
完整包下载地址:点击这里
import random
import sys
import time
from PyQt6 import QtOpenGLWidgets
from PyQt6.QtCore import QTimer, Qt
from PyQt6.QtGui import QPixmap
from PyQt6.QtWidgets import QLabel, QApplication
# 飞机大战主类
class PlaneBigWar(QtOpenGLWidgets.QOpenGLWidget):
"""
控制方式:
子弹发射:
1. 使用鼠标单点发射
2. 使用X半自动发射
3. 使用空格自动发射
# 屏幕宽高,内部部件与飞机位置会随着屏幕大小改变自动改变
screenWidth = 1300
screenHeight = 700
# 初始生命分数
life = 3
score = 0
# 存储子弹与敌人的列表
enemies = []
bullets = []
# 游戏状态控制,初始为开始状态
STATES = {"START": 0, "RUNNING": 1, "PAUSE": 2, "GAME_OVER": 3}
state = STATES["START"]
# 时间间隔静态方法,可提供其他类使用
def isActionTime(lastTime, interval)
"""
# 屏幕宽高,内部部件与飞机位置会随着屏幕大小改变自动改变
screenWidth = 1300
screenHeight = 700
# 初始生命分数
life = 3
score = 0
# 存储子弹与敌人的列表
enemies = []
bullets = []
# 游戏状态控制,初始为开始状态
STATES = {"START": 0, "RUNNING": 1, "PAUSE": 2, "GAME_OVER": 3}
state = STATES["START"]
# 时间间隔静态方法,可提供其他类使用
@staticmethod
def isActionTime(lastTime, interval):
if lastTime == 0:
return True
currentTime = time.time()
return currentTime - lastTime >= interval
# 初始化主类构造器
def __init__(self):
super().__init__()
# 初始化相关变量
self.timer = QTimer(self)
# 初始化UI窗口
self.initUI()
# 入场对象的时间间隔0.5
self.lastTime = 0
self.interval = 0.5
# 与英雄机碰撞的时间间隔0.5
self.hitLastTime = 0
self.hitInterval = 0.5
# 初始化爆炸特效
self.booms = [QPixmap(f"./images/b{i}.png") for i in range(1, 12)]
# 初始化logo图片
logo = QPixmap("./images/LOGO.png")
# 初始化分数牌图片
indicator = QPixmap("./images/score.png")
# 初始化游戏开始提示图片图片
startGame = QPixmap("./images/startGame.png")
# 初始化暂停提示图片
gamePause = QPixmap("./images/game_pause_nor.png")
# 初始化图片提示图片
gameOver = QPixmap("./images/over.png")
# 初始化再来一次提示图片
again = QPixmap("./images/again.png")
# 初始化背景图片
self.bg = QPixmap("./images/bg235.jpg")
# 初始化英雄图片
self.h = QPixmap("./images/hero1.png")
# 初始化子弹图片
self.b = QPixmap("./images/bullet1.png")
# 初始化敌人1图片
self.e1 = QPixmap("./images/enemy1.png")
# 初始化敌人2图片
self.e2 = QPixmap("./images/enemy2.png")
# 初始化敌人3图片
self.e3 = QPixmap("./images/enemy3.png")
# 初始化天空类
self.sky = Sky(self, self.bg)
# 初始化英雄类
self.hero = Hero(self, self.h, self.booms)
# 初始化Logo类(图片)
self.logo = Remind(self, PlaneBigWar.screenWidth // 2 - logo.width() // 2,
PlaneBigWar.screenHeight // 2 - logo.height() // 2, logo)
# 初始化分数牌类(图片)
self.indicator = Remind(self, PlaneBigWar.screenWidth - indicator.width(), 0, indicator)
# 初始化游戏开始类(图片)
self.startGame = Remind(self, PlaneBigWar.screenWidth // 2 - startGame.width() // 2,
PlaneBigWar.screenHeight // 2 + logo.height() // 2 + startGame.height(),
startGame)
# 初始化暂停类(图片)
self.gamePause = Remind(self, PlaneBigWar.screenWidth // 2 - gamePause.width() // 2,
PlaneBigWar.screenHeight // 2 - gamePause.height() // 2, gamePause)
# 初始化游戏结束类(图片)
self.gameOver = Remind(self, PlaneBigWar.screenWidth // 2 - gameOver.width() // 2,
PlaneBigWar.screenHeight // 2 - gameOver.height() // 2, gameOver)
# 初始化再来一次类(图片)
self.again = Remind(self, PlaneBigWar.screenWidth // 2 - again.width() // 2,
PlaneBigWar.screenHeight // 2 + gameOver.height() // 2 + again.height(),
again)
# 初始化生命文字类
self.lifeLabel = Text(self, PlaneBigWar.screenWidth - indicator.width() + 140, 51)
# 初始化分数文字类
self.scoreLabel = Text(self, PlaneBigWar.screenWidth - indicator.width() + 140, 13)
def initUI(self):
"""
初始化UI界面
"""
self.initializeGL()
# 设置窗口大小,并设置不可自动调整大小
self.resize(PlaneBigWar.screenWidth, PlaneBigWar.screenHeight)
self.setFixedSize(PlaneBigWar.screenWidth, PlaneBigWar.screenHeight)
# 设置游戏标题
self.setWindowTitle('飞机大战')
# 设置鼠标可被自动侦测
self.setMouseTracking(True)
# 显示窗口
self.show()
# 初始化定时器自动运行run方法
self.timer.start(10)
self.timer.timeout.connect(self.run)
def run(self):
"""
程序运行体,该方法每10毫秒被调用一次
功能与游戏状态息息相关
"""
self.componentPaint()
# 开始状态
if PlaneBigWar.state == PlaneBigWar.STATES["START"]:
self.logo.img.raise_()
self.startGame.img.raise_()
self.logo.paint()
self.startGame.paint()
# 运行状态
elif PlaneBigWar.state == PlaneBigWar.STATES["RUNNING"]:
self.componentEnter()
self.componentStep()
self.componentHit()
self.componentDelete()
# 暂停状态
elif PlaneBigWar.state == PlaneBigWar.STATES["PAUSE"]:
self.gamePause.paint()
self.gamePause.img.raise_()
# 游戏结束状态
elif PlaneBigWar.state == PlaneBigWar.STATES["GAME_OVER"]:
self.gameOver.paint()
self.again.paint()
self.again.img.raise_()
self.gameOver.img.raise_()
# 判断英雄总生命是否小于1,如果是将游戏状态设置为结束
if PlaneBigWar.life < 1:
PlaneBigWar.state = PlaneBigWar.STATES["GAME_OVER"]
def enterEvent(self, event):
"""
该方法判断鼠标是否移入了程序窗口
如果游戏状态为暂停状态将之恢复为运行状态
"""
if PlaneBigWar.state == PlaneBigWar.STATES["PAUSE"]:
PlaneBigWar.state = PlaneBigWar.STATES["RUNNING"]
self.gamePause.img.hide()
def leaveEvent(self, event):
"""
该方法判断鼠标是否移出了程序窗口
如果游戏状态为运行状态将之设置为暂停状态
"""
if PlaneBigWar.state == PlaneBigWar.STATES["RUNNING"]:
PlaneBigWar.state = PlaneBigWar.STATES["PAUSE"]
def mousePressEvent(self, event):
"""
鼠标点击事件
状态为开始时,点击鼠标设置为运行状态
状态为结束时,点击鼠标
游戏将被初始化为开始状态
游戏运行时,激活单发发射子弹模式
"""
if not self.hero.isDead:
self.hero.shoot()
if PlaneBigWar.state == PlaneBigWar.STATES["START"]:
PlaneBigWar.state = PlaneBigWar.STATES["RUNNING"]
self.logo.img.hide()
self.startGame.img.hide()
elif PlaneBigWar.state == PlaneBigWar.STATES["GAME_OVER"]:
PlaneBigWar.life = 3
PlaneBigWar.score = 0
for enemy in PlaneBigWar.enemies:
enemy.img.hide()
for bullet in PlaneBigWar.bullets:
bullet.img.hide()
PlaneBigWar.enemies = []
PlaneBigWar.bullets = []
self.hero.img.hide()
self.gameOver.img.hide()
self.again.img.hide()
self.hero = Hero(self, self.h, self.booms)
PlaneBigWar.state = PlaneBigWar.STATES["START"]
def keyPressEvent(self, QKeyEvent):
"""
键盘按键事件,按下x键启用半自动模式
按下空格键时,启动自动发射模式
"""
if QKeyEvent.key() == Qt.Key.Key_X:
if not self.hero.isDead:
self.hero.shoot()
if QKeyEvent.key() == Qt.Key.Key_Space:
if self.hero.autoShoot:
self.hero.autoShoot = False
else:
self.hero.autoShoot = True
def mouseMoveEvent(self, event):
"""
鼠标移动事件,活着的英雄机将跟随鼠标移动
"""
if PlaneBigWar.state == PlaneBigWar.STATES["RUNNING"] and not self.hero.isDead:
mousePos = event.position()
pos = (int(mousePos.x()), int(mousePos.y()))
self.hero.step(pos)
def componentPaint(self):
"""
游戏绘制组件,将绘制游戏中显示的图片与文字
"""
self.sky.paint()
self.indicator.paint()
self.indicator.img.raise_()
self.lifeLabel.paint(f"{PlaneBigWar.life}")
self.lifeLabel.label.raise_()
self.scoreLabel.paint(f"{PlaneBigWar.score}")
self.scoreLabel.label.raise_()
self.hero.paint()
for enemy in PlaneBigWar.enemies:
enemy.paint()
for bullet in PlaneBigWar.bullets:
bullet.paint()
def componentHit(self):
"""
游戏碰撞组件,用于检测某个物体与某个物体是否发生碰撞
"""
for enemy in PlaneBigWar.enemies:
if enemy.hit(self.hero):
self.hero.punish()
enemy.punish()
for bullet in PlaneBigWar.bullets:
if bullet.hit(enemy) and (not bullet.isDead or not enemy.isDead):
enemy.punish()
bullet.punish()
def componentEnter(self):
"""
游戏物体入场组件,用于添加对象至游戏
"""
if self.hero.autoShoot and not self.hero.isDead:
self.hero.shoot()
if not PlaneBigWar.isActionTime(self.lastTime, self.interval):
return
self.lastTime = time.time()
num = random.randint(0, 9)
if num < 5:
PlaneBigWar.enemies.append(Enemy(self, 1, 3, 1, self.e1, self.booms, random.randint(4, 5)))
elif num <= 8:
PlaneBigWar.enemies.append(Enemy(self, 2, 7, 5, self.e2, self.booms, random.randint(3, 4)))
elif num == 9:
if PlaneBigWar.enemies.__len__() == 0 or PlaneBigWar.enemies[0].type != 3:
PlaneBigWar.enemies.insert(0, Enemy(self, 3, 10, 30, self.e3, self.booms, random.randint(2, 3)))
def componentDelete(self):
"""
删除组件,将物体状态isDelete为True的对象进行移除
"""
for enemy in PlaneBigWar.enemies:
enemy.isOutBounds()
if enemy.isDelete:
enemy.img.hide()
PlaneBigWar.enemies.remove(enemy)
for bullet in PlaneBigWar.bullets:
bullet.isOutBounds()
if bullet.isDelete:
bullet.img.hide()
PlaneBigWar.bullets.remove(bullet)
if not PlaneBigWar.isActionTime(self.hitLastTime, self.hitInterval):
return
self.hitLastTime = time.time()
if self.hero.life <= 0:
self.hero.img.hide()
if PlaneBigWar.life > 0:
self.hero = Hero(self, self.h, self.booms)
PlaneBigWar.life -= 1
def componentStep(self):
"""
游戏对象移动组件,用于移动游戏中的对象
"""
self.sky.step()
for enemy in PlaneBigWar.enemies:
enemy.step()
for bullet in PlaneBigWar.bullets:
bullet.step()
class Sky(object):
"""
天空类,该类作为游戏的背景,自动创建两张相同的背景从上向下移动
"""
def __init__(self, canvas, img, speed=1):
self.imgLab1 = QLabel(canvas)
self.imgLab1.setPixmap(img)
self.imgLab2 = QLabel(canvas)
self.imgLab2.setPixmap(img)
self.imgLab1.setMouseTracking(True)
self.imgLab2.setMouseTracking(True)
self.imgLab1.lower()
self.imgLab2.lower()
self.speed = speed
self.x = 0
self.y = 0
self.width = img.width()
self.height = img.height()
def paint(self):
self.imgLab1.show()
self.imgLab2.show()
self.imgLab1.move(self.x, self.y % self.height)
self.imgLab2.move(self.x, (self.y - self.height) % self.height - self.height)
def step(self):
if self.y % self.height == 0:
self.y = 0
self.y += self.speed
class FlayingObject(object):
"""
游戏物体父类,所有能被添加到游戏中的物体都继承于此类
"""
def __init__(self, canvas, x, y, life, img, imgs, speed=2):
self.canvas = canvas
self.img = QLabel(canvas)
self.img.setPixmap(img)
self.img.setMouseTracking(True)
self.imgs = imgs
self.x = x
self.y = y
self.life = life
self.speed = speed
self.width = img.width()
self.height = img.height()
self.img.move(self.x, self.y)
self.index = 0
self.hitLastTime = 0
self.hitInterval = 0.5
self.isDead = False
self.isDelete = False
def isOutBounds(self):
"""
越界方法,判断是否超出了屏幕的高度
"""
if self.y > PlaneBigWar.screenHeight:
self.isDelete = True
def hit(self, obj):
"""
碰撞算法,判断两个对象是否发生碰撞5为偏差值,使游戏更自然
"""
x1 = self.x - obj.width + 5
x2 = self.x + self.width - 5
y1 = self.y - obj.height + 5
y2 = self.y + self.height - 5
return x1 <= obj.x <= x2 and y1 <= obj.y <= y2
def paint(self):
"""
绘制自己的方法,如果活着,正常绘制,死了激活动画效果,动画播放完毕激活删除
"""
if self.isDead:
if self.index > self.imgs.__len__() - 1:
self.isDelete = True
if (isinstance(self, Enemy) or isinstance(self, Hero)) and self.index < self.imgs.__len__():
self.img.setPixmap(self.imgs[self.index])
self.img.move(self.x - 20, self.y - 20)
self.img.resize(self.imgs[0].width(), self.imgs[0].height())
self.index += 1
else:
self.img.move(self.x, self.y)
if self.isDelete:
self.img.hide()
else:
self.img.show()
def step(self):
"""
移动方法,但多数子类都是从上向下所以默认从上向下.
有特殊需求重写此方法
"""
self.y += self.speed
def punish(self):
"""
惩罚与奖励方法,调用此方法该对象会获得惩罚,如果敌人获得惩罚,英雄将获得奖励
"""
self.life -= 1
if self.life < 1:
self.isDead = True
if isinstance(self, Enemy):
if not PlaneBigWar.isActionTime(self.hitLastTime, self.hitInterval):
return
self.hitLastTime = time.time()
PlaneBigWar.score += self.score
if isinstance(self, Bullet):
self.isDelete = True
class Hero(FlayingObject):
"""英雄类,具备发生子弹功能"""
def __init__(self, canvas, img, imgs):
FlayingObject.__init__(self, canvas, PlaneBigWar.screenWidth // 2 - img.width() // 2,
int(PlaneBigWar.screenHeight * 0.7), 1, img, imgs)
# 自动射击
self.autoShoot = False
# 射击延迟
self.shootLastTime = 0
self.shootInterval = 0.1
# 子弹类型
self.bulletType = 0
def step(self, pos):
"""
重写父类移动方法,定位至pos的位置
"""
self.x = pos[0] - self.width // 2
self.y = pos[1] - self.height // 2
def shoot(self):
"""
子弹设计方法
bulletType 0: 普通子弹
bulletType 1: 双排子弹
bulletType 2: 散弹
"""
if not PlaneBigWar.isActionTime(self.shootLastTime, self.shootInterval):
return
self.shootLastTime = time.time()
if self.bulletType == 0:
PlaneBigWar.bullets.append(
Bullet(self.canvas, self.x + self.width // 2 - self.canvas.b.width() // 2,
self.y - self.canvas.b.height(), 1, self.canvas.b))
class Enemy(FlayingObject):
"""
敌人类,游戏的敌人对象模板
"""
def __init__(self, canvas, type, life, score, img, speed, imgs: list):
FlayingObject.__init__(self, canvas, random.randint(0, PlaneBigWar.screenWidth - img.width()), -img.height(),
life, img, speed, imgs)
# 敌人类型
self.type = type
# 敌人分数
self.score = score
class Award(FlayingObject):
"""
奖励类,英雄机碰到此物获得奖励
"""
def __init__(self, canvas, type, life, code, img, speed, imgs: list):
FlayingObject.__init__(self, canvas, random.randint(0, PlaneBigWar.screenWidth - img.width()), -img.height(),
life, img, speed, imgs)
# 奖励类型
self.type = type
# 奖品代码
self.code = code
class Bullet(FlayingObject):
"""
子弹类,英雄或敌人可发射用于攻击
"""
def __init__(self, canvas, x, y, life, img, speedX=0, speedY=-20):
FlayingObject.__init__(self, canvas, x, y, life, img, [], speedY)
self.speedX = speedX
def step(self):
"""
子弹移动方法
"""
self.y += self.speed
self.x += self.speedX
def isOutBounds(self):
"""
子弹越界方法
"""
if self.x > PlaneBigWar.screenWidth or self.x < -self.width or self.y > PlaneBigWar.screenHeight or self.y < -self.height:
self.isDelete = True
class Remind(FlayingObject):
"""
提示类,用于显示图片信息的类
"""
def __init__(self, canvas, x, y, img):
FlayingObject.__init__(self, canvas, x, y, 1, img, [])
class Text(FlayingObject):
"""
文本类,用于显示文字
"""
def __init__(self, canvas, x, y, size=30, fontStyle="simhei"):
self.canvas = canvas
self.label = QLabel(canvas)
self.label.resize(75, 30)
self.label.setMouseTracking(True)
self.label.setStyleSheet("QLabel{color:rgba(245,245,245,1);"
"font-size:" + str(size) + "px;"
"font-weight:bold;"
"font-family:" + fontStyle + ";}")
self.x = x
self.y = y
self.label.move(self.x, self.y)
self.width = self.label.width()
self.height = self.label.height()
def paint(self, text):
"""
绘制文字方法
"""
self.label.setText(text)
self.label.move(self.x, self.y)
self.label.show()
# 程序运行入口
if __name__ == "__main__":
app = QApplication(sys.argv)
pbw = PlaneBigWar()
sys.exit(app.exec())
版权声明:本文为u011245132原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。