pygame实现俄罗斯方块

使用pygame实现简单的俄罗斯方块,实现了强降、预降位置显示等功能。若键盘无法控制,将输入法调为英文。

俄罗斯方块1.0演示


import os
import pygame,sys,random,copy,time

pygame.init()
pygame.mixer.init()
pygame.display.set_caption('俄罗斯方块1.0')

'''操作设置'''
left = pygame.K_LEFT
right = pygame.K_RIGHT
down = pygame.K_DOWN
spi_r = pygame.K_UP #右旋-上键
spi_l = pygame.K_g #左旋-G
change = pygame.K_d #保留-D
plunge = pygame.K_f #强降-F
again = pygame.K_2 #重新游戏
leve = 1 #难度等级,数字越大,下落越快

'''定义屏幕大小'''
width = 500
height = 700
screen   = pygame.display.set_mode((500,700))#屏幕大小

'''基础方块绘制'''
size=30#方块规格
sore = 10#分数单位
sores = [0]#记录总分
#基础方块的绘制
face  = pygame.Surface((size,size),flags=pygame.HWSURFACE)
# face.fill("white")
pygame.draw.rect(face, (0, 0, 0), [0,0,size,size],1)
# pygame.draw.circle(face, (255, 0, 0), (15,15), 15, width=1)
#基础方块的投影绘制--增加透明度
face1  = pygame.Surface((size,size),flags=pygame.HWSURFACE)
# face1.fill((255,255,255,0))
pygame.draw.rect(face1, (0, 0, 0,0), [0,0,size,size],1)
# pygame.draw.circle(face1, (255, 0, 0,0), (15,15), 15, width=1)
face1.set_alpha(100)#设置透明度
#字体设置
f = pygame.font.SysFont(['方正粗黑宋简体'],30)#分数显示等需要用的字体
f1 = pygame.font.SysFont(['方正粗黑宋简体'],20)
f2 = pygame.font.SysFont(['方正粗黑宋简体'],15)

'''地图参数设置'''
origin=(5,5)                           #原点位置,边框的宽度
set = [4*size+origin[0],origin[1]+0]     #初始生成方块位置,该坐标全局控制当前形状的位置
c_list=(2,4,6,7,14,16,19)#分别为7种大类型的方块,见方块类型函数
ch1 = [ c_list[random.randint(0,6)]  for i in range(4)] #初始方块产生随机函数
ch1.append(0)#ch1为一个有装4个值的列表,前三个为即将出现的三个形状的标号,第四个为保留的形状的标号,开始时没有,定为0
filled = []#落地方块储存列表,将一落地的每一个形状的信息存入
n=[0]#控制是否能更换当前手中方块
control = [1]#控制游戏结束,0为结束

'''方块类型函数'''
#每个形状表示为四个坐标,取其中一个方块为原点算出其他方块坐标
#c为方块类型标号,a为形状的坐标。
# 该函数最终输出一个列表,其中包含6个坐标,即为一个形状(包含四个基础方块)的四个方块坐标和四个方块中最小的x,y和最大的x,y,方便之后的碰撞判断
#还要输出形状标号c(方便进行不同方块的不同颜色绘制)
def forms(c,a):

    #长条
    if c == 1:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = -1
        x2 = 0
        y2 = 2
        x3 = 0
        y3 = 1
    if c == 2:#横条
            x0 = 0
            y0 = 0
            x1 = -1
            y1 = 0
            x2 = 1
            y2 = 0
            x3 = 2
            y3 = 0
    # S
    if c==3:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = 1
        x2 = -1
        y2 = 0
        x3 = -1
        y3 = -1
    if c == 4:
            x0 = 0
            y0 = 0
            x1 = -1
            y1 = 0
            x2 = 0
            y2 = -1
            x3 = 1
            y3 = -1
        #Z
    if c==5:
        x0 = 0
        y0 = 0
        x1 = 1
        y1 = 0
        x2 = 0
        y2 = 1
        x3 = 1
        y3 = -1
    if c==6:
        x0 = 0
        y0 = 0
        x1 = -1
        y1 = 0
        x2 = 0
        y2 = 1
        x3 = 1
        y3 = 1
