第 13 次大作业进展报告
5/23/25About 3 min
问题
请编写带有图形界面的普通三阶魔方模拟程序.
要求:
- 实现平移、放大、缩小和自适应大小的魔方展示功能.
- 请自定义编码表示魔方的各种可能操作, 每种编码表示其中 1 种操作.
- 实现打开文本文件的功能, 该文本文件由一系列编码组成, 对应魔方操作.
- 实现魔方操作功能: 可以交互实现每个操作, 也可以通过动画自动播放魔方的系列操作.
- 在操作或转动魔方时, 必须以动画的形式展示, 从而方便看清如何操作或转动.
- 可以保存魔方操作, 保存结果是由一系列编码组成文本文件.
- 编写文档详细介绍模拟算法与图形界面等内容.
参考:
- 雍俊海. 清华教授的小课堂魔方真好玩. 北京: 清华大学出版社.
1. 核心实现原理
我们的魔方模拟程序基于以下核心设计:
- 3D 坐标系: 使用 Y 轴向上,Z 轴向前,X 轴向右的右手坐标系
- 魔方结构:
- 3×3×3=27 个小立方体 (Cubie)
- 每个小立方体初始位置用三维坐标表示 (如 (-1,1,1))
- 操作表示:
enum Side { FRONT, BACK, UP, DOWN, LEFT, RIGHT };
class Action {
Side side; // 操作的面
bool clockwise; // 旋转方向(顺时针/逆时针)
};2. 关键功能实现
2.1. 魔方旋转动画
// 计算立方体新位置
glm::ivec3 Action::rotate(const glm::ivec3 location) const {
return glm::round(glm::rotate(loc, rotate_angle(), rotate_axis()));
}
// 更新动画进度
void Cubie::update(const Action action, float progress) {
glm::mat4x4 transform = action.rotate(this->_start, progress);
mesh->setTransform(transform); // 更新3D变换
}2.2. 操作序列处理
// 从文件读取操作序列
std::deque<Action> Action::from_file(const std::string &filepath) {
while (file >> ch) {
switch(ch) {
case 'F': actions.emplace_back(Action::FRONT); break;
case '\'': actions.back().clockwise = false; // 逆时针
}
}
}
// 保存操作序列到文件
void Action::to_file(const string &filepath, const deque<Action> &actions) {
for (const Action &action : actions) {
file << action.to_string() << ' '; // 如 "F'" 或 "R"
}
}2.3. 用户交互
// 键盘控制
if (ImGui::IsKeyPressed(ImGuiKey_F)) {
cube->action(Action(Action::FRONT, !shiftPressed));
}
// 文件操作按钮
if (ImGui::Button("Replay")) {
string filepath = polyscope::promptForFilename("demo/actions.txt");
cube->replay(Action::from_file(filepath));
}3. 程序架构
src/
├── cube.[h/cc] # 魔方核心逻辑
├── cubie.[h/cc] # 小立方体实现
├── action.[h/cc] # 魔方操作处理
├── utils.[h/cc] # 辅助函数
├── assets.[h/cc] # 3D模型加载
├── setup.[h/cc] # 场景初始化
└── main.cc # 主程序入口4. 使用指南
4.1. 基本操作
- 按键
F/B/U/D/L/R:旋转对应面(顺时针) - 按住
Shift+ 按键:逆时针旋转 - 界面按钮:录制/回放/保存操作序列
4.2. 文件格式
- 纯文本文件 (如
demo/actions.txt) - 示例:
F U R' D2 B'表示:- 前面顺时针旋转
- 上面顺时针旋转
- 右面逆时针旋转
- 下面旋转 180°
- 后面逆时针旋转
4.3. 动画效果
- 所有操作以平滑动画展示
- 旋转速度可调 (默认 0.5 秒完成 90° 旋转)
5. 关键技术点
5.1. 3D 变换:
- 使用 GLM 数学库进行矩阵变换
glm::rotate(progress * angle, axis) * transform;5.2. 状态管理
enum State { IDLE, RECORDING, REPLAYING };
class Cube {
State _state;
deque<Action> _actions; // 操作记录
bool _animating; // 动画状态
};5.3. 模型分组
// 按位置分组管理小立方体
string group_name(int x, int y, int z) {
return fmt::format("{:2d}{:2d}{:2d}", x, y, z);
}6. 编译运行
xmake config --mode=debug
xmake
xmake run