用Pygame写俄罗斯方块

此文章参考的是吃饭超人的文章

首先我们先打开cmd输入如下令命

pip install pygame

然后打开python或者pycharm

输入如下代码

import os
import pygame
import sys
import random
import pygame.font
import time
pygame.init()

clos = 10                        #游戏网格列数,可以调整,>=8
rows = 20                        #游戏网格行数,可以调整
cell_size = 40                    #一个网格的大小
block_size = cell_size - 1        #一个方块的大小,小于等于cell_size
block_edge = int(block_size /2)    #方块的立体感,数字>=1,数字越小立体感越强
fps = 40                        #每秒帧数,建议范围20-60,越大难度递进越越缓

win_width = clos * 2 * cell_size + 6 * cell_size
win_hight = (rows + 1) * cell_size    
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (400,40)
screen = pygame.display.set_mode((win_width, win_hight))
pygame.display.set_caption("Crystal方块")

#在4*4的小网格内,以左上角坐标为(0,0),7种方块及其各形态4个方块在小网格的相对坐标
#移动时记录小网络(0,0)点在游戏网格的(x,y),就知道4个方块在游戏网格中的位置
blocks = {
    1: [[(0,1),(1,1),(2,1),(3,1)],
        [(2,0),(2,1),(2,2),(2,3)]],        #I型
    2: [[(1,1),(2,1),(1,2),(2,2)]],        #O型
    3: [[(0,1),(1,1),(2,1),(1,2)],
        [(1,0),(0,1),(1,1),(1,2)],
        [(1,1),(0,2),(1,2),(2,2)],
        [(1,0),(1,1),(2,1),(1,2)]],        #T型
    4: [[(0,1),(1,1),(2,1),(0,2)],
        [(0,0),(1,0),(1,1),(1,2)],
        [(2,1),(0,2),(1,2),(2,2)],
        [(1,0),(1,1),(1,2),(2,2)]],        #L型
    5: [[(0,1),(1,1),(2,1),(2,2)],
        [(1,0),(1,1),(0,2),(1,2)],
        [(0,1),(0,2),(1,2),(2,2)],
        [(1,0),(2,0),(1,1),(1,2)]],        #J型
    6: [[(1,1),(2,1),(0,2),(1,2)],
        [(0,0),(0,1),(1,1),(1,2)]],        #s型
    7: [[(0,1),(1,1),(1,2),(2,2)],
        [(2,0),(1,1),(2,1),(1,2)]],}    #Z型
        
#第1个为网格底色,后7个为对应方块的颜色,因为要加和原色相近的明暗边,自定义色RGB值最小得不低于50,最高不超过205,否则出错。    
#最后一个颜色(灰)用来画NEXT方块,也可以用NEXT方块的next_key值来指向本色    
block_color = [(199,238,206),(200,50,50),(50,200,200),(50,50,200),(200,200,50),(200,50,200),(50,200,50),(125,50,125),(180,180,180)]