#T
    if c==7:
        x0 = 0
        y0 = 0
        x1 = 1
        y1 = 0
        x2 = -1
        y2 = 0
        x3 = 0
        y3 = -1
    if c==8:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = -1
        x2 = 0
        y2 = 1
        x3 = 1
        y3 = 0
    if c==9:
        x0 = 0
        y0 = 0
        x1 = -1
        y1 = 0
        x2 = 0
        y2 = 1
        x3 = 1
        y3 = 0
    if c==10:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = 1
        x2 = 0
        y2 = -1
        x3 = -1
        y3 = 0
    #L
    if c==11:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = -1
        x2 = 0
        y2 = 1
        x3 = 1
        y3 = 1
    if c==12:
        x0 = 0
        y0 = 0
        x1 = -1
        y1 = 0
        x2 = 1
        y2 = 0
        x3 = -1
        y3 = 1
    if c==13:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = -1
        x2 = 0
        y2 = 1
        x3 = -1
        y3 = -1
    if c==14:
        x0 = 0
        y0 = 0
        x1 = -1
        y1 = 0
        x2 = 1
        y2 = 0
        x3 = 1
        y3 = -1
    #J
    if c==15:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = -1
        x2 = 0
        y2 = 1
        x3 = -1
        y3 = 1
    if c==16:
        x0 = 0
        y0 = 0
        x1 = -1
        y1 = -1
        x2 = -1
        y2 = 0
        x3 = 1
        y3 = 0
    if c==17:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = 1
        x2 = 0
        y2 = -1
        x3 = 1
        y3 = -1
    if c==18:
        x0 = 0
        y0 = 0
        x1 = -1
        y1 = 0
        x2 = 1
        y2 = 0
        x3 = 1
        y3 = 1
    # 田
    if c == 19:
        x0 = 0
        y0 = 0
        x1 = 0
        y1 = 1
        x2 = -1
        y2 = 0
        x3 = -1
        y3 = 1
    mx = max(x0,x1,x2,x3)
    my = max(y0,y1,y2,y3)
    mx1 = min(x0, x1, x2,x3)
    my1 = min(y0, y1, y2,y3)
    Z=[[x0*size+a[0],y0*size+a[1]],[x1*size+a[0],y1*size+a[1]],[x2*size+a[0],y2*size+a[1]],[x3*size+a[0],y3*size+a[1]],[mx1*size+a[0],my1*size+a[1]],[mx*size+a[0],my*size+a[1]],c]
    return Z

