俄罗斯方块游戏代码

简介: 俄罗斯方块游戏代码

一.什么是python

Python由荷兰数学计算机科学研究学会的吉多·范罗苏姆于1990年代初设计,作为一门叫做ABC语言的替代品。   Python提供了高效的高级数据结构,还能简单有效地面向对象编程。Python语法和动态类型,以及解释型语言的本质,使它成为多数平台上写脚本和快速开发应用的编程语言, [ 随着版本的不断更新和语言新功能的添加,逐渐被用于独立的、大型项目的开发。

Python解释器易于扩展,可以使用C语言C++(或者其他可以通过C调用的语言)扩展新的功能和数据类型。Python也可用于可定制化软件中的扩展程序语言。Python丰富的标准库,提供了适用于各个主要系统平台的源码机器码

二.游戏代码效果呈现

e17e61e1799a4dc287bb8e6dbd1cfa41.png

三.游戏主代码

'''


'''

import os

import sys

import random

from modules import *

from PyQt5.QtGui import *

from PyQt5.QtCore import *

from PyQt5.QtWidgets import *



'''定义俄罗斯方块游戏类'''

class TetrisGame(QMainWindow):

   def __init__(self, parent=None):

       super(TetrisGame, self).__init__(parent)

       # 是否暂停ing

       self.is_paused = False

       # 是否开始ing

       self.is_started = False

       self.initUI()

   '''界面初始化'''

   def initUI(self):

       # icon

       self.setWindowIcon(QIcon(os.path.join(os.getcwd(), 'resources/icon.jpg')))

       # 块大小

       self.grid_size = 22

       # 游戏帧率

       self.fps = 200

       self.timer = QBasicTimer()

       # 焦点

       self.setFocusPolicy(Qt.StrongFocus)

       # 水平布局

       layout_horizontal = QHBoxLayout()

       self.inner_board = InnerBoard()

       self.external_board = ExternalBoard(self, self.grid_size, self.inner_board)

       layout_horizontal.addWidget(self.external_board)

       self.side_panel = SidePanel(self, self.grid_size, self.inner_board)

       layout_horizontal.addWidget(self.side_panel)

       self.status_bar = self.statusBar()

       self.external_board.score_signal[str].connect(self.status_bar.showMessage)

       self.start()

       self.center()

       self.setWindowTitle('俄罗斯方块儿 —— 源码基地:959755565')

       self.show()

       self.setFixedSize(self.external_board.width() + self.side_panel.width(), self.side_panel.height() + self.status_bar.height())

   '''游戏界面移动到屏幕中间'''

   def center(self):

       screen = QDesktopWidget().screenGeometry()

       size = self.geometry()

       self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2)

   '''更新界面'''

   def updateWindow(self):

       self.external_board.updateData()

       self.side_panel.updateData()

       self.update()

   '''开始'''

   def start(self):

       if self.is_started:

           return

       self.is_started = True

       self.inner_board.createNewTetris()

       self.timer.start(self.fps, self)

   '''暂停/不暂停'''

   def pause(self):

       if not self.is_started:

           return

       self.is_paused = not self.is_paused

       if self.is_paused:

           self.timer.stop()

           self.external_board.score_signal.emit('Paused')

       else:

           self.timer.start(self.fps, self)

       self.updateWindow()

   '''计时器事件'''

   def timerEvent(self, event):

       if event.timerId() == self.timer.timerId():

           removed_lines = self.inner_board.moveDown()

           self.external_board.score += removed_lines

           self.updateWindow()

       else:

           super(TetrisGame, self).timerEvent(event)

   '''按键事件'''

   def keyPressEvent(self, event):

       if not self.is_started or self.inner_board.current_tetris == tetrisShape().shape_empty:

           super(TetrisGame, self).keyPressEvent(event)

           return

       key = event.key()

       # P键暂停

       if key == Qt.Key_P:

           self.pause()

           return

       if self.is_paused:

           return

       # 向左

       elif key == Qt.Key_Left:

           self.inner_board.moveLeft()

       # 向右

       elif key == Qt.Key_Right:

           self.inner_board.moveRight()

       # 旋转

       elif key == Qt.Key_Up:

           self.inner_board.rotateAnticlockwise()

       # 快速坠落

       elif key == Qt.Key_Space:

           self.external_board.score += self.inner_board.dropDown()

       else:

           super(TetrisGame, self).keyPressEvent(event)

       self.updateWindow()



'''run'''

if __name__ == '__main__':

   app = QApplication([])

   tetris = TetrisGame()

   sys.exit(app.exec_())


三.游戏主代码二

1.shapes

'''

Function:

   定义俄罗斯方块的形状


'''