class Game_machine():
    def __init__(self,x0,y0):
        self.x0, self.y0 = x0, y0                #记录player游戏区(0,0)点在屏幕的坐标
        self.rect = pygame.Rect(0,0,block_size, block_size)    #方块矩形大小            
        self.display_array = [[0 for i in range(clos)] for j in range(rows)]    #游戏区每格初始值设为0,为1时不能通过
        self.color_array = [[0 for i in range(clos)] for j in range(rows)]        #游戏区每格的颜色block_color的索引值
        self.x, self.y = 0, 0                    #记录移动方块(0,0)点在游戏网格的(clo,row)位置
        self.key = 0                            #记录移动方块在blocks的键,是哪种方块
        self.index_ = 0                            #记录移动方块形态的索引
        self.next_key = self.rand_key()            #记录NEXT方块在blocks的键        
        self.speed = fps                        #速度,和帧率一致
        self.fall_buffer = self.speed            #自动下落的缓冲时间,屏幕每刷一次自动减1
        self.fall_speed_up = False                #是否加速下落
        self.score = 0
        self.lines = 0
        self.level = 0
        self.creat_new_block()
                        
    def creat_new_block(self):
        #产生新的移动方块和NEXT方块,以第一形态作为初始形态
        self.key = self.next_key
        self.next_key = self.rand_key()
        self.index = 0
        self.x = 4                    #初始列设在第4列
        self.y = -1                    #初始高度设为-1,保证方块在最顶部位置出现,研究每种方块第一形态坐标可以找到答案

    def rand_key(self):
        keys = [1,1,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,7,7]        #决定每种方块出现概率
        return keys[random.randint(0,len(keys)-1)]
        
    def move(self, dx, dy):
        #方块左、右、下移动:左:dx=-1,dy=0  右:dx=1,dy=0  下:dx=0,dy=1
        if self.can_move(self.index, dx, dy):
            self.x += dx
            self.y += dy
        elif dy:
            #不能下落:在顶部位置不能下落,游戏结束,以下位置则停止移动
            if self.y <= 0:
                self.game_over()
            else:
                self.stop_move()
            
    def rotate(self):
        #方块旋转至下一形态,使用的顺时针旋转,被注释的是逆时针旋转
        next_index = (self.index + 1) % len(blocks[self.key])
        #next_index = (self.index - 1 + len(blocks[self.key])) % len(blocks[self.key])
        if self.can_move(next_index, 0, 0):
            self.index = next_index
    
    def can_move(self, index, dx, dy):
        #方块能否移动:出界或碰到其他方块
        for (x,y) in blocks[self.key][index]:
            clo, row = self.x + x + dx , self.y + y + dy
            if clo >= clos  or clo < 0 or row >= rows or row < 0:    #出界
                return False
            if self.display_array[row][clo]:            #值等于1时不能移动
                return False
        return True

    def stop_move(self):
        #方块停止移动,停落区域赋值1和相应的颜色
        self.score += 4    
        for (x,y) in  blocks[self.key][self.index]:
            self.display_array[y+self.y][x+self.x] = 1
            self.color_array[y+self.y][x+self.x] = self.key
        self.del_full_row()    
        self.creat_new_block()    
    
    def del_full_row(self):
        #删除填满的行,记录成绩
        lines = 0        
        for row in range(rows):
            if sum(self.display_array[row]) == clos:            #填满行判断
                lines += 1                #记录一次连续删除的行数,实现多消多奖
                self.lines += 1
                if self.lines % 5 == 0:                #每消5行等级升1,速度加快
                    self.level = self.lines / 5
                    self.speed = int(self.speed * 0.9)            #越小越快
                self.score += (self.level + clos * lines) * 5
                
                del self.display_array[row]
                self.display_array.insert(0,[0 for i in range(clos)])
                
    def display(self):
        self.display_stop_blocks()
        self.display_next_blocks()
        self.display_move_blocks()
        self.display_score()
        
        #每刷一次缓冲计数减1,缓冲计数=0,或按住了向下键则下落一格
        self.fall_buffer -= 1
        if self.fall_buffer == 0 or self.fall_speed_up:
            self.fall_buffer = self.speed
            self.move(0,1)
                
    def display_stop_blocks(self):
        #显示不移动的方块,值为1画彩色立体方块,值为0画底色块
        for y in range(rows):
            for x in range(clos):
                self.rect.topleft = x * cell_size, y * cell_size
                if  self.display_array[y][x]:
                    self.draw_block(self.color_array[y][x], 1)
                else:
                    self.draw_block(0, 0)
                    
    def display_next_blocks(self):
        #显示下一个方块
        for (x,y) in  blocks[self.next_key][0]:
            self.rect.topleft = x * cell_size , (y - 1) * cell_size
            self.draw_block(8, 1)        

    def display_move_blocks(self):
        #显示移动的方块
        for (x,y) in  blocks[self.key][self.index]:
            self.rect.topleft = (self.x + x) * cell_size, (self.y + y) * cell_size
            self.draw_block(self.key, 1)    

    def display_score(self):
        #显示得分记录
        text = "得分:%d  行数:%d  等级:%d" %(self.score,self.lines,self.level)
        self.img = pygame.font.SysFont("kaiti",25).render(text, True, (0,0,255))
        self.img_rect = self.img.get_rect()
        self.img_rect.topleft = (self.x0, rows* cell_size)
        screen.blit(self.img, self.img_rect)
                
    def game_over(self):
        #只是简单的数据重新初始化后立即重新开始
        self.__init__(self.x0, self.y0)
                        
    def draw_block(self, color_index, draw_edge):
        #在指定位置画方块
        (r,g,b) = block_color[color_index]
        self.rect.centerx = self.rect.left + self.x0 + int(cell_size / 2)
        self.rect.centery = self.rect.top + self.y0 + int(cell_size / 2)
        if draw_edge:
            #画方块明暗过度边,增加立体感,x0~x4是方块四角和中心的坐标。
            x0 = self.rect.center                    
            x1 = self.rect.topleft
            x2 = self.rect.topright
            x3 = self.rect.bottomright
            x4 = self.rect.bottomleft
            pygame.draw.polygon(screen, (r+50, g+50, b+50), (x0,x1,x2), 0)
            pygame.draw.polygon(screen, (r+20, g+20, b+20), (x0,x2,x3), 0)
            pygame.draw.polygon(screen, (r-50, g-50, b-50), (x0,x3,x4), 0)
            pygame.draw.polygon(screen, (r-20, g-20, b-20), (x0,x4,x1), 0)
            pygame.draw.rect(screen, (r,g,b), self.rect.inflate(-block_edge, -block_edge), 0)
        else:
            pygame.draw.rect(screen, (r,g,b), self.rect, 0)