'''屏幕更新函数'''
"""
屏幕动态更新的核心函数
实时更新形状位置,分数,预览形状等都在该函数完成
大概思路:
1每一次都使用新的空白页面(粉色覆盖,绘制边框)覆盖之前的内容,再
2再绘制新的实时内容
  a、根据filled列表中储存的形状坐标信息绘制已经降落的形状
  b、根据ch1列表中储存的实时形状(正在下落的形状,预降位置,预览的形状)
  c、根据sores列表记录的分数绘制新的分数
"""
def update():
    # 更新前进行碰撞判断
    isclear(filled)
    # 游戏框绘制
    screen.fill("pink")
    pygame.draw.line(screen, (0, 0, 250), (0, 0), (size * 10 + 10, 0), 10)
    pygame.draw.line(screen, (0, 0, 250), (0, 0), (0, size * 20 + 10), 10)
    pygame.draw.line(screen, (0, 0, 250), (size * 10+10 , 0), (size * 10 +10, size * 20+15 ), 10)
    pygame.draw.line(screen, (0, 0, 250), (0, 10+size * 20), (size * 10 + 10, size * 20+10 ), 10)

    pygame.draw.line(screen, (0, 0, 250), (10*size+origin[0]+10,100+size), (width,100+size), 5)
    pygame.draw.line(screen, (0, 0, 250), (10 * size + origin[0] + 10, 100 + 5*size), (width, 100 + 5*size), 5)
    pygame.draw.line(screen, (0, 0, 250), (10 * size + origin[0] + 10, 100 + 9 * size), (width, 100 + 9 * size), 5)
    pygame.draw.line(screen, (0, 0, 100), (10 * size + origin[0] + 10, 100 + 13 * size), (width, 100 + 13 * size), 5)
    pygame.draw.line(screen, (0, 0, 100), (10 * size + origin[0] + 10, 100 + 17 * size), (width, 100 + 17 * size), 5)

    # 操作解释绘制
    sor = f2.render("操作介绍:", True, (0, 100, 10))
    screen.blit(sor, (20, 610))
    sor = f1.render("左:" + pygame.key.name(left), True, (0, 0, 0))
    screen.blit(sor, (50, 630))
    sor = f1.render("右:" + pygame.key.name(right), True, (0, 0, 0))
    screen.blit(sor, (150, 630))
    sor = f1.render("下:" + pygame.key.name(down), True, (0, 0, 0))
    screen.blit(sor, (250, 630))
    sor = f1.render("右旋:" + pygame.key.name(spi_r), True, (0, 0, 0))
    screen.blit(sor, (50, 660))
    sor = f1.render("左旋:" + pygame.key.name(spi_l), True, (0, 0, 0))
    screen.blit(sor, (150, 660))
    sor = f1.render("强降:" + pygame.key.name(plunge), True, (0, 0, 0))
    screen.blit(sor, (250, 660))
    sor = f1.render("保留:" + pygame.key.name(change), True, (0, 0, 0))
    screen.blit(sor, (360, 660))

    # 方块颜色控制函数
    '''
    c表示方块的编号
    face表示前面定义的基础方块
    '''
    def d_color(c, face=face):
        a = -1
        colors = ((0, 160, 233), (34, 172, 56), (230, 0, 18), (146, 7, 131), (235, 97, 0), (0, 71, 157), (243, 152, 0))
        if c == 1 or c == 2 or c == -2:
            a = 0
            face.fill(colors[0])
        if c == 3 or c == 4:
            face.fill(colors[1])
            a = 1
        if c == 5 or c == 6:
            a = 2
            face.fill(colors[2])
        if c >= 7 and c <= 10:
            a = 3
            face.fill(colors[3])
        if c >= 11 and c <= 14:
            a = 4
            face.fill(colors[4])
        if c >= 15 and c <= 18:
            a = 5
            face.fill(colors[5])
        if c == 19:
            a = 6
            face.fill(colors[6])
        pygame.draw.rect(face, (255,255,255), [0, 0, size, size], 1)

    #当前正在下落的方块绘制
    d_color(ch1[0], face=face)
    for i in range(4):
        screen.blit(face,forms(ch1[0],set)[i])

    #计算预降位置,找到当前形状与已落地方块的距离
    a = 19 * size - forms(ch1[0], set)[5][1] + origin[1]
    for i in filled:
        for j in range(4):
            for k in range(4):
                if i[j][0] == forms(ch1[0], set)[k][0]:#x相同的时候,找到符合要求的最y值,即当前形状与已落地方块的距离
                    if a > i[j][1] - forms(ch1[0], set)[k][1] - size:
                        a = i[j][1] - forms(ch1[0], set)[k][1] - size
    # 方块预降位置绘制
    d_color(ch1[0], face=face1)
    for i in range(4):
        screen.blit(face1,forms(ch1[0],(set[0],set[1]+a))[i])

    #将出现的方块预览绘制,可以预览3个形状
    d_color(ch1[1], face=face)
    for i in range(4):
        screen.blit(face,forms(ch1[1],(330+2*size,120+2*size))[i])
    d_color(ch1[2], face=face)
    for i in range(4):
        screen.blit(face,forms(ch1[2],(330+2*size,120+6*size))[i])
    d_color(ch1[3], face=face)
    for i in range(4):
        screen.blit(face,forms(ch1[3],(330+2*size,120+10*size))[i])

    # 有保留的形状时绘制,其值为0时没有保留的形状
    sor = f.render("retain", True, (0, 0, 0))
    screen.blit(sor, (10*size+20, 90 + 13 * size))
    if ch1[4]!=0:
        d_color(ch1[4], face=face)
        for i in range(4):
            screen.blit(face,forms(ch1[4],(330+2*size,120+14*size))[i])

    #已经落地方块绘制
    for i  in filled:
        d_color(i[-1], face=face)
        for j in range(4):
            screen.blit(face, i[j])

    #分数绘制
    sor =  f.render("sore:"+str(sores[0]),True,(0,0,0),(246,127,240))
    screen.blit(sor, (335, 50))

