软件实习项目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(殷越)

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值