time = pygame.time.Clock()    
player1 = Game_machine(0, 0)
player2 = Game_machine((clos + 6) * cell_size, 0)

while True:
    time.tick(fps)
    screen.fill((166,124,64))
    player1.display()
    player2.display()
    pygame.display.update()
        
    #移动旋转控制            
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_g:            #player1 :g键右移动一格
                player1.move(1,0)
            elif event.key == pygame.K_d:        #player1 :d键左移动一格
                player1.move(-1,0)
            elif event.key == pygame.K_r:        #player1 :r键旋转一次
                player1.rotate()
            elif event.key == pygame.K_f:        #player1 :f键加速下移
                player1.fall_speed_up = True
                
            if event.key == pygame.K_RIGHT:        #player2 :→键右移动一格
                player2.move(1,0)
            elif event.key == pygame.K_LEFT:    #player2 :←键左移动一格
                player2.move(-1,0)
            elif event.key == pygame.K_UP:        #player2 :↑键旋转一次
                player2.rotate()
            elif event.key == pygame.K_DOWN:    #player2 :↓键加速下移
                player2.fall_speed_up = True
                
            elif event.key == pygame.K_q:
                sys.exit()
                
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_f:
                player1.fall_speed_up = False
            if event.key == pygame.K_DOWN:
                player2.fall_speed_up = False    
        elif event.type == pygame.QUIT:
            sys.exit()

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Python和Pygame俄罗斯方块的示例代码: ```python import pygame import random # 初始化 Pygamepygame.init() # 定义颜色 BLACK = (0, 0, 0) WHITE = (255, 255, 255) GRAY = (128, 128, 128) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) YELLOW = (255, 255, 0) # 设置屏幕大小 SCREEN_WIDTH = 400 SCREEN_HEIGHT = 500 SCREEN_SIZE = (SCREEN_WIDTH, SCREEN_HEIGHT) # 设置方块大小 BLOCK_SIZE = 20 # 创建游戏窗口 screen = pygame.display.set_mode(SCREEN_SIZE) pygame.display.set_caption("Tetris") # 定义字体 font = pygame.font.SysFont("arial", 36) # 定义方块类 class Block(pygame.sprite.Sprite): def __init__(self, color): super().__init__() self.image = pygame.Surface([BLOCK_SIZE, BLOCK_SIZE]) self.image.fill(color) self.rect = self.image.get_rect() # 定义方块组类 class BlockGroup(pygame.sprite.Group): def __init__(self, *sprites): super().__init__(*sprites) self.speed = 1 def update(self, *args): for block in self.sprites(): block.rect.y += self.speed def move(self, direction): for block in self.sprites(): block.rect.x += direction def rotate(self): center = self.sprites()[0].rect.center for block in self.sprites()[1:]: x, y = block.rect.center x -= center[0] y -= center[1] x, y = -y, x block.rect.center = (x + center[0], y + center[1]) # 定义方块类型 block_types = [ [(0, 0), (1, 0), (0, 1), (1, 1), RED], [(0, 0), (1, 0), (2, 0), (3, 0), GREEN], [(0, 0), (1, 0), (2, 0), (1, 1), BLUE], [(1, 0), (2, 0), (0, 1), (1, 1), YELLOW], [(1, 0), (0, 1), (1, 1), (2, 1), GRAY], [(0, 0), (0, 1), (1, 1), (2, 1), WHITE], [(2, 0), (0, 1), (1, 1), (2, 1), BLUE] ] # 定义游戏主循环 def main(): # 创建方块组 block_group = BlockGroup() # 创建当前方块 current_block = BlockGroup() # 创建下一个方块 next_block = BlockGroup() # 随机选择方块类型 block_type = random.choice(block_types) # 创建当前方块 for pos in block_type[:-1]: block = Block(block_type[-1]) block.rect.x = (pos[0] + 3) * BLOCK_SIZE block.rect.y = pos[1] * BLOCK_SIZE current_block.add(block) # 创建下一个方块 block_type = random.choice(block_types) for pos in block_type[:-1]: block = Block(block_type[-1]) block.rect.x = (pos[0] + 14) * BLOCK_SIZE block.rect.y = (pos[1] + 2) * BLOCK_SIZE next_block.add(block) # 设置计时器 clock = pygame.time.Clock() interval = 500 timer = pygame.time.get_ticks() # 设置分数 score = 0 # 游戏主循环 while True: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: current_block.move(-BLOCK_SIZE) elif event.key == pygame.K_RIGHT: current_block.move(BLOCK_SIZE) elif event.key == pygame.K_UP: current_block.rotate() # 更新方块组 block_group.update() # 判断是否碰撞 if pygame.sprite.groupcollide(block_group, current_block, False, False): # 将当前方块加入方块组 block_group.add(current_block.sprites()) # 创建新的当前方块 current_block.empty() for block in next_block.sprites(): new_block = Block(block_type[-1]) new_block.rect.x = block.rect.x - 11 * BLOCK_SIZE new_block.rect.y = block.rect.y - 2 * BLOCK_SIZE current_block.add(new_block) # 创建新的下一个方块 next_block.empty() block_type = random.choice(block_types) for pos in block_type[:-1]: block = Block(block_type[-1]) block.rect.x = (pos[0] + 14) * BLOCK_SIZE block.rect.y = (pos[1] + 2) * BLOCK_SIZE next_block.add(block) # 判断是否到达底部 if any(block.rect.y >= SCREEN_HEIGHT for block in current_block.sprites()): # 将当前方块加入方块组 block_group.add(current_block.sprites()) # 创建新的当前方块 current_block.empty() for block in next_block.sprites(): new_block = Block(block_type[-1]) new_block.rect.x = block.rect.x - 11 * BLOCK_SIZE new_block.rect.y = block.rect.y - 2 * BLOCK_SIZE current_block.add(new_block) # 创建新的下一个方块 next_block.empty() block_type = random.choice(block_types) for pos in block_type[:-1]: block = Block(block_type[-1]) block.rect.x = (pos[0] + 14) * BLOCK_SIZE block.rect.y = (pos[1] + 2) * BLOCK_SIZE next_block.add(block) # 绘制背景 screen.fill(BLACK) # 绘制方块组 block_group.draw(screen) # 绘制当前方块 current_block.draw(screen) # 绘制下一个方块 next_block.draw(screen) # 绘制分数 score_text = font.render("Score: {}".format(score), True, WHITE) screen.blit(score_text, (10, 10)) # 更新屏幕 pygame.display.update() # 判断是否结束游戏 if any(block.rect.y <= BLOCK_SIZE for block in block_group.sprites()): pygame.quit() exit() # 更新计时器 if pygame.time.get_ticks() - timer >= interval: block_group.speed += 1 timer = pygame.time.get_ticks() # 更新分数 score = len(block_group.sprites()) // 10 # 设置帧率 clock.tick(60) if __name__ == "__main__": main() ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值