#判断游戏是否结束
    if iscrash(forms(ch1[0],set),filled)[0]==0 and forms(ch1[0],set)[5][1]==origin[1]:
        control[0]=0
#绘制游戏结束界面并判断游戏是否继续
    if control[0]==0:
        sor1 = f1.render("game over!!", True, (255, 0, 0), (255, 255, 255))
        screen.blit(sor1, (100, 300))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:
                if event.key == again:
                    filled.clear()
                    set[0]=origin[0]+4*size
                    set[1]=origin[1]+0
                    sores[0]=0
                    control[0]=1
    pygame.display.flip()#更新屏幕

"""方块控制函数"""
'''
控制原理为改变set列表中的横纵坐标对形状的位置进行控制
每次移动完成要及时进行碰撞判断(无论是否有按键事件都要判断)
但该版本还未解决长按连续移动的问题
'''
def move():
    #获取键盘事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:

            if event.key== left:#左移动
                set[0] -= size
                if iscrash(forms(ch1[0], set), filled)[2] == 2:
                    set[0] += size

            if event.key == right:
                set[0] += size
                if iscrash(forms(ch1[0], set), filled)[1] == 1:
                    set[0] -= size

            if event.key == down:#加速下降
                set[1] += size
            if event.key == spi_r:#右旋
                m = ch1[0]
                spin(0)
                for i in filled:
                    for j in range(4):
                        for k in range(4):
                            if i[j][0]==forms(ch1[0],set)[k][0] and i[j][1]==forms(ch1[0],set)[k][1]:
                                ch1[0]=m
            if event.key == spi_l:#左旋
                m = ch1[0]
                spin(1)
                for i in filled:
                    for j in range(4):
                        for k in range(4):
                            if i[j][0]==forms(ch1[0],set)[k][0] and i[j][1]==forms(ch1[0],set)[k][1]:
                                ch1[0]=m

            if event.key ==  change:#保留
                if n[0]==0:
                    if ch1[4]==0:
                        if ch1[0] == 19:
                            ch1[4]=19

                        if ch1[0]>=1 and ch1[0]<=2:
                            ch1[4] = 2

                        if ch1[0]>=3 and ch1[0]<=4:
                            ch1[4] = 4

                        if ch1[0]>=5 and ch1[0]<=6:
                            ch1[4] = 6

                        if ch1[0]>=7 and ch1[0]<=10:
                            ch1[4] = 7

                        if ch1[0]>=11 and ch1[0]<=14:
                            ch1[4] = 14

                        if ch1[0]>=15 and ch1[0]<=18:
                            ch1[4] = 16

                        ch1[0] = ch1[1]
                        ch1[1]=ch1[2]
                        ch1[2]=ch1[3]
                        ch1[3]=c_list[random.randint(0,6)]
                        set[0] =4 * size + origin[0]
                        set[1]=origin[1] + 0
                        n[0]=1
                    else:
                        v=ch1[0]
                        ch1[0] = ch1[4]
                        if v == 19:

                            ch1[4]=19
                        if v>=1 and v<=2:

                            ch1[4] = 2
                        if v>=3 and v<=4:
                            ch1[4] = 4
                        if v>=5 and v<=6:
                            ch1[4] = 6
                        if v>=7 and v<=10:
                            ch1[4] = 7
                        if v>=11 and v<=14:
                            ch1[4] = 14
                        if v>=15 and v<=18:
                            ch1[4] = 16
                        set[0] = 4 * size + origin[0]
                        set[1] = origin[1] + 0
                        n[0] = 1

            if event.key == plunge:#强降
                #原理也是计算当前方块落地的最小距离
                a=20*size-forms(ch1[0],set)[5][1]+origin[1]
                for i in filled:
                    for  j  in range(4):
                        for k in range(4):
                            if i[j][0]==forms(ch1[0],set)[k][0]:
                                if a>i[j][1]-forms(ch1[0],set)[k][1]:
                                    a=i[j][1]-forms(ch1[0],set)[k][1]
                set[1] += a

    # 判断碰撞情况
    if forms(ch1[0], set)[4][0] < origin[0]:
        set[0] += size
    if forms(ch1[0], set)[5][0] > origin[0] + 9 * size:
        set[0] -= size

    # 落地判断
    if forms(ch1[0], set)[5][1] > origin[1] + 19 * size:
        set[1] -= size
        filled.append(copy.deepcopy(forms(ch1[0], set)))
        set[0] = 4 * size + origin[0]
        set[1] = origin[1] + 0
        ch1[0] = ch1[1]
        ch1[1] = ch1[2]
        ch1[2] = ch1[3]
        ch1[3] = c_list[random.randint(0, 6)]
        n[0] = 0

    #方块间的碰撞判断
    if iscrash(forms(ch1[0], set), filled)[0] == 0:
        set[1] -= size

        filled.append(copy.deepcopy(forms(ch1[0], set)))
        set[0] = 4 * size + origin[0]
        set[1] = origin[1] + 0
        ch1[0] = ch1[1]
        ch1[1] = ch1[2]
        ch1[2] = ch1[3]
        ch1[3] = c_list[random.randint(0, 6)]
        n[0] = 0

