zoukankan      html  css  js  c++  java
  • Python3+pygame实现的俄罗斯方块 代码完整 有演示效果

    一、简单说明

    80、90后的小伙伴都玩过“俄罗斯方块”,那种“叱咤风云”场景 偶尔闪现在脑海 真的是太爽了;如果没有来得及玩过的同学,这次可以真正的自己做一个了

    本实例用的是Python3(当然了Python3.5 3.6 3.7....都行 )+ pygame实现的

    运行之前需要安装pygame模块,安装命令如下

    pip install pygame -i https://mirrors.aliyun.com/pypi/simple/

    二、运行效果

    三、完整代码

    下面的代码,用到了字体文件yh.ttf,下载地址 https://www.itprojects.cn/web/material/details.html?id=11

    文件main.py代码如下:

    """
    作者:it项目实例网
    更多项目实例,请访问:www.itprojects.cn
    """
    
    import random
    import sys
    import time
    
    import pygame
    
    from blocks import block_s, block_i, block_j, block_l, block_o, block_t, block_z
    
    SCREEN_WIDTH, SCREEN_HEIGHT = 450, 750
    BG_COLOR = (40, 40, 60)  # 背景色
    BLOCK_COL_NUM = 10  # 每行的方格数
    SIZE = 30  # 每个小方格大小
    BLOCK_ROW_NUM = 25  # 每列的方个数
    BORDER_WIDTH = 4  # 游戏区边框宽度
    RED = (200, 30, 30)  # 红色,GAME OVER 的字体颜色
    
    
    def judge_game_over(stop_all_block_list):
        """
        判断游戏是否结束
        """
        if "O" in stop_all_block_list[0]:
            return True
    
    
    def change_speed(score):
        speed_level = [("1", 0.5, 0, 20), ("2", 0.4, 21, 50), ("3", 0.3, 51, 100), ("4", 0.2, 101, 200), ("5", 0.1, 201, None)]
        for speed_info, speed, score_start, score_stop in speed_level:
            if score_stop and score_start <= score <= score_stop:
                return speed_info, speed
            elif score_stop is None and score >= score_start:
                return speed_info, speed
    
    
    def judge_lines(stop_all_block_list):
        """
        判断是否有同一行的方格,如果有则消除
        """
        # 记录刚刚消除的行数
        move_row_list = list()
        # 消除满格的行
        for row, line in enumerate(stop_all_block_list):
            if "." not in line:
                # 如果这一行没有. 那么就意味着全部是O,则消除这一行
                stop_all_block_list[row] = ['.' for _ in range(len(line))]
                move_row_list.append(row)
    
        # 如果没有满格的行,则结束此函数
        if not move_row_list:
            return 0
    
        # 移动剩余的行到下一行
        for row in move_row_list:
            stop_all_block_list.pop(row)
            stop_all_block_list.insert(0, ['.' for _ in range(len(line))])
    
        return len(move_row_list) * 10
    
    
    def add_to_stop_all_block_list(stop_all_block_list, current_block, current_block_start_row, current_block_start_col):
        """
        将当前已经停止移动的block添加到列表中
        """
        for row, line in enumerate(current_block):
            for col, block in enumerate(line):
                if block != '.':
                    stop_all_block_list[current_block_start_row + row][current_block_start_col + col] = "O"
    
    
    def change_current_block_style(current_block):
        """
        改变图形的样式
        """
        # 计算出,当前图形样式属于哪个图形
        current_block_style_list = None
        for block_style_list in [block_s, block_i, block_j, block_l, block_o, block_t, block_z]:
            if current_block in block_style_list:
                current_block_style_list = block_style_list
    
        # 得到当前正在用的图形的索引(下标)
        index = current_block_style_list.index(current_block)
        # 它的下一个图形的索引
        index += 1
        # 防止越界
        index = index % len(current_block_style_list)
        # 返回下一个图形
        return current_block_style_list[index]
    
    
    def judge_move_right(current_block, current_block_start_col):
        """
        判断是否可以向右移动
        """
        # 先判断列的方式是从右到左
        for col in range(len(current_block[0]) - 1, -1, -1):
            # 得到1列的所有元素
            col_list = [line[col] for line in current_block]
            # 判断是否碰到右边界
            if 'O' in col_list and current_block_start_col + col >= BLOCK_COL_NUM:
                return False
        return True
    
    
    def judge_move_left(current_block, current_block_start_col):
        """
        判断是否可以向左移动
        """
        # 先判断列的方式是从左到右
        for col in range(len(current_block[0])):
            # 得到1列的所有元素
            col_list = [line[col] for line in current_block]
            # 判断是否碰到右边界
            if 'O' in col_list and current_block_start_col + col < 0:
                return False
        return True
    
    
    def judge_move_down(current_block, current_block_start_row, current_block_start_col, stop_all_block_list):
        """
        判断是否碰撞到其它图形或者底边界
        """
        # 得到其它图形所有的坐标
        stop_all_block_position = list()
        for row, line in enumerate(stop_all_block_list):
            for col, block in enumerate(line):
                if block != ".":
                    stop_all_block_position.append((row, col))
        # print(stop_all_block_position)
    
        # 判断碰撞
        for row, line in enumerate(current_block):
            if 'O' in line and current_block_start_row + row >= BLOCK_ROW_NUM:
                # 如果当前行有0,且从起始行开始算+当前显示的行,超过了总行数,那么就认为碰到了底部
                return False
            for col, block in enumerate(line):
                if block != "." and (current_block_start_row + row, current_block_start_col + col) in stop_all_block_position:
                    return False
    
        return True
    
    
    def get_block():
        """
        创建一个图形
        """
        block_style_list = random.choice([block_s, block_i, block_j, block_l, block_o, block_t, block_z])
        return random.choice(block_style_list)
    
    
    def main():
        pygame.init()
        screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
        pygame.display.set_caption('俄罗斯方块')
    
        current_block = get_block()  # 当前图形
        current_block_start_row = -2  # 当前图片从哪一行开始显示图形
        current_block_start_col = 4  # 当前图形从哪一列开始显示
        next_block = get_block()  # 下一个图形
        last_time = time.time()
        speed = 0.5  # 降落的速度
        speed_info = '1'  # 显示的速度等级
    
        # 定义一个列表,用来存储所有的已经停止移动的形状
        stop_all_block_list = [['.' for i in range(BLOCK_COL_NUM)] for j in range(BLOCK_ROW_NUM)]
    
        # 字体
        font = pygame.font.Font('yh.ttf', 24)  # 黑体24
        game_over_font = pygame.font.Font("yh.ttf", 72)
        game_over_font_width, game_over_font_height = game_over_font.size('GAME OVER')
        game_again_font_width, game_again_font_height = font.size('鼠标点击任意位置,再来一局')
    
        # 得分
        score = 0
    
        # 标记游戏是否结束
        game_over = False
    
        # 创建计时器(防止while循环过快,占用太多CPU的问题)
        clock = pygame.time.Clock()
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_LEFT:
                        if judge_move_left(current_block, current_block_start_col - 1):
                            current_block_start_col -= 1
                    elif event.key == pygame.K_RIGHT:
                        if judge_move_right(current_block, current_block_start_col + 1):
                            current_block_start_col += 1
                    elif event.key == pygame.K_UP:
                        current_block_next_style = change_current_block_style(current_block)
                        if judge_move_left(current_block_next_style, current_block_start_col) and \
                                judge_move_right(current_block_next_style, current_block_start_col) and \
                                judge_move_down(current_block, current_block_start_row, current_block_start_col, stop_all_block_list):
                            # 判断新的样式没有越界
                            current_block = current_block_next_style
                    elif event.key == pygame.K_DOWN:
                        # 判断是否可以向下移动,如果碰到底部或者其它的图形就不能移动了
                        if judge_move_down(current_block, current_block_start_row + 1, current_block_start_col, stop_all_block_list):
                            current_block_start_row += 1
                elif event.type == pygame.MOUSEBUTTONDOWN and event.button:
                    if game_over:
                        # 重置游戏用到的变量
                        current_block = get_block()  # 当前图形
                        current_block_start_row = -2  # 当前图片从哪一行开始显示图形
                        current_block_start_col = 4  # 当前图形从哪一列开始显示
                        next_block = get_block()  # 下一个图形
                        stop_all_block_list = [['.' for i in range(BLOCK_COL_NUM)] for j in range(BLOCK_ROW_NUM)]
                        score = 0
                        game_over = False
    
            # 判断是否修改当前图形显示的起始行
            if not game_over and time.time() - last_time > speed:
                last_time = time.time()
                # 判断是否可以向下移动,如果碰到底部或者其它的图形就不能移动了
                if judge_move_down(current_block, current_block_start_row + 1, current_block_start_col, stop_all_block_list):
                    current_block_start_row += 1
                else:
                    # 将这个图形存储到统一的列表中,这样便于判断是否成为一行
                    add_to_stop_all_block_list(stop_all_block_list, current_block, current_block_start_row, current_block_start_col)
                    # 判断是否有同一行的,如果有就消除,且加上分数
                    score += judge_lines(stop_all_block_list)
                    # 判断游戏是否结束(如果第一行中间有O那么就表示游戏结束)
                    game_over = judge_game_over(stop_all_block_list)
                    # 调整速度
                    speed_info, speed = change_speed(score)
                    # 创建新的图形
                    current_block = next_block
                    next_block = get_block()
                    # 重置数据
                    current_block_start_col = 4
                    current_block_start_row = -2
    
            # 画背景(填充背景色)
            screen.fill(BG_COLOR)
    
            # 画游戏区域分隔线
            pygame.draw.line(screen, (100, 40, 200), (SIZE * BLOCK_COL_NUM, 0), (SIZE * BLOCK_COL_NUM, SCREEN_HEIGHT), BORDER_WIDTH)
    
            # 显示当前图形
            for row, line in enumerate(current_block):
                for col, block in enumerate(line):
                    if block != '.':
                        pygame.draw.rect(screen, (20, 128, 200), ((current_block_start_col + col) * SIZE, (current_block_start_row + row) * SIZE, SIZE, SIZE), 0)
    
            # 显示所有停止移动的图形
            for row, line in enumerate(stop_all_block_list):
                for col, block in enumerate(line):
                    if block != '.':
                        pygame.draw.rect(screen, (20, 128, 200), (col * SIZE, row * SIZE, SIZE, SIZE), 0)
    
            # 画网格线 竖线
            for x in range(BLOCK_COL_NUM):
                pygame.draw.line(screen, (0, 0, 0), (x * SIZE, 0), (x * SIZE, SCREEN_HEIGHT), 1)
            # 画网格线 横线
            for y in range(BLOCK_ROW_NUM):
                pygame.draw.line(screen, (0, 0, 0), (0, y * SIZE), (BLOCK_COL_NUM * SIZE, y * SIZE), 1)
    
            # 显示右侧(得分、速度、下一行图形)
            # 得分
            score_show_msg = font.render('得分: ', True, (255, 255, 255))
            screen.blit(score_show_msg, (BLOCK_COL_NUM * SIZE + 10, 10))
            score_show_msg = font.render(str(score), True, (255, 255, 255))
            screen.blit(score_show_msg, (BLOCK_COL_NUM * SIZE + 10, 50))
            # 速度
            speed_show_msg = font.render('速度: ', True, (255, 255, 255))
            screen.blit(speed_show_msg, (BLOCK_COL_NUM * SIZE + 10, 100))
            speed_show_msg = font.render(speed_info, True, (255, 255, 255))
            screen.blit(speed_show_msg, (BLOCK_COL_NUM * SIZE + 10, 150))
            # 下一个图形(文字提示)
            next_style_msg = font.render('下一个: ', True, (255, 255, 255))
            screen.blit(next_style_msg, (BLOCK_COL_NUM * SIZE + 10, 200))
            # 下一个图形(图形)
            for row, line in enumerate(next_block):
                for col, block in enumerate(line):
                    if block != '.':
                        pygame.draw.rect(screen, (20, 128, 200), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE, SIZE, SIZE), 0)
                        # 显示这个方格的4个边的颜色
                        #
                        pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * col, (BLOCK_COL_NUM + row + 1) * SIZE), 1)
                        #
                        pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row) * SIZE), 1)
                        #
                        pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row + 1) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row + 1) * SIZE), 1)
                        #
                        pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row + 1) * SIZE), 1)
    
            # 显示游戏结束画面
            if game_over:
                game_over_tips = game_over_font.render('GAME OVER', True, RED)
                screen.blit(game_over_tips, ((SCREEN_WIDTH - game_over_font_width) // 2, (SCREEN_HEIGHT - game_over_font_height) // 2))
                # 显示"鼠标点击任意位置,再来一局"
                game_again = font.render('鼠标点击任意位置,再来一局', True, RED)
                screen.blit(game_again, ((SCREEN_WIDTH - game_again_font_width) // 2, (SCREEN_HEIGHT - game_again_font_height) // 2 + 80))
    
            # 刷新显示(此时窗口才会真正的显示)
            pygame.display.update()
            # FPS(每秒钟显示画面的次数)
            clock.tick(60)  # 通过一定的延时,实现1秒钟能够循环60次
    
    
    if __name__ == '__main__':
        main()

    文件blocks.py代码如下:

    # S形方块
    block_s = [['.OO',
                'OO.',
                '...'],
               ['O..',
                'OO.',
                '.O.']]
    # Z形方块
    block_z = [['OO.',
                '.OO',
                '...'],
               ['.O.',
                'OO.',
                'O..']]
    # I型方块
    block_i = [['.O..',
                '.O..',
                '.O..',
                '.O..'],
               ['....',
                '....',
                'OOOO',
                '....']]
    # O型方块
    block_o = [['OO',
                'OO']]
    # J型方块
    block_j = [['O..',
                'OOO',
                '...'],
               ['.OO',
                '.O.',
                '.O.'],
               ['...',
                'OOO',
                '..O'],
               ['.O.',
                '.O.',
                'OO.']]
    # L型方块
    block_l = [['..O',
                'OOO',
                '...'],
               ['.O.',
                '.O.',
                '.OO'],
               ['...',
                'OOO',
                'O..'],
               ['OO.',
                '.O.',
                '.O.']]
    # T型方块
    block_t = [['.O.',
                'OOO',
                '...'],
               ['.O.',
                '.OO',
                '.O.'],
               ['...',
                'OOO',
                '.O.'],
               ['.O.',
                'OO.',
                '.O.']]
  • 相关阅读:
    Python socket 基础(Server)
    Python socket 基础(Client)
    DOM
    Software Testing Concepts
    coroutine
    这一周~&&html+css的学习感悟
    充实的几天~
    时间不够用的感觉
    论文真痛苦
    焦躁的一周……
  • 原文地址:https://www.cnblogs.com/dong4716138/p/14467634.html
Copyright © 2011-2022 走看看