专栏首页Python小二你的童年有俄罗斯方块吗?教你用 Python 实现俄罗斯方块!

你的童年有俄罗斯方块吗?教你用 Python 实现俄罗斯方块!

在那个电子产品比较匮乏的年代,小游戏机

还是为数不多的游戏类电子产品,对小孩子更是有着不可抗拒的魔力,在当时如果哪个小孩买了一个小游戏机,大伙一定迅速围上去...

俄罗斯方块作为其中一款小游戏,尽管规则简单、只有黑白双色,但其对当时游戏玩家的影响丝毫不亚于 LOL、农药、吃鸡对现在游戏玩家的影响,下面我们来看一下如何用 Python 实现俄罗斯方块这款小游戏。

规则

由小方块组成的不同形状的板块陆续从屏幕上方落下来,玩家通过调整板块的位置和方向,使它们在屏幕底部拼出完整的一条或几条。这些完整的横条会随即消失,给新落下来的板块腾出空间,与此同时,玩家得到分数奖励。没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,玩家便告输,游戏结束。 --- 百度百科

环境

  • 操作系统:Windows
  • Python 版本:3.6
  • 涉及模块:sys、random、PyQt5

实现

首先安装第三方模块 PyQt5,使用 pip install PyQt5 即可。

游戏主界面

实现代码

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
class MainBoard(QFrame):
    msg = pyqtSignal(str)
    BoardWidth = 10
    BoardHeight = 22
    Speed = 300
    def __init__(self, parent):
        super().__init__(parent)
        self.initBoard()
    def initBoard(self):
        self.timer = QBasicTimer()
        self.isWaitingAfterLine = False
        self.curX = 0
        self.curY = 0
        self.numLinesRemoved = 0
        self.board = []
        self.setFocusPolicy(Qt.StrongFocus)
        self.isStarted = False
        self.isPaused = False

效果图如下

小板块

定义小版块的形状

class ShapeForm(object):
    NoShape = 0
    ZShape = 1
    SShape = 2
    LineShape = 3
    TShape = 4
    SquareShape = 5
    LShape = 6
    MirroredLShape = 7

class Shape(object):
    coordsTable = (
        ((0, 0),     (0, 0),     (0, 0),     (0, 0)),
        ((0, -1),    (0, 0),     (-1, 0),    (-1, 1)),
        ((0, -1),    (0, 0),     (1, 0),     (1, 1)),
        ((0, -1),    (0, 0),     (0, 1),     (0, 2)),
        ((-1, 0),    (0, 0),     (1, 0),     (0, 1)),
        ((0, 0),     (1, 0),     (0, 1),     (1, 1)),
        ((-1, -1),   (0, -1),    (0, 0),     (0, 1)),
        ((1, -1),    (0, -1),    (0, 0),     (0, 1))
    )

    def __init__(self):
        self.coords = [[0,0] for i in range(4)]
        self.pieceShape = ShapeForm.NoShape
        self.setShape(ShapeForm.NoShape)

画出图形

def drawSquare(self, painter, x, y, shape):
    colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC,
                  0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00]
    color = QColor(colorTable[shape])
    painter.fillRect(x + 1, y + 1, self.squareWidth() - 2,
        self.squareHeight() - 2, color)
    painter.setPen(color.lighter())
    painter.drawLine(x, y + self.squareHeight() - 1, x, y)
    painter.drawLine(x, y, x + self.squareWidth() - 1, y)
    painter.setPen(color.darker())
    painter.drawLine(x + 1, y + self.squareHeight() - 1,
        x + self.squareWidth() - 1, y + self.squareHeight() - 1)
    painter.drawLine(x + self.squareWidth() - 1,
        y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)

效果图如下

按键事件

    def keyPressEvent(self, event):
        if not self.isStarted or self.curPiece.shape() == ShapeForm.NoShape:
            super(MainBoard, self).keyPressEvent(event)
            return
        key = event.key()
        if key == Qt.Key_P:
            self.pause()
            return
        if self.isPaused:
            return
        elif key == Qt.Key_Left:
            self.tryMove(self.curPiece, self.curX - 1, self.curY)
        elif key == Qt.Key_Right:
            self.tryMove(self.curPiece, self.curX + 1, self.curY)
        elif key == Qt.Key_Down:
            self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY)
        elif key == Qt.Key_Up:
            self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY)
        elif key == Qt.Key_Space:
            self.dropDown()
        elif key == Qt.Key_D:
            self.oneLineDown()
        else:
            super(MainBoard, self).keyPressEvent(event)

    def tryMove(self, newPiece, newX, newY):
        for i in range(4):
            x = newX + newPiece.x(i)
            y = newY - newPiece.y(i)
            if x < 0 or x >= MainBoard.BoardWidth or y < 0 or y >= MainBoard.BoardHeight:
                return False
            if self.shapeAt(x, y) != ShapeForm.NoShape:
                return False
        self.curPiece = newPiece
        self.curX = newX
        self.curY = newY
        self.update()
        return True