"""方块间的碰撞判断函数"""
def iscrash(form, form1):
    a, b, m = 10, 10, 10
    # 上下碰撞
    for i in form1:
        for c in range(4):
            for j in range(4):

                if i[c][0] == form[j][0] and i[c][1] - form[j][1] == 0:
                    a = 0
    # 碰right
    for i in form1:
        for c in range(4):
            for j in range(4):
                if i[c][0] - form[j][0] == 0 and i[c][1] - form[j][1] == 0:
                    b = 1
    # 碰left
    for i in form1:
        for c in range(4):
            for j in range(4):
                if form[j][0] - i[c][0] == 0 and i[c][1] - form[j][1] == 0:
                    m = 2
    return a, b, m

"""形状旋转命令函数"""
""""
输入旋转命令(在move函数中调用),
直接改变ch1[0]的值(正在下落的形状标号),及直接改变当前形状
"""
def spin(a):
    if a==0:#右旋
        if ch1[0]==1:
            ch1[0]=2
            return ch1[0]
        if ch1[0]==2:
            ch1[0]=1
            return ch1[0]
        if ch1[0]==3:
            ch1[0]=4
            return ch1[0]
        if ch1[0]==4:
            ch1[0]=3
            return ch1[0]
        if ch1[0]==5:
            ch1[0]=6
            return ch1[0]
        if ch1[0]==6:
            ch1[0]=5
            return ch1[0]
        if ch1[0]==7:
            ch1[0]=8
            return ch1[0]
        if ch1[0] == 8:
            ch1[0] = 9
            return ch1[0]
        if ch1[0] == 9:
            ch1[0] = 10
            return ch1[0]
        if ch1[0] == 10:
            ch1[0] = 7
            return ch1[0]
        if ch1[0] == 11:
            ch1[0] = 12
            return ch1[0]
        if ch1[0] == 12:
            ch1[0] = 13
            return ch1[0]
        if ch1[0] == 13:
            ch1[0] = 14
            return ch1[0]
        if ch1[0] == 14:
            ch1[0] = 11
            return ch1[0]
        if ch1[0] == 15:
            ch1[0] = 16
            return ch1[0]
        if ch1[0] == 16:
            ch1[0] = 17
            return ch1[0]
        if ch1[0] == 17:
            ch1[0] = 18
            return ch1[0]
        if ch1[0] == 18:
            ch1[0] = 15
            return ch1[0]
        if ch1[0] == 19:
            ch1[0] = 19
            return ch1[0]
    if a==1:#左旋
        if ch1[0]==1:
            ch1[0]=2
            return ch1[0]
        if ch1[0]==2:
            ch1[0]=1
            return ch1[0]
        if ch1[0]==3:
            ch1[0]=4
            return ch1[0]
        if ch1[0]==4:
            ch1[0]=3
            return ch1[0]
        if ch1[0]==5:
            ch1[0]=6
            return ch1[0]
        if ch1[0]==6:
            ch1[0]=5
            return ch1[0]
        if ch1[0]==7:
            ch1[0]=10
            return ch1[0]
        if ch1[0] == 10:
            ch1[0] = 9
            return ch1[0]
        if ch1[0] == 9:
            ch1[0] = 8
            return ch1[0]
        if ch1[0] == 8:
            ch1[0] = 7
            return ch1[0]
        if ch1[0] == 11:
            ch1[0] = 14
            return ch1[0]
        if ch1[0] == 14:
            ch1[0] = 13
            return ch1[0]
        if ch1[0] == 13:
            ch1[0] = 12
            return ch1[0]
        if ch1[0] == 12:
            ch1[0] = 11
            return ch1[0]
        if ch1[0] == 15:
            ch1[0] = 18
            return ch1[0]
        if ch1[0] == 18:
            ch1[0] = 17
            return ch1[0]
        if ch1[0] == 17:
            ch1[0] = 16
            return ch1[0]
        if ch1[0] == 16:
            ch1[0] = 15
            return ch1[0]
        if ch1[0] == 19:
            ch1[0] = 19
            return ch1[0]