'''定义一个俄罗斯方块的形状'''

class tetrisShape():

   def __init__(self, shape=0):

       # 空块

       self.shape_empty = 0

       # 一字型块

       self.shape_I = 1

       # L型块

       self.shape_L = 2

       # 向左的L型块

       self.shape_J = 3

       # T型块

       self.shape_T = 4

       # 田字型块

       self.shape_O = 5

       # 反向Z型块

       self.shape_S = 6

       # Z型块

       self.shape_Z = 7

       # 每种块包含的四个小方块相对坐标分布

       self.shapes_relative_coords = [

           [[0, 0], [0, 0], [0, 0], [0, 0]],

           [[0, -1], [0, 0], [0, 1], [0, 2]],

           [[0, -1], [0, 0], [0, 1], [1, 1]],

           [[0, -1], [0, 0], [0, 1], [-1, 1]],

           [[0, -1], [0, 0], [0, 1], [1, 0]],

           [[0, 0], [0, -1], [1, 0], [1, -1]],

           [[0, 0], [0, -1], [-1, 0], [1, -1]],

           [[0, 0], [0, -1], [1, 0], [-1, -1]]

       ]

       self.shape = shape

       self.relative_coords = self.shapes_relative_coords[self.shape]

   '''获得该形状当前旋转状态的四个小方块的相对坐标分布'''

   def getRotatedRelativeCoords(self, direction):

       # 初始分布

       if direction == 0 or self.shape == self.shape_O:

           return self.relative_coords

       # 逆时针旋转90度

       if direction == 1:

           return [[-y, x] for x, y in self.relative_coords]

       # 逆时针旋转180度

       if direction == 2:

           if self.shape in [self.shape_I, self.shape_Z, self.shape_S]:

               return self.relative_coords

           else:

               return [[-x, -y] for x, y in self.relative_coords]

       # 逆时针旋转270度

       if direction == 3:

           if self.shape in [self.shape_I, self.shape_Z, self.shape_S]:

               return [[-y, x] for x, y in self.relative_coords]

           else:

               return [[y, -x] for x, y in self.relative_coords]

   '''获得该俄罗斯方块的各个小块绝对坐标'''

   def getAbsoluteCoords(self, direction, x, y):

       return [[x + i, y + j] for i, j in self.getRotatedRelativeCoords(direction)]

   '''获得相对坐标的边界'''

   def getRelativeBoundary(self, direction):

       relative_coords_now = self.getRotatedRelativeCoords(direction)

       xs = [i[0] for i in relative_coords_now]

       ys = [i[1] for i in relative_coords_now]

       return min(xs), max(xs), min(ys), max(ys)

2.misc


'''

Function:

   其他工具函数


'''

from PyQt5.QtGui import *



'''给板块的一个Cell填色'''

def drawCell(painter, x, y, shape, grid_size):

   colors = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00]

   if shape == 0:

       return

   color = QColor(colors[shape])

   painter.fillRect(x + 1, y + 1, grid_size - 2, grid_size - 2, color)

   painter.setPen(color.lighter())

   painter.drawLine(x, y + grid_size - 1, x, y)

   painter.drawLine(x, y, x + grid_size - 1, y)

   painter.setPen(color.darker())

   painter.drawLine(x + 1, y + grid_size - 1, x + grid_size - 1, y + grid_size - 1)

   painter.drawLine(x + grid_size - 1, y + grid_size - 1, x + grid_size - 1, y + 1)

3.gameboard

