俄罗斯方块-简单开发版

news2025/4/22 21:38:59

一、需求分析

        实现了一个经典的俄罗斯方块小游戏,主要满足以下需求:

1.图形界面

        使用 pygame 库创建一个可视化的游戏窗口,展示游戏的各种元素,如游戏区域、方块、分数等信息。

2.游戏逻辑

        实现方块的生成、移动、旋转、下落和锁定等基本操作,同时检测方块是否超出边界或与已有方块重叠。

3.计分系统

        根据玩家消除的行数来计算分数和等级,等级的提升会加快方块的下落速度。

4.用户交互

        支持用户通过键盘控制方块的移动、旋转和快速下落,游戏结束后可按 R 键重新开始。

5.提示信息

        在游戏界面显示下一个方块预览、分数、等级以及操作说明,游戏结束时给出相应提示。

二、关键模块

1.初始化

import pygame
import random
import sys

# 初始化pygame
pygame.init()

# 颜色定义
BACKGROUND_COLOR = (214, 226, 251)  # 背景色
# ... 其他颜色定义

# 游戏设置
GRID_SIZE = 30
GRID_WIDTH = 10
GRID_HEIGHT = 20
SCREEN_WIDTH = GRID_WIDTH * GRID_SIZE + 200
SCREEN_HEIGHT = GRID_HEIGHT * GRID_SIZE

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("俄罗斯方块")

# 使用系统自带的中文字体
try:
    font = pygame.font.SysFont("PingFang", 20)
    large_font = pygame.font.SysFont("PingFang", 40)
except:
    font = pygame.font.SysFont(None, 20)
    large_font = pygame.font.SysFont(None, 40)

        此模块负责导入必要的库,初始化 pygame ,定义游戏所需的颜色、尺寸等常量,创建游戏窗口并设置字体。

2.Tetris 类模块

class Tetris:
    def __init__(self):
        self.grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
        self.current_piece = self.new_piece()
        self.next_piece = self.new_piece()
        self.game_over = False
        self.score = 0
        self.level = 1
        self.fall_speed = 0.5  # 初始下落速度(秒)
        self.fall_time = 0
    
    # ... 其他方法

        Tetris 类封装了游戏的核心逻辑,包括游戏状态的初始化、方块的生成、移动、旋转、锁定以及行消除和计分等功能。

3.主游戏循环模块

def main():
    clock = pygame.time.Clock()
    game = Tetris()
    
    while True:
        # 处理事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            # ... 其他事件处理
        
        # 自动下落
        if not game.game_over:
            current_time = pygame.time.get_ticks() / 1000
            if current_time - game.fall_time > game.fall_speed:
                game.fall_time = current_time
                if game.valid_move(game.current_piece, 0, 1):
                    game.current_piece['y'] += 1
                else:
                    game.lock_piece()
        
        # 绘制游戏
        game.draw()
        pygame.display.update()
        clock.tick(60)

        该模块是游戏的主循环,负责处理用户输入事件,控制方块的自动下落,更新游戏状态并绘制游戏界面。

三、完整代码

import pygame
import random
import sys

# 初始化pygame
pygame.init()

# 颜色定义
BACKGROUND_COLOR = (214, 226, 251)  # 背景色
GRID_COLOR = (255, 255, 255)        # 游戏区域网格颜色
BLOCK_GRID_COLOR = (0, 0, 0)        # 方块网格颜色
TEXT_COLOR = (0, 0, 0)              # 普通文字颜色
GAME_OVER_COLOR = (255, 0, 0)       # 游戏结束文字颜色

# 游戏设置
GRID_SIZE = 30
GRID_WIDTH = 10
GRID_HEIGHT = 20
SCREEN_WIDTH = GRID_WIDTH * GRID_SIZE + 200
SCREEN_HEIGHT = GRID_HEIGHT * GRID_SIZE

