《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-🎮 俄罗斯方块:用旋转矩阵打造经典 🧊
大家好!今天我将带大家用MATLAB实现经典的俄罗斯方块游戏。我们将从数学原理出发,通过旋转矩阵实现方块的变形,最终完成一个可玩的游戏版本。让我们一起进入这个充满趣味的编程之旅吧!✨
文章目录
- [《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-🎮 俄罗斯方块:用旋转矩阵打造经典 🧊](#《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-🎮 俄罗斯方块:用旋转矩阵打造经典 🧊)
-
- [1. 游戏设计思路 🧠](#1. 游戏设计思路 🧠)
-
- [1.1 模块设计](#1.1 模块设计)
- [1.2 流程设计](#1.2 流程设计)
-
- [1.2.1 流程图说明](#1.2.1 流程图说明)
- [1.2.2 关键路径说明](#1.2.2 关键路径说明)
- [2. 旋转矩阵原理(重点) 🔄](#2. 旋转矩阵原理(重点) 🔄)
-
- [2.1 旋转矩阵基础](#2.1 旋转矩阵基础)
- [2.2 方块旋转实现](#2.2 方块旋转实现)
- [3. 游戏架构设计 🏗️](#3. 游戏架构设计 🏗️)
- [4. MATLAB实现详解 💻](#4. MATLAB实现详解 💻)
-
- [4.1 初始化游戏](#4.1 初始化游戏)
- [4.2 旋转函数实现](#4.2 旋转函数实现)
- [4.3 碰撞检测](#4.3 碰撞检测)
- [5. 完整代码 🎮](#5. 完整代码 🎮)
- [6. 总结与扩展 🚀](#6. 总结与扩展 🚀)

🎉 正文开始前,先来看看最终效果图! 🎉
奈何我自己的水平有点菜🐣,只得了 900分......你们也来玩一局试试吧!看看自己能拿多少分💪
🔥 挑战一下,把你的得分打在评论区 🔥
看看谁的分数最高🏆,说不定你就是那个隐藏的大神哦!✨
(快来PK吧!😎)
1. 游戏设计思路 🧠
1.1 模块设计
俄罗斯方块的核心机制可以分解为以下几个部分:
- 方块生成:7种基本形状(I, J, L, O, S, T, Z)
- 方块旋转:通过旋转矩阵实现90°旋转
- 方块移动:左右移动和加速下落
- 碰撞检测:判断方块是否可以移动或旋转
- 消行计分:当一行填满时消除并计分
- 游戏结束:当方块堆叠到顶部时结束游戏
1.2 流程设计
以下是俄罗斯方块游戏的完整流程图设计,包含移动、碰撞检测、旋转处理等流程:
旋转处理 碰撞检测 是 否 左箭头 右箭头 下箭头 上箭头 空格 是 否 是 否 是 否 计算旋转后坐标 旋转方块 应用旋转矩阵 检查旋转合法性 检查边界 移动合法? 检查已有方块 返回检测结果 开始游戏 初始化游戏板 生成新方块 游戏结束? 游戏结束 绘制游戏界面 玩家输入 尝试左移 尝试右移 加速下落 快速下落 更新方块位置 固定方块 检查消除行 有完整行? 消除行并计分 自动下落计时结束? 尝试下落
1.2.1 流程图说明
1.2.1.1. 游戏初始化阶段:
- 初始化游戏板(20x10矩阵)
- 生成第一个方块
1.2.1.2. 主游戏循环:
绘制界面 处理输入 自动下落
1.2.1.3. 输入处理分支:
- 左右移动:修改x坐标
- 旋转:应用旋转矩阵
- 下落:修改y坐标
1.2.1.4. 关键判断节点:
- 移动/旋转合法性检查(碰撞检测)
- 自动下落计时器
- 行消除判断
1.2.1.5. 特殊处理流程:
- 旋转计算:应用旋转矩阵后必须通过碰撞检测
- 快速下落:连续执行下落直到碰撞
1.2.2 关键路径说明
1.2.2.1. 方块移动流程:
玩家输入 → 计算新位置 → 碰撞检测 → 更新位置/固定方块
1.2.2.2. 旋转特殊处理:
旋转请求 → 计算旋转坐标 → 矩阵变换 → 合法性检查 → 更新状态
1.2.2.3. 自动下落逻辑:
计时结束 → 尝试下落 → 成功则更新/失败则固定
这个流程图完整展示了游戏的所有可能状态转换,特别是突出了旋转矩阵的应用位置(在旋转处理子流程中)。建议在阅读代码时对照此流程图理解游戏逻辑。
今天我们将重点讲解旋转矩阵的实现,这是游戏中最有趣的数学部分!🤓
2. 旋转矩阵原理(重点) 🔄
2.1 旋转矩阵基础
在二维空间中,旋转矩阵可以将任何点绕原点旋转θ角度。对于90°旋转(θ=π/2),旋转矩阵为:
R = [ 0 − 1 1 0 ] R = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix} R=[01−10]
应用到点(x,y)上:
x ′ = 0 ⋅ x + ( − 1 ) ⋅ y = − y y ′ = 1 ⋅ x + 0 ⋅ y = x \begin{aligned} x' &= 0 \cdot x + (-1) \cdot y = -y \\ y' &= 1 \cdot x + 0 \cdot y = x \end{aligned} x′y′=0⋅x+(−1)⋅y=−y=1⋅x+0⋅y=x
2.2 方块旋转实现
俄罗斯方块中,每个方块由4个小方块(我们称为"方块块")组成。旋转时,我们需要:
- 找到方块的旋转中心(通常是中心块或靠近中心的位置)
- 将每个方块块相对于旋转中心应用旋转矩阵
- 确保旋转后的位置是合法的(不超出边界或与已有方块重叠)
💡 小技巧:我们可以将方块表示为相对坐标,这样旋转计算会更方便!
3. 游戏架构设计 🏗️
我们的MATLAB实现将采用以下结构:
- 主循环:控制游戏流程
- 游戏板:20行×10列的矩阵表示
- 当前方块:存储当前下落方块的信息
- 绘图函数:实时更新游戏界面
- 键盘回调:处理玩家输入
4. MATLAB实现详解 💻
4.1 初始化游戏
matlab
function tetris()
% 游戏参数
boardWidth = 10;
boardHeight = 20;
blockSize = 25; % 每个小方块的像素大小
% 创建图形窗口
fig = figure('Name','俄罗斯方块','NumberTitle','off',...
'KeyPressFcn',@keyPress,...
'Position',[200 200 boardWidth*blockSize+100 boardHeight*blockSize+100]);
% 创建游戏板
ax = axes('Parent',fig,'Position',[0.05 0.05 0.7 0.9]);
axis equal; axis([0 boardWidth 0 boardHeight]);
set(ax,'XTick',0:boardWidth,'YTick',0:boardHeight,'XColor','k','YColor','k');
grid on; hold on;
title('俄罗斯方块 - MATLAB版');
% 初始化游戏板矩阵 (0=空, 1-7=不同颜色方块)
board = zeros(boardHeight, boardWidth);
% 方块形状定义 (相对坐标)
shapes = {
[0 0; 0 1; 0 2; 0 3], % I
[0 0; 0 1; 0 2; 1 0], % J
[0 0; 0 1; 0 2; 1 2], % L
[0 0; 0 1; 1 0; 1 1], % O
[0 0; 0 1; 1 1; 1 2], % S
[0 0; 0 1; 0 2; 1 1], % T
[0 0; 1 0; 1 1; 2 1] % Z
};
% 方块颜色
colors = [
0 1 1; % 青色 - I
0 0 1; % 蓝色 - J
1 0.5 0; % 橙色 - L
1 1 0; % 黄色 - O
0 1 0; % 绿色 - S
1 0 1; % 紫色 - T
1 0 0 % 红色 - Z
];
4.2 旋转函数实现
这是最核心的部分!✨
matlab
% 旋转当前方块
function rotatePiece()
% 获取当前方块的旋转中心 (通常是第一个方块块)
pivot = currentPiece(1,:);
% 应用旋转矩阵
rotated = zeros(size(currentPiece));
for i = 1:size(currentPiece,1)
% 相对于旋转中心的坐标
relPos = currentPiece(i,:) - pivot;
% 应用90度旋转矩阵
newRelPos = [-relPos(2), relPos(1)];
% 计算新位置
rotated(i,:) = pivot + newRelPos;
end
% 检查旋转后是否合法
if canMove(rotated, currentPos)
currentPiece = rotated;
drawBoard();
end
end
4.3 碰撞检测
matlab
% 检查移动/旋转是否合法
function valid = canMove(piece, pos)
valid = true;
for i = 1:size(piece,1)
% 计算实际位置
x = pos(1) + piece(i,1);
y = pos(2) + piece(i,2);
% 检查边界
if x < 1 || x > boardWidth || y < 1 || y > boardHeight
valid = false;
return;
end
% 检查是否与已有方块重叠
if y <= boardHeight && board(y,x) ~= 0
valid = false;
return;
end
end
end
5. 完整代码 🎮
以下是适配MATLAB 2016b的完整可运行代码:
matlab
function tetris()
% 游戏参数
boardWidth = 10;
boardHeight = 20;
blockSize = 25; % 每个小方块的像素大小
% 创建图形窗口
fig = figure('Name','俄罗斯方块','NumberTitle','off',...
'KeyPressFcn',@keyPress,...
'Position',[200 200 boardWidth*blockSize+100 boardHeight*blockSize+100]);
% 创建游戏板
ax = axes('Parent',fig,'Position',[0.05 0.05 0.7 0.9]);
axis equal; axis([0 boardWidth 0 boardHeight]);
set(ax,'XTick',0:boardWidth,'YTick',0:boardHeight,'XColor','k','YColor','k');
grid on; hold on;
title('俄罗斯方块 - MATLAB版');
% 初始化游戏板矩阵 (0=空, 1-7=不同颜色方块)
board = zeros(boardHeight, boardWidth);
% 方块形状定义 (相对坐标)
shapes = {
[0 0; 0 1; 0 2; 0 3], % I
[0 0; 0 1; 0 2; 1 0], % J
[0 0; 0 1; 0 2; 1 2], % L
[0 0; 0 1; 1 0; 1 1], % O
[0 0; 0 1; 1 1; 1 2], % S
[0 0; 0 1; 0 2; 1 1], % T
[0 0; 1 0; 1 1; 2 1] % Z
};
% 方块颜色
colors = [
0 1 1; % 青色 - I
0 0 1; % 蓝色 - J
1 0.5 0; % 橙色 - L
1 1 0; % 黄色 - O
0 1 0; % 绿色 - S
1 0 1; % 紫色 - T
1 0 0 % 红色 - Z
];
% 游戏状态变量
currentPiece = [];
currentPos = [];
currentColor = [];
gameOver = false;
score = 0;
scoreText = uicontrol('Style','text','Position',[boardWidth*blockSize+20 300 80 30],...
'String',['分数: ' num2str(score)],...
'FontSize',12);
% 开始新游戏
newGame();
% 主游戏循环
while ~gameOver
moveDown();
pause(0.5); % 控制下落速度
end
% 新游戏初始化
function newGame()
board = zeros(boardHeight, boardWidth);
gameOver = false;
score = 0;
set(scoreText,'String',['分数: ' num2str(score)]);
newPiece();
drawBoard();
end
% 生成新方块
function newPiece()
shapeIdx = randi(7);
currentPiece = shapes{shapeIdx};
currentColor = colors(shapeIdx,:);
currentPos = [floor(boardWidth/2), boardHeight];
% 检查游戏是否结束
if ~canMove(currentPiece, currentPos)
gameOver = true;
msgbox(['游戏结束! 最终分数: ' num2str(score)],'游戏结束');
end
end
% 绘制游戏板
function drawBoard()
cla; % 清除当前轴
% 绘制已固定的方块
for y = 1:boardHeight
for x = 1:boardWidth
if board(y,x) ~= 0
color = colors(board(y,x),:);
rectangle('Position',[x-1 y-1 1 1],'FaceColor',color,'EdgeColor','k');
end
end
end
% 绘制当前方块
for i = 1:size(currentPiece,1)
x = currentPos(1) + currentPiece(i,1);
y = currentPos(2) + currentPiece(i,2);
if y >= 1 && y <= boardHeight
rectangle('Position',[x-1 y-1 1 1],'FaceColor',currentColor,'EdgeColor','k');
end
end
drawnow;
end
% 旋转当前方块
function rotatePiece()
% 获取当前方块的旋转中心 (通常是第一个方块块)
pivot = currentPiece(1,:);
% 应用旋转矩阵
rotated = zeros(size(currentPiece));
for i = 1:size(currentPiece,1)
% 相对于旋转中心的坐标
relPos = currentPiece(i,:) - pivot;
% 应用90度旋转矩阵
newRelPos = [-relPos(2), relPos(1)];
% 计算新位置
rotated(i,:) = pivot + newRelPos;
end
% 检查旋转后是否合法
if canMove(rotated, currentPos)
currentPiece = rotated;
drawBoard();
end
end
% 检查移动/旋转是否合法
function valid = canMove(piece, pos)
valid = true;
for i = 1:size(piece,1)
% 计算实际位置
x = pos(1) + piece(i,1);
y = pos(2) + piece(i,2);
% 检查边界
if x < 1 || x > boardWidth || y < 1
valid = false;
return;
end
% 检查是否与已有方块重叠
if y <= boardHeight && board(y,x) ~= 0
valid = false;
return;
end
end
end
% 移动方块
function movePiece(dx, dy)
newPos = currentPos + [dx, dy];
if canMove(currentPiece, newPos)
currentPos = newPos;
drawBoard();
return;
end
% 如果不能向下移动,固定方块
if dy < 0
fixPiece();
end
end
% 快速下落
function dropPiece()
while canMove(currentPiece, currentPos + [0 -1])
currentPos = currentPos + [0 -1];
end
fixPiece();
end
% 向下移动
function moveDown()
movePiece(0, -1);
end
% 固定方块到游戏板
function fixPiece()
for i = 1:size(currentPiece,1)
x = currentPos(1) + currentPiece(i,1);
y = currentPos(2) + currentPiece(i,2);
if y >= 1 && y <= boardHeight
% 确定颜色索引
colorIdx = find(ismember(colors, currentColor, 'rows'));
board(y,x) = colorIdx;
end
end
% 检查是否有行可以消除
checkLines();
% 生成新方块
newPiece();
drawBoard();
end
% 检查并消除完整的行
function checkLines()
linesToClear = [];
for y = 1:boardHeight
if all(board(y,:) ~= 0)
linesToClear = [linesToClear y];
end
end
if ~isempty(linesToClear)
% 消除行
board(linesToClear,:) = [];
% 添加新的空行
newRows = zeros(length(linesToClear), boardWidth);
board = [newRows; board];
% 更新分数
score = score + length(linesToClear) * 100;
set(scoreText,'String',['分数: ' num2str(score)]);
end
end
% 键盘回调函数
function keyPress(~, event)
if gameOver, return; end
switch event.Key
case 'leftarrow'
movePiece(-1, 0);
case 'rightarrow'
movePiece(1, 0);
case 'downarrow'
moveDown();
case 'uparrow'
rotatePiece();
case 'space'
dropPiece();
end
end
end
6. 总结与扩展 🚀
恭喜你完成了MATLAB俄罗斯方块的实现!🎉 通过这个项目,我们学到了:
- 旋转矩阵在游戏开发中的应用
- 二维游戏的基本架构设计
- MATLAB图形界面和回调函数的用法
扩展思路:
- 添加音效和动画效果 🎵
- 实现"下一个方块"预览功能 👀
- 添加难度随分数增加而提高的机制 📈
- 保存最高分记录 🏆
希望这篇教程对你有所帮助!如果有任何问题或建议,欢迎留言讨论。Happy coding! 💻😊