【连载爽文 Part.2】4*4Puzzle ——基于MATLAB App Designer 的一例游戏。

6.写在前面

我要特别感谢一下CSDN这个技术平台,在昨天我发布了我的第一篇blog ,就被平台推流,而且今天早晨收到此篇blog 进入【CSDN每天最佳新人】榜单的消息,欣喜若狂,受宠若惊。感到平台对新人作者和原创文章的无限尊重与无穷善意,我想这也是各领域的能人异士,乐于在本平台分享知识、交流心得的原因吧!也衷心祝愿本平台越来越好(词穷但认真)!

本篇blog 直接从chap 6 开始写了,此次【连载爽文 Part.2】书接上回,因为本人语言能力有限,代码也不尽如人意,所以昨日拖拖拉拉只完成了App Designer 准备工作的一部分,但已经4000+ characters 。担心文字冗长乏味,使各位看官老爷觉得枯燥无趣,只略施小计,讪讪在文章标题前加了这么个噱头。再行连载本篇是为了与诸位共同探讨学习app designer 的基本使用技法和思路,也是一例简单的Matlab 应用程序的实践。(下图取自我发表的第一篇blog )

7. App Designer 的样板设计 

样板设计就是应用程序的交互排布了,我将app分为了显示区、交互按钮区和puzzle 解谜区3个区域,基本样板如图(显示区为左上、交互按钮区为左下、puzzle 解谜区在右侧):(该图是puzzle 完全开发后初次启动运行的样子(只交互了该puzzle 的startupFcn ))

上图可知。我们制作了四个功能按钮,分别为START ,CHECK ,SHOW ,&RESET 。

START:通过对函数F(在上篇有介绍),随机出一个新的puzzle至右侧解谜区。

CHECK:检测解谜区的puzzle 完成情况,并且输出您完成该puzzle 的步数(此值在闭区间[4,16]之内)这两段输出文档将生成在左上方的显示区中。

SHOW:将START 键产生的puzzle a 完全展示在解谜区,并以二进制4*4 矩阵的形式将答案输出于显示区。

RESET:完成一次puzzle 后按下,会将右侧解谜区完全清除(呈上图的样子)。说直白点呢,就是相当于关闭游戏,又重新打开了一下。

解谜区如何交互呢?因为信号灯Lamp(上图16圆)没有交互属性(中国话就是说,这个灯灯它点不了)所以在16 个信号灯Lamps 下面(注意设置图层关系)又藏了16个按钮Buttons以控制信号灯的颜色,交互之后可以改变Lamp 的颜色(答案正确变绿,答案错误变红)。

反思:其实这里可以用组件库的【图像】组件,可以更完美且更便捷地模拟本篇开始的图片那样——点击图案→正确则显示彩色图像块,错误则显示黑白色的图像块。这种方法且不说虽需要制作2*4*4,两套图像(一套正确彩色,一套错误黑白)和初始图像1*4*4个问号吧(假设)。共制作33张大小统一的图片。但是它快啊(因为它善),交互起来很舒服。

不说这么多,意思就是:我太懒了我不想干你们来吧。

8.显示区

我很笨很懒,图示的标签显示因为要多次换行,所以我拖入了3个固定标签,以及3个变量标签。稍加排版(这里有【*山代码】之嫌,且虚心求教!不在话下。)

*3个固定标签即是这三张

从左至右依次服务于 START&RESET(共用图例1)、SHOW、CHECK。

这三个标签的内容是固定的(即【.Text 】的解析不随交互而变化)只需要改变这三个组件的【.Visible 】解析属性,即可完成按钮和显示区内容的切换。

——这操作简直是拯救人(猪)脑的不二法门。

*3个变量标签即是这三张

初值为YroN 的标签用以表示判定puzzle 完成情况;

初值为Times 的标签以表示步数;

初始DO NOT EXIST 标签以展示puzzle 的整体分布。

在chap7有提到过这些标签与按钮区的交互方式!不再赘述咯。

9.解谜区的交互方式 以及 前置脚本!

我制作了交互解谜区16按钮的方式

以及五个.mlx 脚本,脚本分别命名为Wre、Sow、Cln、Able、dAble。

名称呢,分别取自英文Where、Show、Clean、Able、disAble。接下来为大家介绍用途:

9.1 解谜区的交互

此脚本用以查找每次按键之后,我们到底按在哪里了?按下的答案对不对。

解谜区的交互我直接写到app designer 里面区了,因为很简短,但是调用的组件名称又不能标准化。所以也是开开心心写了16份相似的代码(只有调用名称有所差异)。蛮整齐的嘞~

            a=evalin('base','a');
            if a(1)==1
                app.a_1.Color='g';
            else
                app.a_1.Color='r';
            end

            t=evalin('base','t');
            t(1)=1;
            assignin('base','t',t)
            
            app.Button_1.Enable=0;

