软件实习项目2——贪吃喵(猫吃鱼版贪吃蛇)(代码实现)
类变量的定义以及类的初始化__init__
class CatWindow(QWidget):
row = 0 # 行数
column = 0 # 列数
direction = 0 # 猫头方向
head_row = 0 # 猫头的行
head_column = 0 # 猫头的列
head_position = '' # 猫头位置
coordinate = [] # 猫头和鱼骨的位置列表
fish_row = 0 # 鱼的行
fish_column = 0 # 鱼的列
fish_position = '' # 鱼的位置
score = 0 # 计分
# 速度默认值为500
speed = 500
# 猫咪类型默认值是英短蓝白
head_pic = 'head.png'
dead_pic = 'dead.png'
# 设置几个字体
font1 = QtGui.QFont("Calibri", 20)
font2 = QtGui.QFont("Calibri", 15)
font3 = QtGui.QFont("Calibri", 13)
font4 = QtGui.QFont("幼圆", 20)
font5 = QtGui.QFont("幼圆", 13)
# 所有按钮都按照这个样式
buttons_style = "QPushButton{background-color: rgb(255, 255, 255); border-radius:10px}" \
"QPushButton:hover{Background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 #cdced1, stop:1 #f6f7fa);}" \
"QPushButton:pressed{Background-color:qlineargradient(x1:0,y1:0,x2:0,y2:1,stop:0 #f6f7fa, stop:1 #cdced1);}"
# 初始化
def __init__(self):
QWidget.__init__(self)
self.setWindowTitle('贪吃喵') # 窗口标题
self.setStyleSheet('background-color:#deebf7') # 游戏背景颜色
self.setWindowIcon(QIcon('head.png')) # 设置窗口图标
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid") # 任务栏图标
self.resize(850, 850) # 游戏窗口大小
self.row = 12 # 行数
self.column = 12 # 列数
pygame.mixer.init() # 初始化背景音乐
self.GameStart()
self.windowButton()
self.timer = QTimer() # 计时器
self.timer.start(self.speed) # 开始计时
self.timer.timeout.connect(self.moveCat) # 超时即调用moveCat方法
一、游戏的逻辑
1、猫头的生成
# 随机生成猫头位置
def head(self):
self.backgroundMuisc()
self.score = 0 # 分数清零
self.coordinate.clear() # 坐标清空
self.head_row = random.randint(2, self.row - 2) # 随机选取猫头的行
self.head_column = random.randint(1, self.column - 2) # 随机选取猫头的列
self.coordinate = [str(self.head_row) + "," + str(self.head_column)] # 把猫头位置写入坐标列表中
self.fish() # 调用生成鱼的函数
self.direction = random.randrange(0, 4) # 随机选择方向
self.update()
2、鱼的生成
# 生成鱼的位置
def fish(self):
while True:
self.fish_row = random.randint(1, self.row - 1) # 随机选取鱼的行
self.fish_column = random.randint(0, self.column - 1) # 随机选取鱼的列
self.fish_position = str(self.fish_row) + "," + str(self.fish_column)
# 若随机生成的鱼的位置不在猫头和鱼骨的坐标列表中,则返回鱼的位置,否则重新生成
if self.fish_position not in self.coordinate:
return self.fish_position # 返回鱼的位置
3、猫头和鱼骨的移动
# QTimer的timeout触发的方法
def moveCat(self):
if self.direction == 0:
self.head_row -= 1 # 猫头的行数-1
elif self.direction == 1:
self.head_row += 1 # 猫头的行数+1
elif self.direction == 2:
self.head_column -= 1 # 猫头的列数-1
elif self.direction == 3:
self.head_column += 1 # 猫头的列数+1
# 猫头位置
self.head_position = str(self.head_row) + "," + str(self.head_column)
# 1、若吃到鱼了
if self.head_position == self.fish_position:
self.coordinate.insert(0, self.head_position) # 鱼骨位置不变,在列表最前面插入猫头位置
self.score += 10 # 每吃到一条鱼就加10分
self.fish() # 生成鱼
# 2、若没吃到鱼
else:
# 若猫头和鱼骨没有相撞且猫头没有出界
if 1 <= self.head_row < self.row and 0 <= self.head_column < self.column and self.head_position not in self.coordinate[1:]:
# 1)移动所有鱼骨
for i in range(len(self.coordinate) - 1, 0, -1): # range函数的参数(start, stop, step)
self.coordinate[i] = self.coordinate[i - 1] # 所有坐标等于它的前一个坐标(往前一个移动)
# 2)更新猫头位置
self.coordinate[0] = self.head_position
# 若猫头和鱼骨相撞或猫头出界,则游戏结束
else:
self.GameOver(True)
return
self.update()
4、按下键盘,改变方向
# 按下键盘,改变方向
def keyPressEvent(self, event):
QWidget.keyPressEvent(self, event)
key = event.key()
# 1、按了↑
if key == Qt.Key_W:
self.direction = 0
# 2、按了↓
elif key == Qt.Key_S:
self.direction = 1
# 3、按了←
elif key == Qt.Key_A:
self.direction = 2
# 4、按了→
elif key == Qt.Key_D:
self.direction = 3
二、主窗口的绘制
# 绘制主窗口中的所有物体
def paintEvent(self, event):
QWidget.paintEvent(self, event)
painter = QPainter(self)
row_space = self.height() / self.row # 行间距
column_space = self.width() / self.column # 列间距
# 显示背景图片
painter.drawImage(QRectF(0, 0, self.width(), self.height()), QImage('bg.jpg'))
# 绘制行线和列线
pen = QPen(QColor(255, 255, 255), 1, Qt.DotLine) # 画笔颜色、粗细、线型
painter.setPen(pen)
for n in range(self.row + 1):
painter.drawLine(QPointF(0, row_space * n), QPointF(self.width(), row_space * n))
for n in range(self.column + 1):
painter.drawLine(QPointF(column_space * n, column_space), QPointF(column_space * n, self.height()))
# 显示分数
text_painter = QPainter(self)
text_pen = QPen(QColor(0, 0, 0)) # 画笔颜色、粗细、线型
text_painter.setPen(text_pen)
text_painter.setFont(self.font1)
text_painter.drawText(350, 50, 'Score: ' + str(self.score))
# 画猫头、鱼骨、鱼
index = 0 # 记录coordinate的索引,为0时画猫头,大于0时画鱼骨
for n in self.coordinate:
row = int(n[:n.find(',')])
column = int(n[n.find(',') + 1:])
# 若猫头没出界且没有与鱼骨相撞,画猫头和鱼骨
if 1 <= self.head_row < self.row and 0 <= self.head_column < self.column and self.head_position not in self.coordinate[
1:]:
# 猫头
if index == 0:
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage(self.head_pic))
# 画鱼骨
else:
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('bone.png'))
index += 1
# 若猫头出界了或与鱼骨相撞,画死亡猫头和鱼骨
else:
# 猫头
if index == 0:
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage(self.dead_pic))
# 画鱼骨
else:
painter.drawImage(QRectF(column * column_space, row * row_space, column_space, row_space),
QImage('bone.png'))
index += 1
# 画鱼
painter.drawImage(QRectF(self.fish_column * column_space, self.fish_row * row_space, column_space, row_space),
QImage('fish.png'))
三、游戏开始与结束界面,以及主窗口的按钮
1、开始游戏
# 开始游戏
def GameStart(self):
# 消息框的大小和样式
message_box = QMessageBox()
message_box.setStyleSheet('width: 500; height: 70')
message_box.setWindowTitle('WELCOME')
message_box.setFont(self.font4)
message_box.setText("欢迎来到贪吃喵🐱")
message_box.setWindowIcon(QIcon('head.png')) # 设置消息框图标
message_box.setStyleSheet('background-color:#deebf7')
# click to start按钮
message_box.setStandardButtons(QMessageBox.Yes)
yes = message_box.button(QMessageBox.Yes)
yes.setText("Click to Start")
yes.setFont(self.font2)
yes.setStyleSheet(self.buttons_style)
# 下拉框速度选项
items = ['Speed:', 'Low', 'Middle', 'High']
cb = QComboBox(message_box)
cb.addItems(items) # 添加下拉框选项
cb.setGeometry(400, 5, 120, 40)
cb.setFont(self.font3)
cb.setStyleSheet('background-color: rgb(255, 255, 255); border-radius:10px')
cb.currentIndexChanged.connect(self.speedChanging) # 下拉框选项改变即触发
self.speedChanging(cb.currentIndex()) # 将下拉框此时的选项索引传递给speedChanging函数
# 下拉框猫咪选项
items = ['喵喵:', '英短蓝白', '银渐层', '橘猫', '奶牛猫', '三花猫']
cb1 = QComboBox(message_box)
cb1.addItems(items) # 添加下拉框选项
cb1.setGeometry(400, 50, 120, 40)
cb1.setFont(self.font5)
cb1.setStyleSheet('background-color: rgb(255, 255, 255); border-radius:10px')
cb1.currentIndexChanged.connect(self.catChoosing) # 下拉框选项改变即触发
self.catChoosing(cb1.currentIndex()) # 将下拉框此时的选项索引传递给speedChanging函数
# 退出游戏开始消息框,进入游戏主界面
message_box.exec()
self.show()
self.backgroundMuisc() # 调出背景音乐
self.head()
2、游戏速度设置
# GameStart方法中下拉框选项改变时调用的槽函数,用来设置速度
def speedChanging(self, index):
if index == 1:
self.speed = 500
elif index == 2:
self.speed = 300
elif index == 3:
self.speed = 200
3、猫咪选项设置
# GameStart方法中猫咪下拉框选项改变时调用的槽函数,用来选择自己喜欢的猫咪
def catChoosing(self, index):
if index == 1:
self.head_pic = 'head.png'
self.dead_pic = 'dead.png'
elif index == 2:
self.head_pic = 'head1.png'
self.dead_pic = 'dead1.png'
elif index == 3:
self.head_pic = 'head2.png'
self.dead_pic = 'dead2.png'
elif index == 4:
self.head_pic = 'head3.png'
self.dead_pic = 'dead3.png'
elif index == 5:
self.head_pic = 'head4.png'
self.dead_pic = 'dead4.png'
4、结束游戏
# 结束游戏
def GameOver(self, gameover):
pygame.mixer.music.stop()
message_box = QMessageBox()
message_box.setStyleSheet('width: 300; height: 70')
message_box.setWindowTitle('END')
message_box.setFont(self.font1)
message_box.setWindowIcon(QIcon('head.png')) # 设置消息框图标
message_box.setWindowOpacity(0.75) # 透明度
if gameover:
message_box.setText("Game Over! Your Score: " + str(self.score))
else:
message_box.setText("YOU WIN! Your Score: " + str(self.score))
# 设置游戏结束消息框的两个按钮
message_box.setStandardButtons(QMessageBox.Retry | QMessageBox.Abort)
retry = message_box.button(QMessageBox.Retry)
retry.setText("Retry")
retry.setFont(self.font2)
retry.setStyleSheet(self.buttons_style)
abort = message_box.button(QMessageBox.Abort)
abort.setText("Exit")
abort.setFont(self.font2)
abort.setStyleSheet(self.buttons_style)
abort.clicked.connect(QCoreApplication.instance().quit) # 点击此按钮则退出程序
message_box.exec()
self.head()
5、窗口中的按钮:暂停/开始、重来/退出
# 窗口中的按钮:暂停/开始、重来/退出
def windowButton(self):
# 暂停
pause = QPushButton(self)
pause.setGeometry(10, 10, 100, 50)
pause.setText('Pause')
pause.setFont(self.font3)
pause.setStyleSheet(self.buttons_style)
pause.show()
pause.clicked.connect(self.windowPause) # 点击暂停按钮则触发windowPause方法
# 继续
start = QPushButton(self)
start.setGeometry(120, 10, 120, 50)
start.setText('Continue')
start.setFont(self.font3)
start.setStyleSheet(self.buttons_style)
start.show()
start.clicked.connect(self.windowContinue) # 点击继续按钮则触发windowContinue方法
# 退出
exit_button = QPushButton(self)
exit_button.setGeometry(740, 10, 100, 50)
exit_button.setText('Exit')
exit_button.setFont(self.font3)
exit_button.setStyleSheet(self.buttons_style)
exit_button.show()
exit_button.clicked.connect(QCoreApplication.instance().quit) # 点击退出按钮则退出程序
# 重新开始
restart_button = QPushButton(self)
restart_button.setGeometry(630, 10, 100, 50)
restart_button.setText('Restart')
restart_button.setFont(self.font3)
restart_button.setStyleSheet(self.buttons_style)
restart_button.show()
restart_button.clicked.connect(self.head) # 点击重新开始则重新生成猫头,游戏重新开始
# 按下暂停按钮后调用的方法
def windowPause(self):
self.timer.stop() # 计时器暂停计时
pygame.mixer.music.pause() # 暂停播放音乐
self.update()
# 按下继续按钮后调用的方法
def windowContinue(self):
self.timer.start() # 计时器重新开始计时
pygame.mixer.music.unpause()
self.update()
四、游戏背景音乐
# 背景音乐
def backgroundMuisc(self):
pygame.mixer.music.load("bgmusic.mp3")
pygame.mixer.music.set_volume(0.3) # 设置音量
pygame.mixer.music.play(-1) # 循环播放
——2020/12/16(殷越)