计时器事件

def timerEvent(self, event):
    if event.timerId() == self.timer.timerId():
        if self.isWaitingAfterLine:
            self.isWaitingAfterLine = False
            self.newPiece()
        else:
            self.oneLineDown()
    else:
        super(MainBoard, self).timerEvent(event)

开始和暂停

    def start(self):
        if self.isPaused:
            return
        self.isStarted = True
        self.isWaitingAfterLine = False
        self.numLinesRemoved = 0
        self.clearBoard()
        self.msg.emit(str(self.numLinesRemoved))
        self.newPiece()
        self.timer.start(MainBoard.Speed, self)

    def pause(self):
        if not self.isStarted:
            return
        self.isPaused = not self.isPaused
        if self.isPaused:
            self.timer.stop()
            self.msg.emit("paused")
        else:
            self.timer.start(MainBoard.Speed, self)
            self.msg.emit(str(self.numLinesRemoved))
        self.update()

游戏类及初始化

class Tetris(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.tboard = MainBoard(self)
        self.setCentralWidget(self.tboard)
        self.statusbar = self.statusBar()
        self.tboard.msg[str].connect(self.statusbar.showMessage)
        self.tboard.start()
        self.resize(300, 500)
        self.center()
        self.setWindowTitle('俄罗斯方块')
        self.show()

    def center(self):
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2,
            (screen.height()-size.height())/2)

启动

if __name__ == '__main__':
    app = QApplication([])
    tetris = Tetris()
    sys.exit(app.exec_())

最终效果

打包

为了方便运行,我们将 Python 文件打成 exe 文件,用到的插件为 pyinstaller。

首先,安装 pyinstaller,使用 pip install pyinstaller 即可。安装完成后,在文件目录

打开命令窗口,在命令窗口执行命令 pyinstaller --onefile --nowindowed --icon="C:\Users\LE\Desktop\tetris\tetris.ico" tetris.py 即可。执行完成后,我们到 dist 目录下

即可找到生成的 exe 文件。

本文分享自微信公众号 - Python小二(chengxuzhijian),作者:程序员野客

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 用 Python 实现一场环保无污染的烟花秀

    烟花由中国古代人民较早发明,常用于盛大的典礼或表演中,也在除夕夜及元宵节中燃放用来烘托节日氛围。近年来随着环境污染的加剧,一些地区已经禁止燃放烟花了,那我们就用...

    Python小二
  • 5 分钟教你用 Python 实现贪吃蛇!

    贪吃蛇作为一款经典小游戏,早在 1976 年就面世了,我最早接触它还是在家长的诺基亚手机中。

    Python小二
  • 经典 90 坦克大战 Python 版实现(支持单双人模式)

    坦克大战是一个比较经典的小游戏,而 90 坦克大战是一个比较经典的版本,我们来看一下如何利用 Python 实现坦克大战,先睹为快。

    Python小二
  • PyQt5 内嵌浏览器注入 Javas

    应同学邀请,演示如何使用 PyQt5 内嵌浏览器浏览网页,并注入 Javascript 脚本实现自动化操作。

    py3study
  • python实现队列

    队列是一种先进先出的数据类型,它的跟踪原理类似于在超市收银处排队,队列里的的第一个人首先接受服务,新的元素通过入队的方式添加到队列的末尾,而出队就是将队列的头元...

    一墨编程学习
  • pyqt5实现浏览器与下载文件弹框

    本文由腾讯云+社区自动同步,原文地址 https://stackoverflow.club/article/pyqt5_webbrowser_download_...

    羽翰尘
  • PyQt5 动画类--跳舞的火柴人

    PyQt5.QtCore中的 QPropertyAnimation可以实现动画功能。

    用户6021899
  • 商业篇 | 使用python开发性格分析工具卖钱

    如此不均衡的贫富差距,各行业的领导者如何能管理好公司,让员工们即努力产出,又能安于现状呢?每个领导者必学的一门课程就是职场心理学。只有你充分了解员工心理与对应的...

    叫我龙总
  • 手把手教你使用Python打造一个智能搜索淘宝商品,生成操作日志的系统

    随着网购的兴起,使得很多传统店铺转型做线上生意,电子商务的产生极大便利了我们的生活。

    Python进阶者
  • unslider源码分析

    根据Bootstrap中文网的介绍,Unslider一个超小的 jQuery轮播(slider)插件,参照这个汉化版的介绍页面,这个插件有你需要的优点,但是本...

    用户3579639

扫码关注云+社区

领取腾讯云代金券