注意看,这个app.a_1 是第一个灯泡(此后的灯泡按4*4方阵的元素位置排列,分别是a_1、a_2...a_16)当你按下解谜区第一行第一列的button,就会开始判断我们生成的puzzle棋盘的第一个元素a(1)是否为1,1返还Color='g',0返还Color='r'。我们有必要解释一下这个t,因为这个t是在交互START按钮后生成的,用以记录我们按下按钮的位置。

app.Button_1.Enable=0;        库库破釜沉舟,按完这个按钮就不让你再按了。

9.2 Wre.mlx

此脚本以define puzzle 是否完成;
并且定位完成的通路位置;

e=zeros(4);
for n=1:16
    if t(n)==1
        e(n)=a(n);
    end
end
cross=[sum(diag(e)),sum(diag(flipud(e)))];
col=sum(e);                                 % only col(1)==4
row=sum(e,2)';
mix=[cross,col,row];                        % mix 是一个1*10的列表

得到s;
当没有通路时,s=0;
当有通路时,s的值是通路的位置;

s=find(mix==4);
def=size(s);def=def(2);
if def==0
    s=0;
end

将位置参数转化为字符串str;

if s==0
    str='The puzzle is not finished';
elseif s==1
    str='main diagonal';
elseif s==2
    str='sub diagonal';
end
if s>2 && s<=6
    str=['Puzzle done with column ',num2str(s-2)];
end
if s>6 && s<=10
    str=['Puzzle done with row ',num2str(s-6)];
end

9.3 Sow.mlx

此脚本以展示底层puzzle ;

傻瓜代码,只展示一部分,第1列 lamp 展示;

if a(1)==1
    app.a_1.Color='g';
else
    app.a_1.Color='r';
end

if a(2)==1
    app.a_2.Color='g';
else
    app.a_2.Color='r';
end

if a(3)==1
    app.a_3.Color='g';
else
    app.a_3.Color='r';
end

if a(4)==1
    app.a_4.Color='g';
else
    app.a_4.Color='r';
end

毫无技巧可言。可以讨论 

9.4 Cln.mlx

此脚本以将所有的Lamp复原至灰色;

下为部分代码:(同样为第一列)

app.a_1.Color=[0.80,0.80,0.80];
app.a_2.Color=[0.80,0.80,0.80];
app.a_3.Color=[0.80,0.80,0.80];
app.a_4.Color=[0.80,0.80,0.80];

9.5 Able.mlx & dAble.mlx

此脚本以改变按钮button的交互性质。

顾名思义,前者使button 可交互,后者将button 变不可交互(分别为下方上、下两条代码)。

app.Button_1.Enable=0;

app.Button_1.Enable=1;

10.startupFcn 以及 按钮交互区的回调!

终于来到了自认为很关键的部分,至此上文已经达到1500+字数了~本章会为大家介绍四个按钮的功能以及源代码!

10.1 startupFcn回调

直接展示可编辑段:

            evalin('base','clear variables')
            dAble
            
            app.START.Enable=1;
            app.RESETButton.Enable=0;
            app.SHOWButton.Enable=0;
            app.CHECKButton.Enable=0;

此时为应用刚打开的情形(参考样板设计图例),

所有的解谜区按钮不可交互,

START按钮可以交互,RESET、SHOW、CHECK按钮则无法选中(可以躲元气弹了)。

10.2 START 按钮回调

            app.start.Visible=1;
            app.check.Visible=0;
            app.YorN.Visible=0;
            app.Times.Visible=0;
            app.show.Visible=0;
            app.atext.Visible=0;
            
            app.START.Enable=1;
            app.RESETButton.Enable=1;
            app.SHOWButton.Enable=1;
            app.CHECKButton.Enable=1;
            
            Cln
            Able
            F
            assignin('base','a',a)
            t=zeros(4);
            assignin('base','t',t)

第一部分为标签的可视化,交互之后只能看到第一段文字(显示区的第一固定标签)

第二部分为按钮去的可交互调用,此时什么都可以按了。

第三部分先是Cln 将所有的Lamp复原至灰色,然后使Lamp 下的Button 可交互了。

再运行函数F(上篇内容),将a写入工作区,建立全0矩阵t,写入工作区。

assignin 函数和evalin 函数是非常重要的,否则会出现没有写入的情况,

(一般写入和调用同时存在,逻辑为:写入——调用——工作区的数据处理——再写入)。

