用App designer制作数字华容道
做完2048后突然想到华容道,但是华容道比较难做,就先做个数字华容道试试。
UI设计
主要控件就是16个展示数字的方块、1个计时用的面板、1个游戏胜利的界面以及1个新游戏按钮。如下图所示。
与2048不同的是,这次的数字方块用的是Button控件,创建该控件代码如下(注意在properties中声明Num类型为matlab.ui.control.Button):
function createNum(app)
for i=1:4
for j=1:4
app.Num(i,j) = uibutton(app.NumHuaRongUIFigure,'push');
app.Num(i,j).ButtonPushedFcn = createCallbackFcn(app, @NumButtonPushed,true);
app.Num(i,j).BackgroundColor = [0.91 0.77 0.66];
app.Num(i,j).Position = [-47.5+j*100 442.5-i*100 95 95];
app.Num(i,j).Text = '';
app.Num(i,j).FontName = 'Segoe UI Historic';
app.Num(i,j).FontSize = 40;
app.Num(i,j).FontColor = [1,1,1];
app.Num(i,j).Tag = num2str(sub2ind([4 4],i,j));
end
end
end
创建对应的回调函数:
function NumButtonPushed(app,event)
end
创建胜利面板函数:
function createGameOverLabel(app)
app.gameOverLabel = uilabel(app.NumHuaRongUIFigure);
app.gameOverLabel.BackgroundColor = [0.59,0.66,0.64];
app.gameOverLabel.Position = [50,140,400,200];
app.gameOverLabel.FontName = 'Ink Free';
app.gameOverLabel.FontSize = 70;
app.gameOverLabel.FontColor = [1,1,1];
app.gameOverLabel.HorizontalAlignment = 'center';
app.gameOverLabel.Text = "YOU WIN";
app.gameOverLabel.Visible = 'off';
end
其余控件建议直接使用用户界面创建。
规则设计
- 游戏初始矩阵
我们需要一个打乱的矩阵才能开始游戏。要实现这个功能可以使用randperm()函数,其可以生成一组各不相同的整数。
m = randperm(16,16)-1;
m = reshape(m,4,4);
app.theMatrix = m;
- 点击空格旁边的方块可以使方块移动到空格
实现这个规则主要有两点:一是判断点击的方块在不在空格周围,二是交换位置。首先,空白格对应矩阵元素为0,利用find()函数可以快速确定其位置,而在空格周围可移动的最多有4个位置。我们可以将点击的方块位置索引传入,并与空白格索引比较。如果两个位置的行索引相等且列索引相差1,或者列索引相等而行索引相差1,则该方块可以与空白格交换。
function f = isMovable(app,i,j)
[x,y] = find(app.theMatrix == 0);
if (i==x)&&(abs(j-y)==1)
f = true;
elseif (j==y)&&(abs(i-x)==1)
f = true;
else
f = false;
end
end
其次,交换位置就是把矩阵两个位置的值修改一下。
function moveNum(app,i,j)
if app.isMovable(i,j)
[x,y] = find(app.theMatrix == 0);
app.theMatrix(x,y) = app.theMatrix(i,j);
app.theMatrix(i,j) = 0;
end
end
- 使方块按顺序排列,并且最后一格是空格即宣布游戏胜利
这个规则的实现只需用isequal()函数判断两个矩阵是否相等。
function y = isGameWin(app)
if isequal(app.theMatrix,app.desMatrix)
y = true;
else
y = false;
end
end
计时器
为了评估游戏成绩,我们可以加入一个计时器。
- 在properties中创建一个timer
theTimer = timer
- 创建一个timer的初始化函数
function timerInit(app)
app.theTimer.StartDelay = 1;
app.theTimer.Period = 1;
app.theTimer.ExecutionMode = 'fixedSpacing';
app.theTimer.TimerFcn = @(~,~)timerCallback(app);
end
上述代码表明timer会有1s的开始延迟,且其每隔1s会执行回调
- 别忘了创建timer的回调函数
function timerCallback(app)
end
- 在回调中修改计时器面板的值实现计时功能
t = str2double(app.TimerPanel.Value);
t = t+1;
app.TimerPanel.Value = string(t);
- 使用start()和stop()分别开始和停止计时器,别忘了在关闭APP前先删除计时器(在UIFigure的回调函数中)
function NumHuaRongUIFigureCloseRequest(app, event)
stop(app.theTimer)
delete(app.theTimer)
delete(app)
end
完善各回调,一个简单的数字华容道就完成了。