Python+Qt5实现flappybird
算是对最近一直在看的py和Qt5 for python的一次小实战(当然离不开Siri老师的帮助1551我真是蒟蒻本弱
先写了一个initial interface嘛,打算写完扔github上。
遇到的问题:
1.一开始使用的是QVBoxLayout垂直布局,把QLabel放进垂直布局里,但是出现了类似于margin无法等于0的问题,始终存在外边距(当然尝试了使用QSS设置为0但无卵用),layout也有setmargin的方法但调用了提示参数error(?) 反正后来是改成了现在这样(似乎现在思路清楚但其实是BoxLayout不会用(?)QAQ
2.一个解决游戏界面切换的思路:当前游戏界面hide,目标游戏界面show
3.对于green bar的滚动思路
4.对于鸟飞行状态的图片切换
5.对于buttom两个状态的图片切换:hover,clicked
其实花时间多的主要还是1和3
- main.py
创建一个应用对象,sys.argv提供对脚本控制的功能
# -*- coding:utf-8 -*- """ @author:Kazama @file:main.py @time:2018/9/28 11:03 """ import sys from PyQt5.QtWidgets import QApplication from MainWindow import MainWindow if __name__ == '__main__': app = QApplication([]) mainWindow = MainWindow() sys.exit(app.exec_())
- MainWindow.py
# -*- coding:utf-8 -*- """ @author:Kazama @file:MainWindow.py @time:2018/9/28 11:13 """ from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QMainWindow, QDesktopWidget, QVBoxLayout, QLabel from GameScene import GameScene from MainScene import MainScene from srcImg import srcImg class MainWindow(QMainWindow): def __init__(self): super().__init__() self.srcImg = srcImg() self.initUI() def initUI(self): self.setWindowTitle("Flappy bird") self.setFixedSize(384, 512) self.center()#窗口居中 # self.menuBar() # # self.statusBar() """ centerLabel为什么需要?因为MainWindow只能同时设置一个CentralWidget,如果要重新setCentralWidget, 则将会自动销毁原有的Widget QVBoxLayout可以不用传参:centerLabel,也就是说mainScene可以少修改一个clabel。但是用了它会出现一个边框, 类似于margin!=0 """ self.centerLabel = QLabel()#建个中心标签 self.mainScene = MainScene(self.centerLabel,self)#把MainScene画在centerLabel,MainScene类实例化 self.mainScene.setFixedSize(384, 512)#使窗口大小固定 self.mainScene.move(0,0) self.gameScene=GameScene(self.centerLabel,self) self.gameScene.setFixedSize(384, 512) self.gameScene.move(0, 0) self.gameScene.hide()#游戏中界面切换的思路 self.setCentralWidget(self.centerLabel) # 设置CentralWidget(把centerLabel放进去 self.show() # 展示8 def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def switch2GameScene(self): self.mainScene.hide() self.gameScene.show() def switch2MainScene(self): self.mainScene.show() self.gameScene.hide()
- MainScene.py
# -*- coding:utf-8 -*- """ @author:Kazama @file:MainScene.py @time:2018/9/28 11:31 """ from PyQt5.QtCore import QBasicTimer from PyQt5.QtGui import QPainter from PyQt5.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton class MainScene(QWidget): # MainScene是MainWindow的一个成员,父组件ParentWindow,其实获取的是MainWindow(因为要调用父级的组件) # clabel对应前面传进来的centerLabel #父级init需要传进参数才能init def __init__(self,clabel,ParentWindow): super().__init__(clabel) self.parentWindow=ParentWindow self.timer=QBasicTimer()#控制60帧 self.painter=QPainter()#加图片 self.countTime=0#计数器 self.groundPosition=0#记录grass bar的pos self.initUI() def initUI(self): self.btn_play=QPushButton(self) self.btn_play.move(35,360) self.btn_play.resize(140,78) self.btn_play.setStyleSheet('QPushButton{background:url(data/Picture/other/Again.png);border-radius:10px}'\ 'QPushButton:hover{background:url(data/Picture/other/AgainHover.png);border-radius:10px}'\ 'QPushButton:pressed{background:url(data/Picture/other/AgainPressed.png);border-radius:10px}') self.btn_play.clicked.connect(self.on_btn_play_clicked) self.btn_rank = QPushButton(self) self.btn_rank.move(210, 360) self.btn_rank.resize(140, 78) self.btn_rank.setStyleSheet('QPushButton{background:url(data/Picture/other/Ranking.png);border-radius:10px}'\ 'QPushButton:hover{background:url(data/Picture/other/RankingHover.png);border-radius:10px}' \ 'QPushButton:pressed{background:url(data/Picture/other/RankingPressed.png);border-radius:10px}') self.show() """ paintEvent三种调用情形:1.调用show()2.窗口有变化(属性改变时)3.(前2被动调用,3主动)self.repaint和update() repaint会立即执行,update是向消息循环中加入绘图事件 """ def paintEvent(self, event): self.painter.begin(self) self.rendBackground() self.rendBird() self.painter.end() super().paintEvent(event) def rendBird(self): if self.countTime<15: self.painter.drawPixmap(175, 220, self.parentWindow.srcImg.wingCentered0) elif self.countTime<30: self.painter.drawPixmap(175, 216, self.parentWindow.srcImg.wingUp0) elif self.countTime<45: self.painter.drawPixmap(175, 220, self.parentWindow.srcImg.wingCentered0) else: self.painter.drawPixmap(175, 224, self.parentWindow.srcImg.wingDown0) def rendBackground(self): self.painter.drawPixmap(0,0,self.parentWindow.srcImg.background_dayCopyy)#白天图 self.painter.drawPixmap( self.groundPosition, 448,self.parentWindow.srcImg.ground); self.painter.drawPixmap(self.groundPosition - 384, 448,self.parentWindow.srcImg.ground); def timerEvent(self, event): if event.timerId()==self.timer.timerId(): self.countTime=self.countTime%60+1#60帧 self.update_groundPosition() self.update()#手动刷新,update()是QT默认调用所有的event,然后一直循环 else: super().timerEvent() def update_groundPosition(self): self.groundPosition -= 2 if self.groundPosition <= 0: self.groundPosition = 384 def show(self): self.timer.start(1000/60,self)#1帧=1000/60ms就是60帧 super().show() def hide(self): self.timer.stop() super().hide() def on_btn_play_clicked(self): self.parentWindow.switch2GameScene()