'''
Function:
'''
import random
from .misc import *
from .shapes import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QFrame
'''内部板块'''
class InnerBoard():
    def __init__(self, width=10, height=22):
        # 宽和长, 单位长度为小方块边长
        self.width = width
        self.height = height
        self.reset()
    '''判断当前俄罗斯方块是否可以移动到某位置'''
    def ableMove(self, coord, direction=None):
        assert len(coord) == 2
        if direction is None:
            direction = self.current_direction
        for x, y in self.current_tetris.getAbsoluteCoords(direction, coord[0], coord[1]):
            # 超出边界
            if x >= self.width or x < 0 or y >= self.height or y < 0:
                return False
            # 该位置有俄罗斯方块了
            if self.getCoordValue([x, y]) > 0:
                return False
        return True
    '''向右移动'''
    def moveRight(self):
        if self.ableMove([self.current_coord[0] + 1, self.current_coord[1]]):
            self.current_coord[0] += 1
    '''向左移动'''
    def moveLeft(self):
        if self.ableMove([self.current_coord[0] - 1, self.current_coord[1]]):
            self.current_coord[0] -= 1
    '''顺时针转'''
    def rotateClockwise(self):
        if self.ableMove(self.current_coord, (self.current_direction - 1) % 4):
            self.current_direction = (self.current_direction-1) % 4
    '''逆时针转'''
    def rotateAnticlockwise(self):
        if self.ableMove(self.current_coord, (self.current_direction + 1) % 4):
            self.current_direction = (self.current_direction+1) % 4
    '''向下移动'''
    def moveDown(self):
        removed_lines = 0
        if self.ableMove([self.current_coord[0], self.current_coord[1] + 1]):
            self.current_coord[1] += 1
        else:
            x_min, x_max, y_min, y_max = self.current_tetris.getRelativeBoundary(self.current_direction)
            # 简单起见, 有超出屏幕就判定游戏结束
            if self.current_coord[1] + y_min < 0:
                self.is_gameover = True
                return removed_lines
            self.mergeTetris()
            removed_lines = self.removeFullLines()
            self.createNewTetris()
        return removed_lines
    '''坠落'''
    def dropDown(self):
        removed_lines = 0
        while self.ableMove([self.current_coord[0], self.current_coord[1] + 1]):
            self.current_coord[1] += 1
        x_min, x_max, y_min, y_max = self.current_tetris.getRelativeBoundary(self.current_direction)
        # 简单起见, 有超出屏幕就判定游戏结束
        if self.current_coord[1] + y_min < 0:
            self.is_gameover = True
            return removed_lines
        self.mergeTetris()
        removed_lines = self.removeFullLines()
        self.createNewTetris()
        return removed_lines
    '''合并俄罗斯方块(最下面定型不能再动的那些)'''
    def mergeTetris(self):
        for x, y in self.current_tetris.getAbsoluteCoords(self.current_direction, self.current_coord[0], self.current_coord[1]):
            self.board_data[x + y * self.width] = self.current_tetris.shape
        self.current_coord = [-1, -1]
        self.current_direction = 0
        self.current_tetris = tetrisShape()
    '''移出整行都有小方块的'''
    def removeFullLines(self):
        new_board_data = [0] * self.width * self.height
        new_y = self.height - 1
        removed_lines = 0
        for y in range(self.height - 1, -1, -1):
            cell_count = sum([1 if self.board_data[x + y * self.width] > 0 else 0 for x in range(self.width)])
            if cell_count < self.width:
                for x in range(self.width):
                    new_board_data[x + new_y * self.width] = self.board_data[x + y * self.width]
                new_y -= 1
            else:
                removed_lines += 1
        self.board_data = new_board_data
        return removed_lines
    '''创建新的俄罗斯方块(即将next_tetris变为current_tetris)'''
    def createNewTetris(self):
        x_min, x_max, y_min, y_max = self.next_tetris.getRelativeBoundary(0)
        # y_min肯定是-1
        if self.ableMove([self.init_x, -y_min]):
            self.current_coord = [self.init_x, -y_min]
            self.current_tetris = self.next_tetris
            self.next_tetris = self.getNextTetris()
        else:
            self.is_gameover = True
        self.shape_statistics[self.current_tetris.shape] += 1
    '''获得下个俄罗斯方块'''
    def getNextTetris(self):
        return tetrisShape(random.randint(1, 7))
    '''获得板块数据'''
    def getBoardData(self):
        return self.board_data
    '''获得板块数据上某坐标的值'''
    def getCoordValue(self, coord):
        return self.board_data[coord[0] + coord[1] * self.width]
    '''获得俄罗斯方块各个小块的绝对坐标'''
    def getCurrentTetrisCoords(self):
        return self.current_tetris.getAbsoluteCoords(self.current_direction, self.current_coord[0], self.current_coord[1])
    '''重置'''
    def reset(self):
        # 记录板块数据
        self.board_data = [0] * self.width * self.height
        # 当前俄罗斯方块的旋转状态
        self.current_direction = 0
        # 当前俄罗斯方块的坐标, 单位长度为小方块边长
        self.current_coord = [-1, -1]
        # 下一个俄罗斯方块
        self.next_tetris = self.getNextTetris()
        # 当前俄罗斯方块
        self.current_tetris = tetrisShape()
        # 游戏是否结束
        self.is_gameover = False
        # 俄罗斯方块的初始x位置
        self.init_x = self.width // 2
        # 形状数量统计
        self.shape_statistics = [0] * 8
'''外部板块'''
class ExternalBoard(QFrame):
    score_signal = pyqtSignal(str)
    def __init__(self, parent, grid_size, inner_board):
        super(ExternalBoard, self).__init__(parent)
        self.grid_size = grid_size
        self.inner_board = inner_board
        self.setFixedSize(grid_size * inner_board.width, grid_size * inner_board.height)
        self.initExternalBoard()
    '''外部板块初始化'''
    def initExternalBoard(self):
        self.score = 0
    '''把内部板块结构画出来'''
    def paintEvent(self, event):
        painter = QPainter(self)
        for x in range(self.inner_board.width):
            for y in range(self.inner_board.height):
                shape = self.inner_board.getCoordValue([x, y])
                drawCell(painter, x * self.grid_size, y * self.grid_size, shape, self.grid_size)
        for x, y in self.inner_board.getCurrentTetrisCoords():
            shape = self.inner_board.current_tetris.shape
            drawCell(painter, x * self.grid_size, y * self.grid_size, shape, self.grid_size)
        painter.setPen(QColor(0x777777))
        painter.drawLine(0, self.height() - 1, self.width(), self.height() - 1)
        painter.drawLine(self.width() - 1, 0, self.width() - 1, self.height())
        painter.setPen(QColor(0xCCCCCC))
        painter.drawLine(self.width(), 0, self.width(), self.height())
        painter.drawLine(0, self.height(), self.width(), self.height())
    '''数据更新'''
    def updateData(self):
        self.score_signal.emit(str(self.score))
        self.update()
'''侧面板, 右边显示下一个俄罗斯方块的形状'''
class SidePanel(QFrame):
    def __init__(self, parent, grid_size, inner_board):
        super(SidePanel, self).__init__(parent)
        self.grid_size = grid_size
        self.inner_board = inner_board
        self.setFixedSize(grid_size * 5, grid_size * inner_board.height)
        self.move(grid_size * inner_board.width, 0)
    '''画侧面板'''
    def paintEvent(self, event):
        painter = QPainter(self)
        x_min, x_max, y_min, y_max = self.inner_board.next_tetris.getRelativeBoundary(0)
        dy = 3 * self.grid_size
        dx = (self.width() - (x_max - x_min) * self.grid_size) / 2
        shape = self.inner_board.next_tetris.shape
        for x, y in self.inner_board.next_tetris.getAbsoluteCoords(0, 0, -y_min):
            drawCell(painter, x * self.grid_size + dx, y * self.grid_size + dy, shape, self.grid_size)
    '''更新数据'''
    def updateData(self):
        self.update()

4.__init__

'''初始化'''

from .shapes import tetrisShape

from .gameboard import InnerBoard, ExternalBoard, SidePanel

 

5.README

requirements

相关文章
|
19天前
|
API C语言 C++
贪吃蛇游戏(必备知识篇)
贪吃蛇游戏(必备知识篇)
48 1
|
19天前
贪吃蛇游戏(代码篇)
贪吃蛇游戏(代码篇)
59 0
|
6月前
俄罗斯方块游戏开发实战教程(3):玩家如何控制形状
俄罗斯方块游戏开发实战教程(3):玩家如何控制形状
77 1
|
6月前
|
开发者 索引
俄罗斯方块游戏开发实战教程(8):下落处理
俄罗斯方块游戏开发实战教程(8):下落处理
83 0
|
Python
项目猜拳游戏
用Python语言,编写出猜拳游戏。
63 0
|
定位技术 开发者
如何做一个俄罗斯方块游戏(一)
从今天开始,我将开启一个新的游戏,并且顺带着会写一个新的系列教程,这个游戏就是人人都知道的——俄罗斯方块。 我一直都在做消除类型的游戏,在所有消除类型的游戏里,俄罗斯方块可以称得上是“鼻祖”了,所以,不论怎样这个系列里都不能少的了它。
146 0
|
算法 索引 容器
如何做一个俄罗斯方块游戏(二)
嗨!大家好,我是小蚂蚁。今天我们继续学习如何做一个俄罗斯方块游戏。整个系列教程计划按照这个流程图开展,这也是我制作整个游戏的过程,今天我们就来看一下“随机生成形状”这个模块。想要实现随机的生成形状,首先必须要知道在俄罗斯方块中一共有多少种形状(也就是我们上一节中留下的第二个问题)。
180 0
|
开发者
从零开始制作一个俄罗斯方块游戏
小蚂蚁的游戏目前已经上线,主要面向的是有一定基础的同学。从零开始制作一个经典的俄罗斯方块游戏,理论结合实战,帮助你进一步提升做游戏的技能。
143 0
|
程序员
关于经典游戏俄罗斯方块,你不知道的那些事儿
大家好,我是小蚂蚁。今天带大家来了解一下那个已被载入游戏史册的伟大的游戏——俄罗斯方块。 为什么它被叫做是“俄罗斯方块”呢?因为它诞生于俄罗斯,并且游戏界面都是方块.....开个玩笑,这样的解释也太牵强了。不过,这个游戏诞生于俄罗斯确实是真的。
146 0