# 方块形状
SHAPES = [
    [[1, 1, 1, 1]],  # I
    [[1, 1], [1, 1]],  # O
    [[1, 1, 1], [0, 1, 0]],  # T
    [[1, 1, 1], [1, 0, 0]],  # L
    [[1, 1, 1], [0, 0, 1]],  # J
    [[0, 1, 1], [1, 1, 0]],  # S
    [[1, 1, 0], [0, 1, 1]]   # Z
]

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("俄罗斯方块")

# 使用系统自带的中文字体
try:
    font = pygame.font.SysFont("PingFang", 20)
    large_font = pygame.font.SysFont("PingFang", 40)
except:
    font = pygame.font.SysFont(None, 20)
    large_font = pygame.font.SysFont(None, 40)

class Tetris:
    def __init__(self):
        self.grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
        self.current_piece = self.new_piece()
        self.next_piece = self.new_piece()
        self.game_over = False
        self.score = 0
        self.level = 1
        self.fall_speed = 0.5  # 初始下落速度(秒)
        self.fall_time = 0
    
    def new_piece(self):
        shape = random.choice(SHAPES)
        return {
            'shape': shape,
            'x': GRID_WIDTH // 2 - len(shape[0]) // 2,
            'y': 0
        }
    
    def valid_move(self, piece, x_offset=0, y_offset=0):
        for y, row in enumerate(piece['shape']):
            for x, cell in enumerate(row):
                if cell:
                    new_x = piece['x'] + x + x_offset
                    new_y = piece['y'] + y + y_offset
                    if (new_x < 0 or new_x >= GRID_WIDTH or 
                        new_y >= GRID_HEIGHT or 
                        (new_y >= 0 and self.grid[new_y][new_x])):
                        return False
        return True
    
    def rotate_piece(self):
        # 旋转方块
        rotated = list(zip(*reversed(self.current_piece['shape'])))
        old_shape = self.current_piece['shape']
        self.current_piece['shape'] = rotated
        if not self.valid_move(self.current_piece):
            self.current_piece['shape'] = old_shape
    
    def lock_piece(self):
        # 锁定当前方块到网格
        for y, row in enumerate(self.current_piece['shape']):
            for x, cell in enumerate(row):
                if cell:
                    self.grid[self.current_piece['y'] + y][self.current_piece['x'] + x] = 1
        
        # 检查是否有完整的行
        self.clear_lines()
        
        # 生成新方块
        self.current_piece = self.next_piece
        self.next_piece = self.new_piece()
        
        # 检查游戏是否结束
        if not self.valid_move(self.current_piece):
            self.game_over = True
    
    def clear_lines(self):
        lines_cleared = 0
        for y in range(GRID_HEIGHT):
            if all(self.grid[y]):
                lines_cleared += 1
                # 移动上面的行下来
                for y2 in range(y, 0, -1):
                    self.grid[y2] = self.grid[y2-1][:]
                self.grid[0] = [0 for _ in range(GRID_WIDTH)]
        
        # 更新分数
        if lines_cleared > 0:
            self.score += lines_cleared * 100 * self.level
            self.level = self.score // 1000 + 1
            self.fall_speed = max(0.1, 0.5 - (self.level - 1) * 0.05)
    
    def draw(self):
        # 绘制背景
        screen.fill(BACKGROUND_COLOR)
        
        # 绘制游戏区域网格
        for y in range(GRID_HEIGHT):
            for x in range(GRID_WIDTH):
                pygame.draw.rect(screen, GRID_COLOR, 
                                (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE), 1)
        
        # 绘制已锁定的方块
        for y in range(GRID_HEIGHT):
            for x in range(GRID_WIDTH):
                if self.grid[y][x]:
                    pygame.draw.rect(screen, (0, 100, 200), 
                                    (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE))
                    pygame.draw.rect(screen, BLOCK_GRID_COLOR, 
                                    (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE), 1)
        
        # 绘制当前方块
        if not self.game_over:
            for y, row in enumerate(self.current_piece['shape']):
                for x, cell in enumerate(row):
                    if cell:
                        pygame.draw.rect(screen, (200, 0, 0), 
                                        ((self.current_piece['x'] + x) * GRID_SIZE, 
                                         (self.current_piece['y'] + y) * GRID_SIZE, 
                                         GRID_SIZE, GRID_SIZE))
                        pygame.draw.rect(screen, BLOCK_GRID_COLOR, 
                                        ((self.current_piece['x'] + x) * GRID_SIZE, 
                                         (self.current_piece['y'] + y) * GRID_SIZE, 
                                         GRID_SIZE, GRID_SIZE), 1)
        
        # 绘制信息面板
        info_x = GRID_WIDTH * GRID_SIZE + 10
        
        # 绘制下一个方块预览
        next_text = font.render("下一个:", True, TEXT_COLOR)
        screen.blit(next_text, (info_x, 20))
        
        for y, row in enumerate(self.next_piece['shape']):
            for x, cell in enumerate(row):
                if cell:
                    pygame.draw.rect(screen, (200, 0, 0), 
                                    (info_x + x * GRID_SIZE, 50 + y * GRID_SIZE, GRID_SIZE, GRID_SIZE))
                    pygame.draw.rect(screen, BLOCK_GRID_COLOR, 
                                    (info_x + x * GRID_SIZE, 50 + y * GRID_SIZE, GRID_SIZE, GRID_SIZE), 1)
        
        # 绘制分数和等级
        score_text = font.render(f"分数: {self.score}", True, TEXT_COLOR)
        level_text = font.render(f"等级: {self.level}", True, TEXT_COLOR)
        screen.blit(score_text, (info_x, 150))
        screen.blit(level_text, (info_x, 180))
        
        # 绘制操作说明
        controls = [
            "操作说明:",
            "← → : 左右移动",
            "↑ : 旋转",
            "↓ : 加速下落",
            "空格: 直接落下"
        ]
        
        for i, text in enumerate(controls):
            control_text = font.render(text, True, TEXT_COLOR)
            screen.blit(control_text, (info_x, 230 + i * 25))
        
        # 游戏结束提示
        if self.game_over:
            game_over_text = large_font.render("游戏结束!", True, GAME_OVER_COLOR)
            restart_text = font.render("按R键重新开始", True, GAME_OVER_COLOR)
            screen.blit(game_over_text, (GRID_WIDTH * GRID_SIZE // 2 - 80, GRID_HEIGHT * GRID_SIZE // 2 - 50))
            screen.blit(restart_text, (GRID_WIDTH * GRID_SIZE // 2 - 70, GRID_HEIGHT * GRID_SIZE // 2))

# 主游戏循环
def main():
    clock = pygame.time.Clock()
    game = Tetris()
    
    while True:
        # 处理事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            
            if event.type == pygame.KEYDOWN:
                if game.game_over:
                    if event.key == pygame.K_r:
                        game = Tetris()  # 重新开始游戏
                else:
                    if event.key == pygame.K_LEFT and game.valid_move(game.current_piece, -1):
                        game.current_piece['x'] -= 1
                    elif event.key == pygame.K_RIGHT and game.valid_move(game.current_piece, 1):
                        game.current_piece['x'] += 1
                    elif event.key == pygame.K_DOWN and game.valid_move(game.current_piece, 0, 1):
                        game.current_piece['y'] += 1
                    elif event.key == pygame.K_UP:
                        game.rotate_piece()
                    elif event.key == pygame.K_SPACE:
                        while game.valid_move(game.current_piece, 0, 1):
                            game.current_piece['y'] += 1
                        game.lock_piece()
        
        # 自动下落
        if not game.game_over:
            current_time = pygame.time.get_ticks() / 1000
            if current_time - game.fall_time > game.fall_speed:
                game.fall_time = current_time
                if game.valid_move(game.current_piece, 0, 1):
                    game.current_piece['y'] += 1
                else:
                    game.lock_piece()
        
        # 绘制游戏
        game.draw()
        pygame.display.update()
        clock.tick(60)

if __name__ == "__main__":
    main()

四、代码运行方式

1.代码运行环境

        Python 环境 :建议使用 Python 3.6 及以上版本。
        依赖库 :需要安装 pygame 库,可以使用以下命令进行安装:

pip install pygame

2.游戏操作

        左右移动 :按下键盘的左箭头 ← 或右箭头 → 可以控制方块左右移动。
        旋转 :按下上箭头 ↑ 可以旋转方块。
        加速下落 :按下下箭头 ↓ 可以使方块加速下落。
        直接落下 :按下空格键 Space 可以让方块直接落到最底部。
        重新开始 :游戏结束后,按下 R 键可以重新开始游戏。

3.游戏画面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2340356.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

你学会了些什么200601?--Flask搭建造测试数据平台

搭建造数平台的环境&#xff1a; ***python3.7 ***html5 ***css ***JavaScript ***Ajax ***MySQL 前台页面的显示 1.为了页面美化&#xff0c;使用了JavaScript&#xff0c;通过逐级展开/隐藏的的方式显示下一级菜单 2.为了在提交表单数据时页面不发生跳转&#xff0c;需要引用…

【音视频】FLV格式分析

FLV概述 FLV(Flash Video)是Adobe公司推出的⼀种流媒体格式&#xff0c;由于其封装后的⾳视频⽂件体积⼩、封装简单等特点&#xff0c;⾮常适合于互联⽹上使⽤。⽬前主流的视频⽹站基本都⽀持FLV。采⽤FLV格式封装的⽂件后缀为.flv。 FLV封装格式是由⼀个⽂件头(file header)和…

Keil5没有stm32的芯片库

下载完重启就行了&#xff0c;我这里就不演示了&#xff0c;stm已经下载&#xff0c;随便选的一个芯片库演示一下

【DVWA 靶场通关】 File Inclusion(文件包含漏洞)

1. 前言 文件包含漏洞 是 Web 应用中较为常见的漏洞之一&#xff0c;攻击者通过操控文件路径&#xff0c;访问或包含系统上的敏感文件&#xff0c;甚至执行恶意代码。DVWA&#xff08;Damn Vulnerable Web Application&#xff09;提供了一个理想的实验环境&#xff0c;让安全…

游戏引擎学习第229天

仓库:https://gitee.com/mrxiao_com/2d_game_5 回顾上次内容并介绍今天的主题 上次留下的是一个非常简单的任务&#xff0c;至少第一步是非常简单的。我们需要在渲染器中加入排序功能&#xff0c;这样我们的精灵&#xff08;sprites&#xff09;才能以正确的顺序显示。为此我…

【C++编程入门】:从零开始掌握基础语法

C语言是通过对C语言不足的地方进行优化创建的&#xff0c;C在C语言之上&#xff0c;C当然也兼容C语言&#xff0c; 在大部分地方使用C比C更方便&#xff0c;可能使用C需要一两百行代码&#xff0c;而C只需要五六十行。 目录 C关键字 命名空间 缺省参数 缺省参数分类 函数…

网络开发基础(游戏方向)之 概念名词

前言 1、一款网络游戏分为客户端和服务端两个部分&#xff0c;客户端程序运行在用户的电脑或手机上&#xff0c;服务端程序运行在游戏运营商的服务器上。 2、客户端和服务端之间&#xff0c;服务端和服务端之间一般都是使用TCP网络通信。客户端和客户端之间通过服务端的消息转…

【源码】【Java并发】【AQS】从ReentrantLock、Semaphore、CutDownLunch、CyclicBarrier看AQS源码

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f4da;欢迎订阅专栏…

k8s介绍与实践

第一节 理论 基础介绍&#xff0c;部署实践&#xff0c;操作实践&#xff0c;点击这里学习 第二节 dashboard操作 查看安装的dashboard服务信息 kubectl get pod,svc -n kubernetes-dashboard 网页登录地址&#xff1a;https://server_ip:30976/#/login 创建token kube…

KRaft面试思路引导

Kafka实在2.8之后就用KRaft进行集群管理了 Conroller负责选举Leader&#xff0c;同时Controller管理集群元数据状态信息&#xff0c;并将元数据信息同步给各个分区的Leader 和Zookeeper管理一样&#xff0c;会选出一个Broker作为Controller去管理整个集群&#xff0c;但是元数…

FreeRTOS菜鸟入门(六)·移植FreeRTOS到STM32

目录 1. 获取裸机工程模版 2. 下载 FreeRTOS V9.0.0 源码 3. FreeRTOS文件夹内容简介 3.1 FreeRTOS文件夹 3.1.1 Demo文件夹 3.1.2 License 文件夹 3.1.3 Source 文件夹 3.2 FreeRTOS-Plus 文件夹 4. 往裸机工程添加 FreeRTOS 源码 5. 拷贝 FreeRTOSConfig…

14.第二阶段x64游戏实战-分析人物的名字

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;13.第二阶段x64游戏实战-分析人物等级和升级经验 名字&#xff08;中文英文符号…

【CS*N是狗】亲测可用!!WIN11上禁用Chrome自动更新IDM插件

现象&#xff1a;每次打开chrome后IDM会弹出提示插件版本不一致。经过排查后发现是chrome把IDM插件给更新了&#xff0c;导致IDM提示版本不匹配。经过摸索后&#xff0c;得到了可行的方案。 第一步&#xff0c;打开Chrome&#xff0c;把IDM插件卸载掉&#xff0c;然后重新安装I…

漫游git rebase + 浅谈git checkout和git branch -f的分支命令

今天学了两个命令非常有意思&#xff1a;一个是git checkout&#xff0c;一个是git branch -f。我们可以认为在提交树上&#xff0c;任何一个节点代表着一次提交。并且&#xff0c;git commit将会在 H E A D HEAD HEAD指针指向的节点上进行进一步提交。将每一个分支名视为标记当…

深入理解 React 组件的生命周期:从创建到销毁的全过程

React 作为当今最流行的前端框架之一&#xff0c;其组件生命周期是每个 React 开发者必须掌握的核心概念。本文将全面剖析 React 组件的生命周期&#xff0c;包括类组件的各个生命周期方法和函数组件如何使用 Hooks 模拟生命周期行为&#xff0c;帮助开发者编写更高效、更健壮的…

OpenCV 图形API(44)颜色空间转换-----将图像从 BGR 色彩空间转换为 RGB 色彩空间函数BGR2RGB()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从BGR色彩空间转换为RGB色彩空间。 该函数将输入图像从BGR色彩空间转换为RGB。B、G和R通道值的常规范围是0到255。 输出图像是8位无符号3通…

配置nginx服务,通过多ip区分多网站

首先关闭防火墙,setenforce 0 关过了,不截图了 多IP,首先配置多个IP地址 可以在vm增加虚拟网卡,也可以在同一网卡配置多个IP,我用第一种 记得点确定 查看新的虚拟网卡IP 没有IP,配置一个 安装nginx 写配置 server{listen 192.168.214.130:80;root /www/ip/130; # 资源根目…

[k8s实战]Containerd 1.7.2 离线安装与配置全指南(生产级优化)

[k8s实战]Containerd 1.7.2 离线安装与配置全指南&#xff08;生产级优化&#xff09; 摘要&#xff1a;本文详细讲解在无外网环境下部署 Containerd 1.7.2 容器运行时的完整流程&#xff0c;涵盖二进制包安装、私有镜像仓库配置、Systemd服务集成等关键步骤&#xff0c;并提供…

解决Windows安全中心显示空白页面

1、电脑重装系统后&#xff0c;发现原本一些软件打不开了&#xff0c;电脑莫名认为有病毒&#xff0c;自动删除插件。附图。 2、第一反应是电脑防火墙的原因&#xff0c;默认威胁防护识别到了病毒软件&#xff0c;自动删除。在开始屏幕搜Windows安全中心&#xff0c;打开之后发…

【MQ篇】初识MQ!

目录 一、什么是MQ&#xff1f;简单来说就是个“快递中转站” &#x1f4e6;二、为什么要用MQ&#xff1f;用了它&#xff0c;好处多多&#xff01;&#x1f929;三、MQ的应用场景&#xff1a;各行各业都能用&#xff01;&#x1f30d;四、MQ的优缺点&#xff1a;硬币的两面&am…