成品视频播放链接点击此处跳转观看。
使用matlab制作俄罗斯方块小游戏,首先考虑到的是使用GUI来完成,GUI可以实现方块的显示、键盘的控制、整体逻辑的实现。本文依照结构框架和实现代码来完成介绍。结构框架可分为初始化、逻辑控制、方块控制、按键控制、美化界面五个部分,每个部分下有着细化的分支流程。
1、初始化
此节作为俄罗斯方块的初始化部分,主要为整个界面的构造以及方块的种类定义。
1.1、方块生成
在matlab的GUI中为了表示方块,可以使用“静态文本”构件,静态文本可以通过两层循环调整出现位置,我生成了一个19*29的方格矩阵,背景采取灰色。实现代码为:
%俄罗斯方块显示框
for i = 1:Length
for j = 1:High-1
Block(i,j) = uicontrol(F,'style','text',...
'position',[(i-1)*Side_length+1,(j-1)*Side_length+5,Side_length*0.95,Side_length*0.95],...
'userdata',[i,j],'backgroundcolor',Grey_color);
end
end
1.2、颜色控制
在“静态文本”框中可以切换背景颜色,控制语句为:
Grey_color = [0.8,0.8,0.8];
Bule_color= [0.075,0.624,1.0];
set(handles.text1,'backgroundcolor',Grey_color);
set(handles.text2,'backgroundcolor',Bule_color);
颜色的数据属性对应的是RGB三色数值。
1.3、方块种类
在俄罗斯方块中方块种类存在七种,分别为 I、L(左)、L(右)、O、N(左)、N(右)、T,其形状如下图所示:
在代码中可以规定每个构型的定位点,然后根据其位置关系推导出其他三个方块的坐标,不同的方块代码如下所示:
%I
length1 = op_length;length2 = op_length;length3 = op_length;length4 = op_length;
high1 = op_high;high2 = op_high-1;high3 = op_high-2;high4 = op_high-3;
%L(左)
length1 = op_length;length2 = op_length;length3 = op_length;length4 = op_length+1;
high1 = op_high;high2 = op_high-1;high3 = op_high-2;high4 = op_high-2;
%L(右)
length1 = op_length;length2 = op_length;length3 = op_length;length4 = op_length-1;
high1 = op_high;high2 = op_high-1;high3 = op_high-2;high4 = op_high-2;
%O
length1 = op_length;length2 = op_length+1;length3 = op_length;length4 = op_length+1;
high1 = op_high;high2 = op_high;high3 = op_high-1;high4 = op_high-1;
%N(左)
length1 = op_length;length2 = op_length;length3 = op_length+1;length4 = op_length+1;
high1 = op_high;high2 = op_high-1;high3 = op_high-1;high4 = op_high-2;
%N(右)
length1 = op_length;length2 = op_length-1;length3 = op_length;length4 = op_length-1;
high1 = op_high;high2 = op_high-1;high3 = op_high-1;high4 = op_high-2;
%T
length1 = op_length;length2 = op_length-1;length3 = op_length+1;length4 = op_length;
high1 = op_high;high2 = op_high;high3 = op_high;high4 = op_high-1;
2、逻辑控制
此节为方块的逻辑操作部分,包括方块的向下移动、方块的速度叠加、得分情况判断、边界判定以及游戏结束判定。
2.1、方块下移
方块生成之后,按照一定速度向下移动,直到下降到最底部。其下降的逻辑为:(1)取消当前方块显示;(2)刷新方块下降后的坐标;(3)新增下降后的方块显示;(4)暂停代码运行固定时间。实现代码为:
%%方块往下走
while Bottom_Valid ==0 && Down_Valid ==0
%取消前个方块显示
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
set(op,'backgroundcolor',Grey_color);
%由于混合按键,Down_Valid数值会发生变化,再次进行判断
if Down_Valid == 0
op_high = op_high -1;
else
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
set(op,'backgroundcolor',Bule_color);
continue;
end
%新增方块显示
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
set(op,'backgroundcolor',Bule_color);
%添加声音
Play_Sound(1);%方块下降音效
pause(Speed);%每隔固定时间下落一格高度
%判断是否可下降
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
set(op,'backgroundcolor',Bule_color);
end
%传递下一个变形标志位
R_Num = R_Num_Next;
%添加声音
Play_Sound(3);%方块触底声音
end
2.2、随机生成方块
每次生成的方块均为七种方块的随机一个,实现代码如下:
R_Num = randi([1,7]);%设置随机方块
function [op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num)
switch R_Num
%串联需要注意矩阵维度一致
case 1
%I方块
case 2
%L方块(左)
case 3
%L方块(右)
case 4
%O方块
case 5
%N方块(左)
case 6
%N方块(右)
case 7
%T方块
end
end
2.3、方块下降速度随得分发生变化
为了难度随方块下降速度递增,每得一分后速度增加10%,实现代码如下:
%速度随分数发生变化
if mod(Rec_Score,1) == 0
if Rec_Score~=Rec_Score_Pre
Speed_In = Speed_In/1.1;
Speed = Speed/1.1;
end
end
Speed = Speed_In;%内部速度需要赋值
2.4、得分判定
当方块触底之后,对当前的方块进行判断,如若存在一行方块全为显示的状态,则取消当前行方块,并且计分一次。实现代码如下:
%检测四次
for Num = 1:4
%成功满足一行 消除这一行
for Row = 1:High-1 %逐行搜索
%检测是否满一行填充为蓝色
for Col = 1:Length
if isequal(get(Block(Col,Row),'backgroundcolor'),Bule_color)
else
Col = 1;%出现空白列数置为1
break%遇到灰色 跳出循环
end
end
Rec_Block = [];
%代表可以消除此行
if Col == Length
%记录得分情况
Rec_Score = Rec_Score+1;
Play_Sound(5);%方块消除音效
set(Rec_Score_Block,'string',num2str(Rec_Score));
for delete_Col = 1:Length
set(Block(delete_Col,Row),'backgroundcolor',Grey_color);
end
for Rec_Row = Row+1:High-1
for Rec_Col = 1:Length
if isequal(get(Block(Rec_Col,Rec_Row),'backgroundcolor'),Bule_color)
Rec_Block = [Rec_Block,Block(Rec_Col,Rec_Row-1)];
set(Block(Rec_Col,Rec_Row),'backgroundcolor',Grey_color);
end
end
end
set(Rec_Block,'backgroundcolor',Bule_color);
end
end
end
2.5、边界判定
方块移动左、右、下边界时需要停止移动,这里为三个函数实现判定:
%判断是否能够向下运动
function Down_Valid = Down_Judgment(Block,Length_matrix,High_matrix)
global Bule_color;
Down_Valid = 0;
for i = 1:length(Length_matrix)
if High_matrix(i) ~= 1
if isequal(get(Block(Length_matrix(i),High_matrix(i)-1),'backgroundcolor'),Bule_color)
Down_Valid = 1;
end
end
end
end
%完成对方块左右运动以及边界的判定
function Right_Valid= Right_Judgment(Block,Length_matrix,High_matrix)
%输入 Block: 方块句柄
% Length_matrix 方块坐标矩阵长度方向
% High_matrix 方块坐标矩阵高度方向
%输出 Right_Valid 判定值,0表示正常 1代表无法左移动 2代表无法右移动
global Bule_color
Right_Valid = 0;
for i = 1:length(Length_matrix)
%判断右运动判定
if Length_matrix(i) ~=19
if isequal(get(Block(Length_matrix(i)+1,High_matrix(i)),'backgroundcolor'),Bule_color)
Right_Valid = 1;
end
end
%右边界判定
if Length_matrix(i) ==19
Right_Valid = 1;
end
end
end
%完成对方块左右运动以及边界的判定
function Left_Valid= Left_Judgment(Block,Length_matrix,High_matrix)
%输入 Block: 方块句柄
% Length_matrix 方块坐标矩阵长度方向
% High_matrix 方块坐标矩阵高度方向
%输出 Left_Valid 判定值,0表示正常 1代表无法左移动 2代表无法右移动
global Bule_color
Left_Valid = 0;
for i = 1:length(Length_matrix)
%判断左运动判定
if Length_matrix(i) ~=1
if isequal(get(Block(Length_matrix(i)-1,High_matrix(i)),'backgroundcolor'),Bule_color)
Left_Valid = 1;
end
end
%左边界判定
if Length_matrix(i) ==1
Left_Valid = 1;
end
end
end
2.6、游戏结束判定
游戏结束的标志为当方块触底之后,如若存在方块显示在最上边一行,代表游戏已经结束,并且有弹窗和文字提示信息。
%游戏结束判定
for ii = 1:Length
if isequal(get(Block(ii,High-1),'backgroundcolor'),Bule_color)
%添加游戏结束音效
Play_Sound(4);
flag_stop = 1;
break;
end
end
if flag_stop == 1
break
end
3、方块控制
游戏的关键为使用键盘完成对方块的交互,在matlab的GUI中为设置方块移动以及变形的快捷键。
3.1、左右移动
键盘"<-"左键、"->"右键为控制方块的左右移动,左右移动的逻辑为使方块的坐标+1、-1,并且将触发函数的按键设置一下。
3.2、变形控制
方块的变形为方块按照一个方向旋转90°,每种方块有四种旋转后的形态,有些方块的对称性原因,旋转后的形态只有一种(O形)、两种(I形、N形左、N形右)。变形的按键设置为空格。
3.3、向下加速
当按下键盘的向下箭头时,方块会按照固定速度向下移动。
三种控制的实现代码为:
function Move_Block(hObject,eventdata,Block,R_Num)
Key = eventdata.Key;
switch Key
case 'rightarrow'
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
if Right_Valid ~= 1
set(op,'backgroundcolor',Grey_color);
op_length = op_length+1;
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
set(op,'backgroundcolor',Bule_color);
end
case 'leftarrow'
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
if Left_Valid ~= 1
set(op,'backgroundcolor',Grey_color);
op_length = op_length-1;
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
set(op,'backgroundcolor',Bule_color);
end
case 'downarrow'
Speed = 0.01;
case 'space'
%变形声音
Play_Sound(2);
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
if Deformation_Valid ~= 1
set(op,'backgroundcolor',Grey_color);
Shift_Num = Shift_Num+1;
if Shift_Num == 5
Shift_Num = 1;
end
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
if Deformation_Valid == 1
Shift_Num = Shift_Num - 1;
if Shift_Num == 0
Shift_Num = 4;
end
[op,Left_Valid,Right_Valid,Bottom_Valid,Down_Valid,Deformation_Valid] = Type_Block(Block,R_Num);
end
set(op,'backgroundcolor',Bule_color);
end
end
end
4、按键控制
按键控制可以实现游戏的开始、暂停、重新开始功能。
4.1、开始游戏
按下开始游戏按键后,方块开始下降。
%开始游戏按键
Pb_start = uicontrol(F,'style','pushbutton',...
'position',[Pb_start_x,Pb_start_y,Pb_start_length,Pb_start_high],...
'string','开始游戏');
set(Pb_start,...
'FontName','微软雅黑',...
'FontSize',10,'FontWeight','bold');
4.2、暂停游戏
按下暂停游戏按键后,方块运动停止。
%重新开始按键
Pb_reset = uicontrol(F,'style','pushbutton',...
'position',[Pb_reset_x,Pb_reset_y,Pb_reset_length,Pb_reset_high],...
'string','重新开始');
set(Pb_reset,...
'FontName','微软雅黑',...
'FontSize',10,'FontWeight','bold');
set(Pb_reset,'enable','off');
4.3、重新开始
游戏结束后,可以选择重新开始再次进行游戏。
%暂停按键
Pb_pause = uicontrol(F,'style','pushbutton',...
'position',[Pb_pause_x,Pb_pause_y,Pb_pause_length,Pb_pause_high],...
'string','暂停游戏');
set(Pb_pause,...
'FontName','微软雅黑',...
'FontSize',10,'FontWeight','bold');
5、美化界面
为了增加游戏的可玩性与观赏性,增加了得分统计、背景图片、开始游戏动画、游戏背景音乐。
5.1、得分统计
游戏没得一分,就会在框中显示提高一分,并且设置了一个数据库来保存最高得分,每次开始游戏后均会加载最高得分。代码如下:
% 得分统计框文本
Rec_Score_Block_Txt = uicontrol(F,'style','text',...
'position',[Rec_Score_x_Txt,Rec_Score_y_Txt,Rec_Score_Length_Txt,Rec_Score_High_Txt],...
'backgroundcolor',Grey_color);
set(Rec_Score_Block_Txt,'string','当前得分',...
'FontName','微软雅黑',...
'FontSize',16,'FontWeight','bold');
%得分统计框
Rec_Score_Block = uicontrol(F,'style','text',...
'position',[Rec_Score_x,Rec_Score_y,Rec_Score_Length,Rec_Score_High],...
'backgroundcolor',Grey_color);
set(Rec_Score_Block,'string',num2str(Rec_Score),...
'FontName','微软雅黑',...
'FontSize',16,'FontWeight','bold');
%历史最高得分文本
Rec_Score_Block_max_Txt = uicontrol(F,'style','text',...
'position',[Rec_Score_max_x_Txt,Rec_Score_max_y_Txt,Rec_Score_max_Length_Txt,Rec_Score_max_High_Txt],...
'backgroundcolor',Grey_color);
set(Rec_Score_Block_max_Txt,'string','历史最高',...
'FontName','微软雅黑',...
'FontSize',16,'FontWeight','bold');
%历史最高得分
load('Rec_Score_max.mat');
5.2、背景图片
在界面后加入一个卡通图片,增加趣味性,代码如下:
ha = axes('units','normalized','pos',[0 0 1 1]);
uistack(ha,'bottom');
ii = imread('风景.jpg');
image(ii);
colormap gray
set(ha,'handlevisibility','off','visible','off');
5.3、开始游戏动画
开始游戏后,会显示一次动画,代码如下所示:
%开始动画
for j = 1:29
Play_Sound(3);
for i = 1:19
pause(0.002);
set(Block(i,j),'backgroundcolor',Type_color(5,:));
end
end
pause(1);
Play_Sound(2);
Xiao = [Block(2,27);Block(3,26);Block(4,25);Block(5,28);Block(5,27);Block(5,26);Block(5,25);Block(6,25);Block(7,26);Block(8,27);...
Block(1,24);Block(2,24);Block(3,24);Block(4,24);Block(5,24);Block(6,24);Block(7,24);Block(8,24);Block(9,24);...
Block(1,23);Block(1,22);Block(1,21);Block(1,20);Block(1,19);Block(1,18);Block(1,17);Block(1,16);Block(1,15);...
Block(9,23);Block(9,22);Block(9,21);Block(9,20);Block(9,19);Block(9,18);Block(9,17);Block(9,16);Block(9,15);...
Block(2,21);Block(3,21);Block(4,21);Block(5,21);Block(6,21);Block(7,21);Block(8,21);...
Block(2,18);Block(3,18);Block(4,18);Block(5,18);Block(6,18);Block(7,18);Block(8,18)];
set(Xiao,'backgroundcolor',Type_color(6,:));
pause(1);
Play_Sound(2);
tian = [Block(10,12);Block(11,12);Block(12,12);Block(13,12);Block(14,12);Block(15,12);Block(16,12);Block(17,12);Block(18,12);...
Block(10,11);Block(10,10);Block(10,9);Block(10,8);Block(10,7);Block(10,6);Block(10,5);Block(10,4);Block(10,3);Block(10,2);...
Block(18,11);Block(18,10);Block(18,9);Block(18,8);Block(18,7);Block(18,6);Block(18,5);Block(18,4);Block(18,3);Block(18,2);...
Block(10,3);Block(11,3);Block(12,3);Block(13,3);Block(14,3);Block(15,3);Block(16,3);Block(17,3);Block(18,3);...
Block(11,8);Block(11,8);Block(12,8);Block(13,8);Block(14,8);Block(15,8);Block(16,8);Block(17,8);Block(18,8);...
Block(14,4);Block(14,5);Block(14,6);Block(14,7);Block(14,8);Block(14,9);Block(14,10);Block(14,11)];
set(tian,'backgroundcolor',Type_color(6,:));
Play_Sound(2);
pause(1);
for j = 1:29
Play_Sound(3);
for i = 1:19
pause(0.002);
set(Block(i,j),'backgroundcolor',Grey_color);
end
end
pause(1);
5.4、游戏背景音乐
添加游戏背景音乐,方块的下降与消除均存在音乐。代码如下:
function Play_Sound(sound_type)
switch sound_type
%方块下落声音
case 1
[x, Fs] = audioread('Sound_down.wav');
sound(x, Fs);
%成功消除声音
case 2
[x, Fs] = audioread('Sound_success.wav');
sound(x, Fs);
%方块触底声音
case 3
[x, Fs] = audioread('Sound_botton.wav');
sound(x, Fs);
%游戏结束声音
case 4
[x, Fs] = audioread('Sound_finish.wav');
sound(x, Fs);
%变形声音
case 5
[x, Fs] = audioread('Sound_shift.wav');
sound(x, Fs);
end
end