'''#满行判断'''
#通过及算每一行的横坐标之和来进行满行判断
def isclear(form1):
    sor=0
    for j in range(20):
        sum = 0#保存一行的横坐标和
        c = j * size+origin[1]
        for i in form1:
                for k in range(4):
                        if i[k][1] == c:
                            sum+=i[k][0]
        if sum >= 45*size + origin[0]*10:#判断是否满行
            sor+=sore
            for i in form1:
                for k in range(4):
                    if i[k][1]==c:
                        i[k][1]=size*30#满行后将满行的y值赋值为size*30,在屏幕上就看不见了
                    if i[k][1]<c:
                        i[k][1]+=size#在满行上方的所有方块下移一格
    sores[0] += sor#记录满行数

'''游戏主函数'''
def main():
    while 1:
    #游戏总循环
        if control[0]==1:
            #游戏进行中循环
            # 此处使用两个循环解决操作与自动下落冲突问题
            while 1:
                t = time.time()
                while 1:
                    move()
                    update()
                    if control[0] == 0:
                        break
                    if time.time() - t >= leve:#每隔leve下降一格
                        t = time.time()
                        set[1] += size
                        break
                move()
                update()
                if control[0]==0:break
        if control[0] == 0:
            #游戏结束界面
            while 1:
                update()
                if control[0] == 1:break

if __name__=="__main__":
    main()

还有很多不足之处,欢迎留言。

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值