10.3 CHECK 按钮回调

            app.start.Visible=0;
            app.check.Visible=1;
            app.YorN.Visible=1;
            app.Times.Visible=1;
            app.show.Visible=0;
            app.atext.Visible=0;
            
            app.START.Enable=1;
            app.RESETButton.Enable=1;
            app.SHOWButton.Enable=1;
            app.CHECKButton.Enable=1;
            
            a=evalin('base','a');
            t=evalin('base','t');
            Wre
            assignin('base','a',a)
            %assignin('base','str',str)
            app.YorN.Text=str;
            
            
            t=sum(sum(t));

            app.Times.Text=num2str(t);

第一二部分同样是对【标签可视化】和【按钮交互性】的定义,乖的宝宝已经可以自行理解了。

第三部分即是 assignin 函数和evalin 函数的一个英语,因为Wre 脚本会用到a,我们需要先行调用(此部分虽然没有对a进行任何处理改动,但为了美观和杜绝软错误,我们还是再写入了)

注意app.YorN.Text=str;其代码意义就是将YorN 这段标签的Text 内容改为str ,str 的定义在Wre.mlx 中有提到,动动小手指向上翻翻看吧~

这个t则是我们和解谜区按钮交互的位置,通过sum(sum()) 两次求和,生成t(times) 用于度量次数,值得注意的是.Text的解析只能被【字符串类型】赋值,甚至字符串构成的向量或矩阵,都无法用于改变标签的内容。

10.4 SHOW 按钮回调

            app.start.Visible=0;
            app.check.Visible=0;
            app.YorN.Visible=0;
            app.Times.Visible=0;
            app.show.Visible=1;
            app.atext.Visible=1;
            
            app.START.Enable=1;
            app.RESETButton.Enable=1;
            app.SHOWButton.Enable=1;
            app.CHECKButton.Enable=0;
            
            dAble
            
            a=evalin('base','a');
            Sow
            assignin('base','a',a)
            
            app.atext.Text=strcat(num2str(a(1,:)),10,num2str(a(2,:)),10,num2str(a(3,:)),10,num2str(a(4,:)));
            
            t=zeros(4);
            assignin('base','t',t)

 一二部分跳过

SHOW按钮按了之后,解谜区就不可用了。这里又有一个小技巧,就是如何让app 的标签组件进行分行输出(对,没错,就是那条最长的):

app.atext.Text=strcat(num2str(a(1,:)),10,num2str(a(2,:)),10,num2str(a(3,:)),10,num2str(a(4,:)));

就是按照a的四行,每行转为字符串,然后分段输出。

哇,真的是太神奇辣~(章鱼哥音)

——虽然试了很久如何分段输出:所以不是我笨,我真的只是懒。

10.5 RESET 按钮回调

            app.start.Visible=1;
            app.check.Visible=0;
            app.YorN.Visible=0;
            app.Times.Visible=0;
            app.show.Visible=0;
            app.atext.Visible=0;
                        
            evalin('base','clear variables')
            dAble
            Cln
            
            app.START.Enable=1;
            app.RESETButton.Enable=0;
            app.SHOWButton.Enable=0;
            app.CHECKButton.Enable=0;

样板设计的时候已经介绍过RESET 按钮了,就是将应用程序初始化一下。

(结束了罪恶的一生,然后开始了罪恶的下一生。)

11. Last 写到最后

本篇插入的Matlab 代码段,除了chap 9 的五个脚本都是App Designer 的可编辑部分!

果然不出所料,写这篇blog的时候出现了闭环。因为当我想要介绍前置脚本Wre.mlx 的时候,就一定会提到如何交互解谜区的16按钮,要介绍如何通过按按钮来进行答案监测,又需要写出START 按钮的初始赋值情况,当我决定先写START按钮的回调时,又发现按钮里包含了前置脚本。嚯嚯嚯,所以就按我们(我自己)最能理解的地方开始解释咯~

本次的蓝色部分仍然为讨论部分,手机版可能看不到,认准【可以讨论】字样。

此次连载新增了红色部分,是我觉得写App Designer 时很重要的技巧,也供讨论,畅所欲言。

各功能按钮会导致有一些按钮不能用,这里只tip 上了源代码而不能尽其言。是我的失职,如果想玩一下的话,我可以打包发给你们u~

作者本科在读,但非计算机及相关专业的学生。所以觉得对互联网时代的普遍认知以及观念还不能尽然,代码风格可能遭人唾弃(虚心接受)。但我相信检验出真理这句话。唯有实践才能回溯性的构建思想,解放思想,推陈出新。

本篇也是作者第一次编写APP designer 并且第一次在CSDN发布blog,一路写来,还是有很多大家可以用的上的思路和技巧(是我自己这么想)总之谢谢大家的喜欢!

💐完结撒花

 这个puzzle 的爽文至此结束了!再次感谢一下CSDN和CSDN平台上勤奋的IT小猴子们~

希望和大家一起思考,多多讨论。

  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值