TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9.8 KiB
9.8 KiB
俄罗斯方块游戏 - 完整使用指南
📋 系统要求
- PHP 版本: >= 8.4.0
- 操作系统: Windows 10/11
- 编译器: MSVC (Microsoft Visual C++)
- 依赖: PHPX 编译器框架
🎮 游戏介绍
这是一个使用 PHP 和 C++ 混合编程的俄罗斯方块游戏示例,展示了:
- PHP 编写高层游戏逻辑
- C++ 提供底层图形 API 和性能关键代码
- 通过 Box 机制在 PHP 和 C++ 之间传递对象
📁 项目结构
tetris/
├── main.php # 完整版游戏主程序
├── test-simple.php # 简化测试版(用于快速验证)
├── project.yml # 项目配置文件
├── README.md # 项目说明
├── USAGE_GUIDE.md # 本使用指南
├── php-src/
│ └── tetris.stub.php # C++ 函数的 PHP 声明
└── cpp-src/
└── tetris.cc # C++ 实现(游戏引擎 + 图形渲染)
🔧 编译方法
方法一:编译完整版游戏
cd examples/tetris
php ../../bin/compiler.php build main.php
或使用 project.yml:
cd examples/tetris
php ../../bin/compiler.php build .
方法二:编译简化测试版
cd examples/tetris
php ../../bin/compiler.php build test-simple.php
编译选项
# 启用优化
php ../../bin/compiler.php build -O2 main.php
# 启用调试信息
php ../../bin/compiler.php build --debug-info main.php
# 指定输出文件名
php ../../bin/compiler.php build -o tetris-game main.php
# 并行编译(加速)
php ../../bin/compiler.php build -j 8 main.php
🚀 运行游戏
编译成功后,会在 build/ 目录生成可执行文件:
# 运行完整版游戏
.\build\tetris.exe
# 或运行测试版
.\build\test-simple.exe
🎯 游戏控制
键盘操作
| 按键 | 功能 |
|---|---|
| ← (左箭头) | 向左移动方块 |
| → (右箭头) | 向右移动方块 |
| ↑ (上箭头) | 旋转方块 |
| ↓ (下箭头) | 加速下落 |
| 空格键 | 直接落下(硬降) |
游戏规则
-
基本玩法
- 不同形状的方块从顶部随机出现
- 玩家可以移动和旋转方块
- 方块落地后固定,新方块继续出现
-
消除规则
- 当一行被完全填满时,该行消除
- 一次消除多行有额外奖励分数
- 消除后上方的方块会自动下落
-
计分系统
- 消除 1 行:100 分
- 消除 2 行:400 分(2×2×100)
- 消除 3 行:900 分(3×3×100)
- 消除 4 行:1600 分(4×4×100)
-
难度递增
- 初始下落间隔:500 毫秒
- 每获得 500 分,速度提升一级
- 最快下落间隔:100 毫秒
-
游戏结束
- 当新方块无法放置时,游戏结束
- 显示最终得分
- 可以选择重新开始或退出
🏗️ 技术架构
三层架构设计
1. C++ 层 (cpp-src/tetris.cc)
TetrisBox 类 - 继承自 Box
class TetrisBox : public Box {
public:
int board[BOARD_HEIGHT][BOARD_WIDTH]; // 游戏面板
int currentShape[4][4]; // 当前方块
int currentX, currentY; // 当前位置
int currentType; // 方块类型
int score; // 分数
bool gameOver; // 游戏状态
// 核心算法
void spawnNewPiece(); // 生成新方块
bool isValidPosition(); // 碰撞检测
void rotate(); // 旋转
bool moveDown/moveLeft/moveRight(); // 移动
void lockPiece(); // 固定方块
void clearLines(); // 消除行
};
导出的 C++ 函数(以 php_ 前缀命名):
php_tetris_new()- 创建游戏实例php_tetris_reset()- 重置游戏php_tetris_get_score()- 获取分数php_tetris_is_game_over()- 检查游戏结束php_tetris_rotate/move_*()- 方块控制php_tetris_render()- 图形渲染php_tetris_handle_key()- 键盘处理
2. Stub 层 (php-src/tetris.stub.php)
声明所有 C++ 函数供 PHP 调用:
function tetris_new(): mixed {}
function tetris_get_score(mixed $game): int {}
function tetris_move_down(mixed $game): bool {}
// ... 其他函数声明
3. PHP 层 (main.php)
TetrisGame 类 - 游戏主控制器
class TetrisGame {
private mixed $game; // C++ Box 对象
private int $hWnd; // 窗口句柄
private int $lastDropTime; // 上次下落时间
private int $dropInterval; // 下落间隔
public function initWindow() // 初始化窗口
public function run() // 游戏主循环
private function handleKeyPress() // 处理输入
private function handleGameOver() // 处理游戏结束
}
Box 对象传递机制
C++ 层 PHP 层
┌─────────────┐
│ TetrisBox │ new TetrisBox()
│ extends Box│ ──────────────► mixed $game
│ │ ◄────────────── 传递给 C++ 函数
└─────────────┘ toBox<TetrisBox>()
关键点:
- C++ 类必须继承自
Box - 使用
{new ClassName()}返回给 PHP - PHP 使用
mixed类型接收 - C++ 函数中使用
box.toBox<ClassName>()转换回来
Windows GUI 编程
窗口创建流程:
// 1. 注册窗口类(C++ 中完成)
// 2. 创建窗口
$hWnd = tetris_create_window("俄罗斯方块");
// 3. 显示窗口
tetris_show_window($hWnd, SW_SHOW);
// 4. 消息循环
while (PeekMessage($msg, $hWnd, 0, 0, 1)) {
// 处理消息
}
// 5. 渲染画面
tetris_render($game, $hWnd);
GDI 绘图:
- 使用
FillRect绘制方块 - 使用
Rectangle绘制边框 - 使用
CreateSolidBrush设置颜色 - 支持 UTF-8 中文显示(通过
MultiByteToWideChar转换)
🐛 常见问题
Q1: 编译时提示 PHP 版本过低
错误信息:
Composer detected issues in your platform: Your Composer dependencies
require a PHP version ">= 8.4.0". You are running 8.1.27.
解决方案:
- 升级 PHP 到 8.4+ 版本
- 或修改
composer.json中的版本要求(不推荐)
Q2: 编译成功但运行时没有窗口
可能原因:
- 使用了
--no-console参数但没有正确创建窗口 - 窗口创建失败
解决方案:
- 检查
tetris_create_window()返回值是否为 0 - 使用消息框调试:
tetris_messagebox(0, "Debug", "Info", 0) - 查看是否有错误日志
Q3: 中文显示乱码
解决方案: 确保:
- 源文件使用 UTF-8 编码保存
- C++ 中使用
MultiByteToWideChar转换 - 使用
MessageBoxW而不是MessageBoxA
Q4: 游戏运行卡顿
优化建议:
- 减少渲染频率(目前约 60 FPS)
- 使用
-O2优化级别编译 - 检查是否有内存泄漏
Q5: 如何调试游戏逻辑?
调试方法:
// 1. 使用 echo 输出(控制台模式)
echo "Score: " . tetris_get_score($game) . "\n";
// 2. 写入日志文件
file_put_contents('game.log', $message, FILE_APPEND);
// 3. 使用消息框
tetris_messagebox(0, $message, "Debug", MB_OK);
// 4. 使用调试模式编译
php ../../bin/compiler.php build --debug-info main.php
📊 性能分析
帧率控制
Sleep(16); // 约 60 FPS (1000ms / 60 ≈ 16ms)
自动下落计时
$currentTime = GetTickCount();
if ($currentTime - $this->lastDropTime > $this->dropInterval) {
tetris_move_down($this->game);
$this->lastDropTime = $currentTime;
}
速度调整
// 根据分数动态调整下落速度
$this->dropInterval = max(100, 500 - intdiv($score, 500) * 50);
🔬 扩展开发
添加新功能示例
1. 添加暂停功能
C++ 层 (tetris.cc):
Bool php_tetris_is_paused(var box) {
auto tetris = box.toBox<TetrisBox>();
return tetris->paused;
}
void php_tetris_toggle_pause(var box) {
auto tetris = box.toBox<TetrisBox>();
tetris->paused = !tetris->paused;
}
Stub 层 (tetris.stub.php):
function tetris_is_paused(mixed $game): bool {}
function tetris_toggle_pause(mixed $game): void {}
PHP 层 (main.php):
case VK_P:
tetris_toggle_pause($this->game);
break;
2. 添加音效
可以使用 Windows API 的 PlaySound 函数:
#include <mmsystem.h>
void php_play_sound(String wavFile) {
PlaySound(wavFile.data(), NULL, SND_FILENAME | SND_ASYNC);
}
3. 保存最高分
function saveHighScore(int $score): void {
file_put_contents('highscore.txt', $score);
}
function loadHighScore(): int {
if (file_exists('highscore.txt')) {
return (int)file_get_contents('highscore.txt');
}
return 0;
}
📚 学习资源
参考示例
examples/win32-hello- Windows GUI 基础examples/prime- Box 对象封装docs/MIXED_CPP_PHP.md- C++ 和 PHP 混合编程
外部资源
🎓 教学要点
这个项目适合学习:
-
混合编程架构
- 如何在 PHP 和 C++ 之间分工
- 对象传递机制(Box)
- 函数导出规范
-
游戏开发基础
- 游戏循环设计
- 事件驱动编程
- 状态管理
-
Windows 编程
- Win32 API 使用
- 消息循环处理
- GDI 图形绘制
-
性能优化
- 计算密集型任务交给 C++
- PHP 负责高层逻辑
- 合理的帧率控制
📝 许可证
本项目遵循与 PHPX 编译器相同的许可证。
🤝 贡献
欢迎提交改进建议和 Bug 报告!
祝游戏愉快! 🎮