Skip to content

gulimuzun/tetris

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

俄罗斯方块:单机与局域网对战

这是一个使用 Python 3 和 Pygame 做的俄罗斯方块小项目。除了普通单机模式,还加了一个局域网双人模式:两边各玩各的棋盘,60 秒后比较分数。界面只用了 Pygame 的基本绘制和文字,没有额外的图片素材。

主要功能

单机模式

  • 标准 10×20 棋盘和 I、O、T、S、Z、J、L 七种方块
  • 7-bag 随机算法,保证每轮七种方块各出现一次
  • 左右移动、自动下落、软降和硬降
  • 顺时针、逆时针旋转和简化墙踢
  • 幽灵方块提示硬降位置
  • 方块暂存及下一个方块预览
  • 0.5 秒落地锁定时间
  • 单行、多行消除
  • 分数、累计消行、等级和连击显示
  • 等级提高后自动加快下落
  • 暂停、恢复和游戏结束界面

局域网对战

  • 一名玩家创建房间,另一名玩家加入
  • 使用 UDP 广播自动搜索同一局域网内的房间
  • 自动搜索不可用时可手动输入主机 IPv4 地址
  • 使用 TCP 可靠传输双方棋盘和分数
  • 主机统一发起比赛
  • 比赛开始前显示准备倒计时
  • 每局固定持续 60 秒
  • 双方屏幕实时显示自己和对手的棋盘、操作结果及分数
  • 时间结束后按分数判断胜利、失败或平局
  • 对手断开时显示提示,不会直接导致程序崩溃

联机玩法是独立棋盘计分赛,不会向对手发送垃圾行。一方提前堆满后停止操作,但比赛仍等待 60 秒结束,再比较双方分数。

游戏操作

功能 按键
向左移动
向右移动
软降
顺时针旋转 X
逆时针旋转 Z
硬降 Space
暂存/交换方块 C
单机暂停/继续 P
返回菜单/退出房间 Esc

计分规则

计分由独立的 ScoreSystem 管理,棋盘规则只负责报告发生了什么事件。

下落分

  • 软降:每主动下降一格获得 1 分
  • 硬降:每下降一格获得 2 分
  • 自动下落不计分

消行分

一次消除 基础分
1 行 100
2 行 300
3 行 500
4 行 800

实际消行分为:

基础分 × 当前等级 + 连击奖励

连续两个或更多方块均产生消行时,奖励为 连击索引 × 50。某个方块锁定后没有消行,连击立即中断。每累计消除 10 行提升一级。

环境要求

  • Python 3.10 或更高版本
  • Pygame 2.6.x
  • Windows 10/11 或较新的 macOS
  • 联机设备位于允许相互访问的同一 IPv4 局域网

界面使用系统自带中文字体:

  • Windows:微软雅黑 C:/Windows/Fonts/msyh.ttc
  • macOS:华文黑体 /System/Library/Fonts/STHeiti Medium.ttc

安装与启动

进入项目目录,安装依赖:

python -m pip install -r requirements.txt

启动游戏:

python main.py

部分系统需要使用:

python3 -m pip install -r requirements.txt
python3 main.py

单机使用流程

  1. 启动程序。
  2. 点击“单机模式”。
  3. 使用方向键、旋转键、硬降和暂存键操作。
  4. 查看右侧的分数、消行、等级和连击。
  5. 堆叠到出生区域后游戏结束,按 Esc 返回菜单。

联机使用流程

主机

  1. 启动游戏并进入“联机模式”。
  2. 点击“创建房间”。
  3. 将界面显示的局域网 IP 告知另一名玩家。
  4. 等待对手连接。
  5. 对手连接成功后点击“开始 60 秒对战”。

客户端

  1. 连接与主机相同的局域网。
  2. 进入“联机模式”。
  3. 点击“搜索局域网”,程序会连接发现的第一个房间。
  4. 如果搜索不到,在输入框键入主机 IPv4 地址,再点击“连接 IP”。
  5. 等待主机开始比赛。

网络端口

协议 端口 用途
UDP 45678 房间发现与响应
TCP 45679 昵称、开始消息和游戏快照

Windows 防火墙或 macOS 防火墙询问时,需要允许 Python 接收局域网连接。访客 Wi-Fi、部分校园网和开启客户端隔离的路由器可能禁止设备互访。

项目结构

