Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
柿饼_PersimmonUI
【PersimmonUI柿饼学习营】+ A Byte of China + 2048游戏
发布于 2018-09-02 17:38:35 浏览:3174
订阅该版
* 本帖最后由 ianhom 于 2018-9-2 17:47 编辑 * 第二周作业:制作2048游戏 **_开发环境_** RTT + PerimmonUI + 野火RT1052Mini + 5寸800*480触屏 ![wx_camera_1535343243074.jpg](/uploads/201809/02/174044nkprp41k2povrvp4.jpg) **_开发过程_** 关于环境的搭建可以参考上[一篇帖子](https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=7889&page=1#pid37561),这次2048的作业分成两部分,游戏本身的**逻辑**及**UI实现**。 2048的游戏逻辑 网上有很多[源码例程](https://www.cnblogs.com/pipu-qiao/p/6012697.html),其核心算法如下: 遍历数组从数组的当前位置的**下一个**开始遍历,找不是0的位置 如果没找到什么也不做 如果找到 如果当前位置是0,那么像当前位置与下一个进行互换,将下标减一 如果当前位置和下一个位置相等,将当前位置数据*2,下个位置数据置0 有了这个算法,做上下左右操作的时候,只需要把4*4的二维数组进行转换,然后使用这个算法计算,最后再转换回原来的方向即可。 除了核心算法,还有一些其他功能需要注意:1、在空白的随机位置生成2或4的数据;2、输赢的判断;3、撤销操作;4、得分计算;5、不同数据的方块颜色计算。这些就不详细介绍了,看源码可能更清晰一些。 ```var arrOri = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]; var arrTempI = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]; var arrTempS = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]; var arrRedo = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]; var arrRTT = [[0,2,4,8],[16,32,64,128],[256,512,1024,1024],[1024,1024,1024,1024]]; var Score = 0; var ScoreRedo = 0; var Res = 0; //1=win,2=lose; var BASECLR = 0xFFFFF48F; var OFFSET = 100; function printArr(arr) { for(var i=0;i<4;i++){ console.log(arr*[0],arr*[1],arr*[2],arr*[3]); } } function arrCp(arrSrc,arrDes) { for(var i=0;i<4;i++){ for(var j=0;j<4;j++){ arrDes*[j] = arrSrc*[j]; } } } function arrCmp(arrSrc,arrDes) { for(var i=0;i<4;i++){ for(var j=0;j<4;j++){ if(arrDes*[j] != arrSrc*[j]){ return 0; } } } return 1; } function arrSpan(arrSrc,arrDes) { for(var i=0;i<4;i++){ for(var j=0;j<4;j++){ arrDes[j]* = arrSrc*[j]; } } } function arrInvt(arrSrc,arrDes) { for(var i=0;i<4;i++){ for(var j=0;j<4;j++){ arrDes*[j] = arrSrc*[3-j]; } } } function addNum() { var blankCnt = 0; for(var i=0;i<4;i++){ for(var j=0;j<4;j++){ if(0 == arrOri*[j]){ blankCnt += 1; } } } var luckyNum = Math.floor(Math.random()*2+1)*2; var luckyBox = Math.floor(Math.random()*blankCnt+1); blankCnt = 0; for(var i=0;i<4;i++){ for(var j=0;j<4;j++){ if(0 == arrOri*[j]){ blankCnt += 1; if(blankCnt == luckyBox) { arrOri*[j] = luckyNum; } } } } } function getColor(val) { var temp = (BASECLR + (OFFSET *( Math.log(val)/Math.log(2)))); return temp; } function gameCheck() { for(var i=0;i<4;i++){ for(var j=0;j<3;j++){ if(arrOri*[j] == arrOri*[j+1]){ return; } } } for(var j=0;j<4;j++){ for(var i=0;i<3;i++){ if(arrOri*[j] == arrOri[i+1][j]){ return; } } } for(var j=0;j<4;j++){ for(var i=0;i<4;i++){ if(0 == arrOri*[j]){ return; } } } Res = 2; } function getData(arr) { //遍历数组从数组的的当前位置的下一个开始遍历,找不是0的位置() // 如果没找到什么也不做 // 如果找到 //如果当前位置是0,那么像当前位置与下一个进行互换(当前位置获得下一个位置的数据,并且将下一个位置数据置为0,将下标减一) //如果当前位置和下一个位置相等,将当前位置数据*2,下个位置数据置0 var i,nextI,len,m; len = arr.length; for (i = 0; i < len; i += 1) { //先找nextI nextI = -1; for (m = i+1; m < len; m++){ if(arr[m] !== 0) { nextI = m; break; } } if (nextI !== -1) { //存在下个不为0的位置 if (arr* === 0) { arr* = arr[nextI]; arr[nextI] = 0; i -= 1; } else if (arr* === arr[nextI]) { arr* = arr**2; Score += arr*; arr[nextI] = 0; if(2048 == arr*){ Res = 1; } } } } } var page = { onButton: function(e) { if((e.target.id != "buttonRedo")&&(2 != Res)){ arrCp(arrOri,arrRedo); ScoreRedo = Score; } switch (e.target.id) { case "buttonStart": arrOri = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]; Score = 0; Res = 0; this.setData({buttonStart : {value :'Restart!!', refresh : true}}) this.setData({label19: {value : "", refresh : true}}); this.setData({imagebox2 : {value :'', refresh : true}}) addNum(); break; case "buttonLeft": for(var i = 0; i < 4; i++){ getData(arrOri*); } break; case "buttonRight": arrInvt(arrOri,arrTempI); for(var i = 0; i < 4; i++){ getData(arrTempI*); } arrInvt(arrTempI,arrOri); break; case "buttonUp": arrSpan(arrOri,arrTempS); for(var i = 0; i < 4; i++){ getData(arrTempS*); } arrSpan(arrTempS,arrOri); break; case "buttonDown": arrSpan(arrOri,arrTempS); arrInvt(arrTempS,arrTempI); for(var i = 0; i < 4; i++){ getData(arrTempI*); } arrInvt(arrTempI,arrTempS); arrSpan(arrTempS,arrOri); break; case "buttonRedo": arrCp(arrRedo,arrOri); Score = ScoreRedo; Res = 0; break; case "buttonRTT": arrCp(arrRTT,arrOri); Score = 999999999; Res = 0; break; } if((e.target.id != "buttonRedo")&&(0 == arrCmp(arrOri,arrRedo))){ addNum() } if(arrOri[0][0] == 0){ this.setData({label1 : {value : ""}}); }else{ this.setData({label1 : {value : arrOri[0][0]}}); } this.setData({label1 : {background: getColor(arrOri[0][0]), refresh : true}}); if(arrOri[0][1] == 0){ this.setData({label2 : {value : ""}}); }else{ this.setData({label2 : {value : arrOri[0][1]}}); } this.setData({label2 : {background: getColor(arrOri[0][1]), refresh : true}}); if(arrOri[0][2] == 0){ this.setData({label3 : {value : ""}}); }else{ this.setData({label3 : {value : arrOri[0][2]}}); } this.setData({label3 : {background: getColor(arrOri[0][2]), refresh : true}}); if(arrOri[0][3] == 0){ this.setData({label4 : {value : ""}}); }else{ this.setData({label4 : {value : arrOri[0][3]}}); } this.setData({label4 : {background: getColor(arrOri[0][3]), refresh : true}}); if(arrOri[1][0] == 0){ this.setData({label5 : {value : ""}}); }else{ this.setData({label5 : {value : arrOri[1][0]}}); } this.setData({label5 : {background: getColor(arrOri[1][0]), refresh : true}}); if(arrOri[1][1] == 0){ this.setData({label6 : {value : ""}}); }else{ this.setData({label6 : {value : arrOri[1][1]}}); } this.setData({label6 : {background: getColor(arrOri[1][1]), refresh : true}}); if(arrOri[1][2] == 0){ this.setData({label7 : {value : ""}}); }else{ this.setData({label7 : {value : arrOri[1][2]}}); } this.setData({label7 : {background: getColor(arrOri[1][2]), refresh : true}}); if(arrOri[1][3] == 0){ this.setData({label8 : {value : ""}}); }else{ this.setData({label8 : {value : arrOri[1][3]}}); } this.setData({label8 : {background: getColor(arrOri[1][3]), refresh : true}}); if(arrOri[2][0] == 0){ this.setData({label9 : {value : ""}}); }else{ this.setData({label9 : {value : arrOri[2][0]}}); } this.setData({label9 : {background: getColor(arrOri[2][0]), refresh : true}}); if(arrOri[2][1] == 0){ this.setData({label10: {value : ""}}); }else{ this.setData({label10 : {value : arrOri[2][1]}}); } this.setData({label10: {background: getColor(arrOri[2][1]), refresh : true}}); if(arrOri[2][2] == 0){ this.setData({label11: {value : ""}}); }else{ this.setData({label11 : {value : arrOri[2][2]}}); } this.setData({label11: {background: getColor(arrOri[2][2]), refresh : true}}); if(arrOri[2][3] == 0){ this.setData({label12: {value : ""}}); }else{ this.setData({label12 : {value : arrOri[2][3]}}); } this.setData({label12: {background: getColor(arrOri[2][3]), refresh : true}}); if(arrOri[3][0] == 0){ this.setData({label13: {value : ""}}); }else{ this.setData({label13 : {value : arrOri[3][0]}}); } this.setData({label13: {background: getColor(arrOri[3][0]), refresh : true}}); if(arrOri[3][1] == 0){ this.setData({label14: {value : ""}}); }else{ this.setData({label14 : {value : arrOri[3][1]}}); } this.setData({label14: {background: getColor(arrOri[3][1]), refresh : true}}); if(arrOri[3][2] == 0){ this.setData({label15: {value : ""}}); }else{ this.setData({label15 : {value : arrOri[3][2]}}); } this.setData({label15: {background: getColor(arrOri[3][2]), refresh : true}}); if(arrOri[3][3] == 0){ this.setData({label16: {value : ""}}); }else{ this.setData({label16 : {value : arrOri[3][3]}}); } this.setData({label16: {background: getColor(arrOri[3][3]), refresh : true}}); gameCheck(); if(1 == Res){ this.setData({label19: {value : "Win!!", refresh : true}}); }else if(2 == Res){ this.setData({label19: {value : "lose!!", refresh : true}}); } else{ this.setData({label19: {value : "", refresh : true}}); } this.setData({label17: {value : Score, refresh : true}}); } }; Page(page);``` -----------------------------------------------分界线----------------------------------------------------------- 有了游戏的逻辑,使用柿饼GUI做界面就很轻松了。 我们需要做17个label(16个用于显示4*4的数组,1个显示得分),和6个按键(上下左右键,开始键,撤销键。。。。其实还有一个隐藏神奇按钮),分布如图所示。 ![TIM截图20180902165439.png](/uploads/201809/02/170259ogxjjgi8jp8pssm3.png) 对label的处理,首先空间名称要尽可能按序来设置,例如label1,label2.....,这样便于后续历遍,空间文本可以不写,游戏中计算的结果会刷新到这里。通过setData功能,后面介绍,这里建议配置好一个label之后,复制粘贴,这样比较有效率,然后利用界面工具来对齐,很方便。 ![TIM截图20180902165618.png](/uploads/201809/02/170300gn99ys2qny8k7bb9.png) 然后对按键空间进行配置,首先在bindtap中写入onButton,即在该按键按下时,会触发onButton这个函数(按下事件的回调函数)。然后为每个按键填入易读且不同的空间名称,该名称用于按键事件中区别是哪一个按键被按下(回调函数的参数)。这里可以对按键替换下图片,按下和常态的图片不同,有按下的效果。别忘了清除控件文本。 ![TIM截图20180902165705.png](/uploads/201809/02/170300g5hl59ydi2bbb11a.png) 完成界面配置后,我们可以编写js的部分。如上述步骤,onButton作为page的方法,在按键被按下后将会被调用,然后根据控件名称找到对应的分支,比如buttonLeft,我们就要刷新数组的数据getData()。 ![TIM截图20180902165836.png](/uploads/201809/02/170300uuppprknzzcpou8v.png) 完成数据刷新后,就要刷到显示上,这里使用setData功能,可以设置控件的本文(修改方块值)、修改控件背景颜色(修改方块颜色)及其他属性(位置,大小,是否显示等) ![TIM截图20180902170045.png](/uploads/201809/02/170300qpaqrv0rrqahjhbi.png) 有了上述操作,我们就完成了一个基本的2048游戏了,附件是柿饼工程,这里抛砖引玉,期待大家更完善、更有趣的版本。 **_效果展示_** 先在模拟器上试验效果 ![2048_sim.gif](/uploads/201809/02/172009jfs06zcjsfi0vts6.gif) 开发板上的效果 ![2048_board.gif](/uploads/201809/02/173528tdja0sdcph0yf80f.gif) **_总结_** 控件丰富,玩法也比较灵活,期待更多空间。 2048逻辑蛮有意思的,JavaScript也很容易入门,JS+GUI设计器确实很方便开发复杂的图形功能。 我实现的界面刷新效率不高,期待大佬的优化版本。 柿饼工程 ![hw2-4.rar](/uploads/201809/02/173747rf0p788szy8g698y.rar)
查看更多
4
个回答
默认排序
按发布时间排序
DaZhou
2018-09-02
这家伙很懒,什么也没写!
大佬就是大佬,营中学习的榜样,费尽全力,亦不能望其项背:lol
ianhom
2018-09-02
这家伙很懒,什么也没写!
>大佬就是大佬,营中学习的榜样,费尽全力,亦不能望其项背 --- 大佬谬赞,大佬带带我,我会喊666的:$
haveDream
2018-09-03
这家伙很懒,什么也没写!
大佬也玩柿饼 加油
ianhom
2018-09-05
这家伙很懒,什么也没写!
>大佬也玩柿饼 加油 --- 坚持学习:P
撰写答案
登录
注册新账号
关注者
0
被浏览
3.2k
关于作者
ianhom
这家伙很懒,什么也没写!
提问
17
回答
16
被采纳
0
关注TA
发私信
相关问题
1
【PersimmonUI柿饼学习营】+ A Byte of China + 环境搭建&20W年薪广告
2
【柿饼学习营】+werrysuzhen+20W年薪作业
3
【PersimmonUI柿饼学习营】+ meetwit + 20W年薪广告&lesson01
4
【PersimmonUI柿饼学习营】+ DaZhou + 20W年薪作业+视频有彩蛋
5
【PersimmonUI柿饼学习营】+ DMY+ lesson01 20W年薪广告
6
【PersimmonUI柿饼学习营】+ Bigmagic+20W年薪广告&day01
7
【PersimmonUI柿饼学习营】+ chowguohua+年薪广告
8
【柿饼学习营】+werrysuzhen+脚本及事件学习
9
【PersimmonUI柿饼学习营】+ DaZhou+ 手把手教你做计算器
10
【PersimmonUI柿饼学习营】+ DaZhou + 2048游戏 + 一周感悟
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
ulog
C++_cpp
at_device
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
8
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部