|
|
import pygame
|
|
|
from pygame.locals import *
|
|
|
from sys import exit
|
|
|
import random
|
|
|
|
|
|
# 初始化
|
|
|
pygame.init()
|
|
|
|
|
|
# 常量
|
|
|
MAX_I = 34 # 让地图预留4行作为放入方块的地方
|
|
|
MAX_J = 15
|
|
|
SIZE = 15
|
|
|
|
|
|
COLORS = [(0, 0, 0), (255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 255, 255)]
|
|
|
|
|
|
gameMap = [[0 for j in range(MAX_J + 3)] for i in range(MAX_I + 3)] # 全局地图
|
|
|
tetrisHeight = 0 # 塔高
|
|
|
|
|
|
# 基本方块
|
|
|
tetrises = [
|
|
|
[
|
|
|
[1, 0, 0, 0],
|
|
|
[1, 0, 0, 0],
|
|
|
[1, 0, 0, 0],
|
|
|
[1, 0, 0, 0]
|
|
|
],
|
|
|
[
|
|
|
[0, 0, 0, 0],
|
|
|
[0, 1, 1, 0],
|
|
|
[0, 1, 1, 0],
|
|
|
[0, 0, 0, 0]
|
|
|
],
|
|
|
[
|
|
|
[1, 0, 0, 0],
|
|
|
[1, 1, 0, 0],
|
|
|
[0, 1, 0, 0],
|
|
|
[0, 0, 0, 0]
|
|
|
],
|
|
|
[
|
|
|
[0, 1, 0, 0],
|
|
|
[1, 1, 0, 0],
|
|
|
[1, 0, 0, 0],
|
|
|
[0, 0, 0, 0]
|
|
|
],
|
|
|
[
|
|
|
[0, 1, 0, 0],
|
|
|
[1, 1, 1, 0],
|
|
|
[0, 0, 0, 0],
|
|
|
[0, 0, 0, 0]
|
|
|
],
|
|
|
[
|
|
|
[1, 0, 0, 0],
|
|
|
[1, 1, 1, 0],
|
|
|
[0, 0, 0, 0],
|
|
|
[0, 0, 0, 0]
|
|
|
],
|
|
|
[
|
|
|
[0, 0, 1, 0],
|
|
|
[1, 1, 1, 0],
|
|
|
[0, 0, 0, 0],
|
|
|
[0, 0, 0, 0]
|
|
|
]
|
|
|
]
|
|
|
|
|
|
# 分数
|
|
|
score = 10
|
|
|
|
|
|
# 等级
|
|
|
level = 10
|
|
|
|
|
|
# 音乐开关
|
|
|
isMusic = True
|
|
|
|
|
|
# 游戏暂停
|
|
|
isPause = False
|
|
|
|
|
|
|
|
|
# 播放音乐
|
|
|
def playMyMusic(src):
|
|
|
if isMusic:
|
|
|
sound = pygame.mixer.Sound(src)
|
|
|
sound.play()
|
|
|
|
|
|
|
|
|
# 方块类
|
|
|
class Tetris:
|
|
|
__i = 0
|
|
|
__j = 0
|
|
|
__color = 0
|
|
|
__nextColor = 0
|
|
|
__nextType = 0
|
|
|
|
|
|
def __init__(self):
|
|
|
self.__nextColor = random.randint(0, 3) + 1 # 一共四种颜色
|
|
|
self.__nextType = random.randint(0, 6) # 一共七种类型
|
|
|
self.createTetris()
|
|
|
|
|
|
def createTetris(self):
|
|
|
# 根据类型调整一下快出现的位置
|
|
|
if self.__nextType == 0:
|
|
|
self.__i = 1
|
|
|
self.__j = 7
|
|
|
else:
|
|
|
self.__i = 2
|
|
|
self.__j = 6
|
|
|
|
|
|
self.__color = self.__nextColor
|
|
|
|
|
|
# 根据方块模板,放置整个到地图
|
|
|
for i in range(4):
|
|
|
for j in range(4):
|
|
|
if tetrises[self.__nextType][i][j] == 1:
|
|
|
if gameMap[self.__i + i][self.__j + j] == 0:
|
|
|
gameMap[self.__i + i][self.__j + j] = self.__color
|
|
|
else:
|
|
|
print('游戏失败!')
|
|
|
exit()
|
|
|
return -1
|
|
|
|
|
|
# 产生下一种类型和颜色
|
|
|
self.__nextColor = random.randint(0, 3) + 1 # 一共四种颜色
|
|
|
self.__nextType = random.randint(0, 6) # 一共七种类型
|
|
|
|
|
|
playMyMusic('music/get.wav')
|
|
|
|
|
|
def moveDown(self):
|
|
|
global gameMap
|
|
|
|
|
|
# 判断是否可以下移
|
|
|
for j in range(4):
|
|
|
for i in range(3, -1, -1):
|
|
|
if gameMap[self.__i + i][self.__j + j] == self.__color:
|
|
|
# 判断是否到底
|
|
|
if self.__i + i + 1 > MAX_I:
|
|
|
return 1
|
|
|
|
|
|
# 判断前面是否有东西
|
|
|
if gameMap[self.__i + i + 1][self.__j + j] != 0:
|
|
|
return 1
|
|
|
|
|
|
break
|
|
|
|
|
|
# 下移
|
|
|
for j in range(4):
|
|
|
for i in range(3, -1, -1):
|
|
|
if gameMap[self.__i + i][self.__j + j] == self.__color:
|
|
|
gameMap[self.__i + i][self.__j + j], gameMap[self.__i + i + 1][self.__j + j] = \
|
|
|
gameMap[self.__i + i + 1][self.__j + j], gameMap[self.__i + i][self.__j + j]
|
|
|
|
|
|
self.__i += 1
|
|
|
|
|
|
def stopTetris(self):
|
|
|
global tetrisHeight
|
|
|
|
|
|
flag = True
|
|
|
|
|
|
for i in range(4):
|
|
|
for j in range(4):
|
|
|
if gameMap[self.__i + i][self.__j + j] == self.__color:
|
|
|
gameMap[self.__i + i][self.__j + j] += 10
|
|
|
|
|
|
# 找到第一个颜色方块
|
|
|
if flag:
|
|
|
tetrisHeight = MAX_I - self.__i if tetrisHeight < MAX_I - self.__i else tetrisHeight
|
|
|
flag = False
|
|
|
|
|
|
self.deleteRow()
|
|
|
|
|
|
def moveLeft(self):
|
|
|
# 判断是否能够左移
|
|
|
for i in range(4):
|
|
|
for j in range(4):
|
|
|
if gameMap[self.__i + i][self.__j + j] == self.__color:
|
|
|
if self.__j + j - 1 < 0:
|
|
|
return 1
|
|
|
if gameMap[self.__i + i][self.__j + j - 1] != 0:
|
|
|
return 1
|
|
|
|
|
|
break
|
|
|
|
|
|
# 左移
|
|
|
for i in range(4):
|
|
|
for j in range(4):
|
|
|
if gameMap[self.__i + i][self.__j + j] == self.__color:
|
|
|
gameMap[self.__i + i][self.__j + j], gameMap[self.__i + i][self.__j + j - 1] = \
|
|
|
gameMap[self.__i + i][self.__j + j - 1], gameMap[self.__i + i][self.__j + j]
|
|
|
|
|
|
self.__j -= 1
|
|
|
|
|
|
def moveRight(self):
|
|
|
# 判断是否能右移
|
|
|
for i in range(4):
|
|
|
for j in range(3, -1, -1):
|
|
|
if gameMap[self.__i + i][self.__j + j] == self.__color:
|
|
|
if self.__j + j + 1 >= MAX_J:
|
|
|
return 1
|
|
|
if gameMap[self.__i + i][self.__j + j + 1] != 0:
|
|
|
return 1
|
|
|
|
|
|
break
|
|
|
|
|
|
# 右移
|
|
|
for i in range(4):
|
|
|
for j in range(3, -1, -1):
|
|
|
if gameMap[self.__i + i][self.__j + j] == self.__color:
|
|
|
gameMap[self.__i + i][self.__j + j], gameMap[self.__i + i][self.__j + j + 1] = \
|
|
|
gameMap[self.__i + i][self.__j + j + 1], gameMap[self.__i + i][self.__j + j]
|
|
|
|
|
|
self.__j += 1
|
|
|
|
|
|
def change(self):
|
|
|
tMap = [[0 for j in range(4)] for i in range(4)]
|
|
|
|
|
|
# 将所有方块顺时针旋转90度赋值到 tMap 中
|
|
|
i = 0
|
|
|
k = 3
|
|
|
while i < 4:
|
|
|
for j in range(4):
|
|
|
if MAX_I > self.__i + j >= 0 and MAX_J > self.__j + k >= 0 and gameMap[self.__i + j][
|
|
|
self.__j + k] == 0 or \
|
|
|
gameMap[self.__i + j][self.__j + k] == self.__color:
|
|
|
tMap[j][k] = gameMap[self.__i + i][self.__j + j]
|
|
|
|
|
|
else:
|
|
|
return
|
|
|
|
|
|
i += 1
|
|
|
k -= 1
|
|
|
|
|
|
# 赋值
|
|
|
for i in range(4):
|
|
|
for j in range(4):
|
|
|
gameMap[self.__i + i][self.__j + j] = tMap[i][j]
|
|
|
|
|
|
playMyMusic('music/change.wav')
|
|
|
|
|
|
def deleteRow(self):
|
|
|
# 找到有方块的最后一行
|
|
|
lastRow = 0
|
|
|
t = False
|
|
|
for i in range(3, -1, -1):
|
|
|
for j in range(4):
|
|
|
if gameMap[self.__i + i][self.__j + j] == self.__color + 10:
|
|
|
lastRow = self.__i + i
|
|
|
t = True
|
|
|
break
|
|
|
if t:
|
|
|
break
|
|
|
|
|
|
for i in range(lastRow, MAX_I - tetrisHeight - 1, -1):
|
|
|
for j in range(MAX_J):
|
|
|
if gameMap[i][j] == 0:
|
|
|
break
|
|
|
else:
|
|
|
global score
|
|
|
score += 10
|
|
|
playMyMusic('music/delete.wav')
|
|
|
|
|
|
# 删除行
|
|
|
gameMap.pop(i)
|
|
|
gameMap.insert(0, [0 for j in range(MAX_J + 3)])
|
|
|
|
|
|
# 增加等级
|
|
|
global level
|
|
|
level += score // 1000
|
|
|
|
|
|
# 再次调用删除行函数操作删行
|
|
|
self.deleteRow()
|
|
|
|
|
|
def nextTetris(self):
|
|
|
return self.__nextType, self.__nextColor
|
|
|
|
|
|
|
|
|
# 全局变量
|
|
|
screen = '' # 屏幕
|
|
|
gameTetris = Tetris()
|
|
|
|
|
|
|
|
|
# 绘制游戏地图
|
|
|
def drawMap():
|
|
|
# 画上边框
|
|
|
for i in range(MAX_I - 4):
|
|
|
# 画右边
|
|
|
myRect(screen, COLORS[2], [0, i * SIZE, SIZE, SIZE])
|
|
|
# 画左边
|
|
|
myRect(screen, COLORS[2], [(MAX_J + 1) * SIZE, i * SIZE, SIZE, SIZE])
|
|
|
|
|
|
# 画下面
|
|
|
for i in range(MAX_J + 2):
|
|
|
myRect(screen, COLORS[2], [i * SIZE, (MAX_I - 4) * SIZE, SIZE, SIZE])
|
|
|
|
|
|
# 给地图涂色
|
|
|
for i in range(4, MAX_I):
|
|
|
for j in range(MAX_J):
|
|
|
t = gameMap[i][j] - 10 if gameMap[i][j] > 10 else gameMap[i][j]
|
|
|
|
|
|
myRect(screen, COLORS[t], [(j + 1) * SIZE, (i - 4) * SIZE, SIZE, SIZE])
|
|
|
|
|
|
# 文字内容,下一个方块
|
|
|
drawMyText(screen, "下一块:", 305, 18, 15, (255, 255, 255))
|
|
|
|
|
|
# 绘制下一块方块
|
|
|
startX = 270
|
|
|
startY = 30
|
|
|
|
|
|
nextType, nextColor = gameTetris.nextTetris()
|
|
|
|
|
|
# 显示下一个方块的背景
|
|
|
pygame.draw.rect(screen, COLORS[5], [startX, startY, SIZE * 4, SIZE * 4], 1)
|
|
|
mySize = SIZE * 0.8 # 缩小下一个方块大小
|
|
|
|
|
|
# 根据形状,修改方块的位置(居中)
|
|
|
if nextType == 0:
|
|
|
startX += (SIZE * 4 - mySize) / 2
|
|
|
startY += (SIZE * 4 - mySize * 4) / 2
|
|
|
elif nextType == 2 or nextType == 3:
|
|
|
startX += (SIZE * 4 - mySize * 2) / 2
|
|
|
startY += (SIZE * 4 - mySize * 3) / 2
|
|
|
elif nextType == 4 or nextType == 5 or nextType == 6:
|
|
|
startX += (SIZE * 4 - mySize * 3) / 2
|
|
|
startY += (SIZE * 4 - mySize * 2) / 2
|
|
|
elif nextType == 1:
|
|
|
startX += (SIZE * 4 - mySize * 4) / 2
|
|
|
startY += (SIZE * 4 - mySize * 4) / 2
|
|
|
|
|
|
# 绘制下一个方块
|
|
|
for i in range(4):
|
|
|
for j in range(4):
|
|
|
# 绘制有图形地方
|
|
|
if tetrises[nextType][i][j] == 1:
|
|
|
# 根据不同的
|
|
|
myRect(screen, COLORS[nextColor], [startX + j * mySize, startY + i * mySize, mySize, mySize])
|
|
|
|
|
|
color = (255, 0, 0)
|
|
|
# 绘制分数
|
|
|
scoreText = "分数:{}".format(score)
|
|
|
drawMyText(screen, scoreText, 300, 120, 15, color)
|
|
|
|
|
|
# 等级
|
|
|
drawMyText(screen, "等级:{}".format(level), 300, 140, 15, color)
|
|
|
|
|
|
color = (255, 0, 255)
|
|
|
# 绘制音乐
|
|
|
textMusic = "音乐:"
|
|
|
|
|
|
if isMusic:
|
|
|
textMusic += "开"
|
|
|
else:
|
|
|
textMusic += '关'
|
|
|
|
|
|
drawMyText(screen, textMusic, 300, 220, 15, color)
|
|
|
|
|
|
# 绘制游戏暂停
|
|
|
textPause = "暂停:"
|
|
|
|
|
|
if isPause:
|
|
|
textPause += "开"
|
|
|
else:
|
|
|
textPause += '关'
|
|
|
|
|
|
drawMyText(screen, textPause, 300, 240, 15, color)
|
|
|
|
|
|
|
|
|
# 绘制键值
|
|
|
color = (130, 205, 255)
|
|
|
drawMyText(screen, "↑ 旋转90度", 300, 300, 15, color)
|
|
|
drawMyText(screen, "← 向左移动", 300, 320, 15, color)
|
|
|
drawMyText(screen, "→ 向右移动", 300, 340, 15, color)
|
|
|
drawMyText(screen, "↓ 快速向下", 300, 360, 15, color)
|
|
|
|
|
|
# 绘制背景
|
|
|
startY = 410
|
|
|
color = (255, 255, 0)
|
|
|
flower = "★"
|
|
|
drawMyText(screen, flower, 300, startY + 0, 15, color)
|
|
|
flower = "★★"
|
|
|
drawMyText(screen, flower, 300, startY + 20, 15, color)
|
|
|
flower = "★★★"
|
|
|
drawMyText(screen, flower, 300, startY + 40, 15, color)
|
|
|
|
|
|
|
|
|
# 游戏初始化
|
|
|
def initGame():
|
|
|
# 将地图倒数对大行全部赋值为-1
|
|
|
for j in range(MAX_J):
|
|
|
gameMap[MAX_I][j] = -1
|
|
|
|
|
|
# 将地图倒数最大列全部赋值为-1
|
|
|
for i in range(MAX_I):
|
|
|
gameMap[i][MAX_J] = -1
|
|
|
|
|
|
# 分数初始化
|
|
|
score = 0
|
|
|
|
|
|
# 加载背景音乐文件
|
|
|
pygame.mixer.music.load('music/bgm.mp3')
|
|
|
|
|
|
if isMusic:
|
|
|
# 播放背景音乐,第一个参数为播放的次数(-1表示无限循环),第二个参数是设置播放的起点(单位为秒)
|
|
|
pygame.mixer.music.play(-1, 0.0)
|
|
|
|
|
|
|
|
|
# 绘制有边框矩形
|
|
|
def myRect(screen, colorRect, pos, lineColor=COLORS[0], bold=1):
|
|
|
pygame.draw.rect(screen, colorRect, pos)
|
|
|
pygame.draw.rect(screen, lineColor, pos, bold)
|
|
|
|
|
|
|
|
|
# 绘制我的文字
|
|
|
def drawMyText(screen, text, x, y, bold, fColor, bColor=None):
|
|
|
# 通过字体文件获得字体对象
|
|
|
fontObj = pygame.font.Font('font/SIMYOU.TTF', bold)
|
|
|
|
|
|
# 配置要显示的文字
|
|
|
textSurfaceObj = fontObj.render(text, False, fColor, bColor)
|
|
|
|
|
|
# 获得要显示的对象的rect
|
|
|
textRectObj = textSurfaceObj.get_rect()
|
|
|
|
|
|
# 设置显示对象的坐标
|
|
|
textRectObj.center = (x, y)
|
|
|
|
|
|
# 绘制字体
|
|
|
screen.blit(textSurfaceObj, textRectObj)
|
|
|
|
|
|
|
|
|
# 游戏主体
|
|
|
def my_game():
|
|
|
# 得到屏幕
|
|
|
global screen, isMusic, isPause
|
|
|
screen = pygame.display.set_mode((350, 465))
|
|
|
|
|
|
# 设置标题
|
|
|
pygame.display.set_caption('俄罗斯方块')
|
|
|
|
|
|
# 初始化游戏
|
|
|
initGame()
|
|
|
|
|
|
# 用于控制下落速度
|
|
|
count = 0
|
|
|
|
|
|
while True:
|
|
|
|
|
|
if count == 3 + level * 2:
|
|
|
if not isPause: # 只有暂停是 False 才能下移
|
|
|
if gameTetris.moveDown() == 1:
|
|
|
gameTetris.stopTetris()
|
|
|
gameTetris.createTetris()
|
|
|
|
|
|
count = 0
|
|
|
|
|
|
# 事件判断
|
|
|
for event in pygame.event.get():
|
|
|
if event.type == pygame.QUIT:
|
|
|
# 停止播放背景音乐
|
|
|
pygame.mixer.music.stop()
|
|
|
|
|
|
pygame.quit()
|
|
|
exit()
|
|
|
elif event.type == pygame.MOUSEBUTTONDOWN:
|
|
|
# 控制音乐开关
|
|
|
if 270 < event.pos[0] < 330 and 210 < event.pos[1] < 225:
|
|
|
# 处理音乐开关
|
|
|
if isMusic:
|
|
|
# 停止播放背景音乐
|
|
|
pygame.mixer.music.stop()
|
|
|
else:
|
|
|
# 播放背景音乐,第一个参数为播放的次数(-1表示无限循环),第二个参数是设置播放的起点(单位为秒)
|
|
|
pygame.mixer.music.play(-1, 0.0)
|
|
|
|
|
|
isMusic = not isMusic
|
|
|
|
|
|
# 处理游戏暂停开关
|
|
|
if 270 < event.pos[0] < 327 and 233 < event.pos[1] < 248:
|
|
|
isPause = not isPause
|
|
|
|
|
|
if isPause:
|
|
|
pygame.display.set_caption('俄罗斯方块:已暂停')
|
|
|
else:
|
|
|
pygame.display.set_caption('俄罗斯方块')
|
|
|
|
|
|
elif event.type == pygame.KEYDOWN:
|
|
|
if event.key == K_UP:
|
|
|
gameTetris.change()
|
|
|
|
|
|
keyPressList = pygame.key.get_pressed()
|
|
|
|
|
|
if keyPressList[K_DOWN]:
|
|
|
gameTetris.moveDown()
|
|
|
elif keyPressList[K_LEFT]:
|
|
|
gameTetris.moveLeft()
|
|
|
elif keyPressList[K_RIGHT]:
|
|
|
gameTetris.moveRight()
|
|
|
|
|
|
screen.fill((0, 0, 0))
|
|
|
drawMap()
|
|
|
pygame.display.update()
|
|
|
count += 1
|
|
|
|
|
|
pygame.time.Clock().tick(10)
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
my_game()
|