.
├── main.py                    程序入口
├── requirements.txt           Python 依赖
├── README.md                  项目使用说明
├── tetris/
│   ├── __init__.py
│   ├── config.py              窗口、棋盘、颜色和端口配置
│   ├── core.py                方块、棋盘、玩法和独立计分系统
│   ├── ui.py                  字体、按钮、面板、方格和棋盘绘制
│   ├── network.py             UDP 发现、TCP 会话和消息队列
│   └── app.py                 主循环、场景、输入、绘制和联机控制
├── tests/
│   └── test_core.py           玩法与计分自动测试
└── docs/                      需求、设计、协议、测试和小组分工文档

架构设计

项目按规则、界面、网络和应用控制分层:

main.py
   └── TetrisApp
       ├── TetrisGame
       │   ├── Piece / Bag
       │   └── ScoreSystem
       ├── ui.py
       └── LanSession

TetrisGame

负责棋盘和全部俄罗斯方块玩法,包括碰撞、移动、旋转、下落、暂存、锁定、消行和游戏结束。它不读取键盘,也不进行绘制,因此可以独立测试。

ScoreSystem

只管理分数、累计消行、等级和连击。TetrisGame 在软降、硬降和消行发生时调用计分接口,不在棋盘代码中重复分数公式。

ui.py

提供通用 Pygame 绘制函数。棋盘绘制函数既可以画单机大棋盘,也可以通过不同单元格尺寸画联机对手的小棋盘。

LanSession

UDP 用于房间发现,TCP 使用 UTF-8 JSON Lines 传输消息。网络操作运行在守护线程中,Pygame 主线程通过线程安全队列收发字典,避免连接或接收操作冻结画面。

TetrisApp

管理四种场景:

menu       主菜单
single     单机游戏
network    联机大厅
battle     联机对战

主循环每帧读取事件、更新当前场景、绘制画面,最后调用 pygame.display.flip() 显示结果。

联机协议概览

TCP 每条消息为一行 JSON:

JSON对象 + 换行符

主要消息:

{"type":"hello","name":"玩家名称"}
{"type":"start","delay":1.5}
{"type":"state","data":{"board":[],"score":0,"lines":0,"level":1,"game_over":false}}
{"type":"final","score":3200}

start.delay 表示收到消息后等待多少秒开始,因此不要求两台电脑的系统时钟完全一致。state 大约每 80ms 发送一次。对战双方本地模拟自己的棋盘,网络快照用于向对手展示实时状态。倒计时结束后双方交换 final,使用最终分数判胜,避免用到尚未抵达的旧快照。

运行测试

执行全部自动测试:

python -m unittest discover -s tests -v

测试覆盖:

  • 7-bag 是否包含全部七种方块
  • 棋盘边界碰撞
  • 硬降锁定
  • 单行消除
  • 每个活动块只能暂存一次
  • 软降和硬降分数
  • 消行、等级和连击
  • 无消行时中断连击
  • 方块落地后保持完整的 0.5 秒锁定时间

小组分工

三人按模块分工,合并时以公开接口为准:

  • 成员一:除计分外的完整俄罗斯方块玩法
  • 成员二:UI、输入和场景绘制
  • 组长:独立计分系统、应用控制、局域网和最终集成

具体到类和方法的所有权见:

项目文档

README 放常用的运行和使用信息,具体的分工、接口和 Git 流程分开记在下面三份文档里:

文档 内容
小组分工与集成方案 三人代码所有权和集成流程
完整接口文档 类、方法、数据格式和网络协议契约
Git 与 GitHub 协作指南 从空仓库初始化到PR合并和发布

常见问题

中文显示为方框

确认系统字体文件存在。项目在 Windows 使用微软雅黑,在 macOS 使用华文黑体。如果系统经过精简并删除字体,需要恢复对应系统字体或修改 tetris/ui.py 中的字体路径。

搜索不到局域网房间

确认两台设备连接同一路由器,关闭访客隔离,并允许 UDP 45678。也可以直接输入主机显示的 IPv4 地址。

可以连接但看不到实时状态

确认防火墙允许 TCP 45679,并检查两端是否运行相同版本的网络消息格式。

端口被占用

确认没有旧游戏进程仍在运行。正常退出联机房间会关闭监听和连接套接字。

当前范围

当前版本专注于经典单机和局域网计分对战,不包含垃圾行攻击、互联网服务器、账号系统、排行榜、观战、断线重连、音效或外部图片素材。

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages