Duilib之挑战2048

网上很流行的一款很火爆的手机游戏,并由此衍生出好多2048版的游戏,具体可以百度就知晓了,自己学习duilib后觉得可以实现,就动手写了一个,算法估计很挫,不过界面是百分百像哦,一天就搞定了。

界面展示:

XML界面布局:

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<Window size="359,580"><Font name="微软雅黑" size="20" bold="true" italic="false" /><Font name="微软雅黑" size="53" bold="true" italic="false" /><Font name="新宋体" size="20" bold="false" italic="false" /><Font name="微软雅黑" size="25" bold="true" italic="false" /><VerticalLayout width="359" height="580" bkcolor="#FFFAF8EF"><HorizontalLayout width="363" height="23" /><HorizontalLayout width="359" height="177"><VerticalLayout width="247" height="71"><Label text="2048" float="true" pos="19,0,0,0" width="143" height="70" textcolor="#00776E65" disabledtextcolor="#FFA7A6AA" font="1" /></VerticalLayout><VerticalLayout name="vertical" width="67" height="67" bkcolor="#FFBBADA0"><Label text="得分" float="true" pos="13,4,0,0" width="53" height="25" textcolor="#00FFFBF0" disabledtextcolor="#FFA7A6AA" font="2" /><Text name="scores" text="0" float="true" pos="2,29,0,0" width="63" height="33" textpadding="2,0,2,0" textcolor="#00FFFBF0" disabledtextcolor="#FFA7A6AA" font="3" align="centerwrap" /></VerticalLayout><Label text="玩法:" float="true" pos="14,74,0,0" width="57" height="27" textcolor="#00776E65" disabledtextcolor="#FFA7A6AA" font="0" /><Label text="1.使用方向键移动数字" float="true" pos="14,106,0,0" width="215" height="22" textcolor="#00656E77" disabledtextcolor="#FFA7A6AA" font="2" /><Label text="2.相邻数字相同则并成1个数字" float="true" pos="13,136,0,0" width="346" height="24" textcolor="#00656E77" disabledtextcolor="#FFA7A6AA" font="2" /></HorizontalLayout><HorizontalLayout width="372" height="385"><VerticalLayout width="9" height="26" /><VerticalLayout width="340" height="340" bkcolor="#FFBBADA0"><Button name="bt1" float="true" pos="12,12,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt4" float="true" pos="258,12,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt3" float="true" pos="176,12,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt2" float="true" pos="94,12,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt5" float="true" pos="12,94,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt6" float="true" pos="94,94,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt7" float="true" pos="176,94,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt8" float="true" pos="258,94,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt9" float="true" pos="12,176,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt10" float="true" pos="94,176,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt11" float="true" pos="176,176,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt12" float="true" pos="258,176,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt13" float="true" pos="12,258,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt14" float="true" pos="94,258,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt15" float="true" pos="176,258,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /><Button name="bt16" float="true" pos="258,258,0,0" width="70" height="70" bkcolor="#FFCCC0B3" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" font="3" align="center" /></VerticalLayout></HorizontalLayout></VerticalLayout>
</Window></span><span style="font-size:24px;">
</span>

此时的界面全是平面的,还没有圆角,要实现圆角设计,需要在加载的程序里加入

        SIZE si;si.cx = si.cy = 4;bt->SetBorderRound(si);//bt为一个空间的指针

对于Duilib控件的获取可以用

CTextUI* scores = static_cast<CTextUI*>(m_PaintManager.FindControl(_T("scores")));

如上即是获取显示分数的TEXT控件的方式。

此次XML没有使用任何图片,完全是原始控件绘制,比较简单,所以如果没有代码里的圆角去美化的话,界面就显得很抽象了。

键盘响应:

LRESULT CGameWnd::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{if(wParam == VK_UP){pMove->_up();pMove->Print();}else if(wParam == VK_RIGHT){pMove->_right();pMove->Print();}else if(wParam == VK_DOWN){pMove->_down();pMove->Print();}else if(wParam == VK_LEFT){pMove->_left();pMove->Print();}else if(wParam == VK_SPACE){pMove->Init();pMove->Print();}return TRUE;
}

Duilib的 WindowImplBase类有键盘响应函数,直接重写即可。至于键盘的虚拟码,可以去看下面这个:

移动控制源码:

#include "Move.h"#define random_2_4 (rand()%5==4 ? 4:2)
#define random_x(x) (rand()%x)CMove::CMove(void)
{data = CData_2048::GetInstance();
}
CMove::~CMove(void)
{
}
void CMove::Init()
{data->_count = 0;data->score = 0;memset(data->_matrix,0,sizeof(data->_matrix));srand((int)time(0));for (int i = 0; i < 2; i++)random_data_one();
}
void CMove::AddButton(CButtonUI* bt)
{data->buttons.push_back(bt);
}
bool CMove::b_up()
{for (int k = 0; k < 4; k++){bool flag = false;for (int i = 0; i < 4 - 1; i++){if (data->_matrix[i][k] == 0)flag = true;else{int j = i + 1;while (j < 4){if (data->_matrix[j][k]){if (data->_matrix[i][k] == data->_matrix[j][k])return true;elsebreak;}else{++j;}}}}if (flag){int i = 0, j = 4 - 1;while (i < 4){if (data->_matrix[i][k])++i;elsebreak;}while (j >= 0){if (data->_matrix[j][k] == 0)--j;elsebreak;}if (i < j)return true;}}return false;
}
bool CMove::b_left()
{for (int k = 0; k < 4; k++){bool flag = false;for (int i = 0; i < 4 - 1; i++){if (data->_matrix[k][i] == 0)flag = true;else{int j = i + 1;while (j < 4){if (data->_matrix[k][j]){if (data->_matrix[k][i] == data->_matrix[k][j])return true;elsebreak;}else{++j;}}}}if (flag){int i = 0, j = 4 - 1;while (i < 4){if (data->_matrix[k][i])++i;elsebreak;}while (j >= 0){if (data->_matrix[k][j] == 0)--j;elsebreak;}if (i < j)return true;}}return false;
}
bool CMove::b_down()
{for (int k = 0; k < 4; k++){bool flag = false;for (int i = 4 - 1; i > 0; i--){if (data->_matrix[i][k] == 0)flag = true;else{int j = i - 1;while (j >= 0){if (data->_matrix[j][k]){if (data->_matrix[i][k] == data->_matrix[j][k])return true;elsebreak;}else{--j;}}}}if (flag){int i = 0, j = 4 - 1;while (i < 4){if (data->_matrix[i][k] == 0)++i;elsebreak;}while (j >= 0){if (data->_matrix[j][k])--j;elsebreak;}if (i < j)return true;}}return false;
}
bool CMove::b_right()
{for (int k = 0; k < 4; k++){bool flag = false;for (int i = 4 - 1; i > 0; i--){if (data->_matrix[k][i] == 0)flag = true;else{int j = i - 1;while (j >= 0){if (data->_matrix[k][j]){if (data->_matrix[k][i] == data->_matrix[k][j])return true;elsebreak;}else{--j;}}}}if (flag){int i = 0, j = 4 - 1;while (i < 4){if (data->_matrix[k][i] == 0)++i;elsebreak;}while (j >= 0){if (data->_matrix[k][j])--j;elsebreak;}if (i < j)return true;}}return false;
}
void CMove::_up()
{if (b_up()){for (int i = 0; i < 4; i++){memset(data->current, 0, sizeof(int)*4);int ii = 0;for (int j = 0; j < 4; j++){if (data->_matrix[j][i])data->current[ii++] = data->_matrix[j][i];}for (int k = 0; k < ii - 1; k++){if (data->current[k] == data->current[k + 1]){data->current[k] *= 2;data->score += data->current[k];data->current[k + 1] = 0;++k;--data->_count;}}ii = 0;for (int j = 0; j < 4; j++){if (data->current[j])data->_matrix[ii++][i] = data->current[j];}for (; ii < 4; ii++)data->_matrix[ii][i] = 0;}random_data_one();}
}
void CMove::_down()
{if (b_down()){for (int i = 0; i < 4; i++){memset(data->current, 0, sizeof(int)*4);int ii = 0;for (int j = 4 - 1; j >= 0; j--){if (data->_matrix[j][i])data->current[ii++] = data->_matrix[j][i];}for (int k = 0; k < ii - 1; k++){if (data->current[k] == data->current[k + 1]){data->current[k] *= 2;data->score += data->current[k];data->current[k + 1] = 0;++k;--data->_count;}}ii = 4 - 1;for (int j = 0; j < 4; j++){if (data->current[j])data->_matrix[ii--][i] = data->current[j];}for (; ii >= 0; ii--)data->_matrix[ii][i] = 0;}random_data_one();}
}
void CMove::_left()
{if (b_left()){for (int i = 0; i < 4; i++){memset(data->current, 0, sizeof(int)*4);int ii = 0;for (int j = 0; j < 4; j++){if (data->_matrix[i][j])data->current[ii++] = data->_matrix[i][j];}for (int k = 0; k < ii - 1; k++){if (data->current[k] == data->current[k + 1]){data->current[k] *= 2;data->score += data->current[k];data->current[k + 1] = 0;++k;--data->_count;}}ii = 0;for (int j = 0; j < 4; j++){if (data->current[j])data->_matrix[i][ii++] = data->current[j];}for (; ii < 4; ii++)data->_matrix[i][ii] = 0;}random_data_one();}
}
void CMove::_right()
{if (b_right()){for (int i = 0; i < 4; i++){memset(data->current, 0, sizeof(int)*4);int ii = 0;for (int j = 4 - 1; j >= 0; j--){if (data->_matrix[i][j])data->current[ii++] =data->_matrix[i][j];}for (int k = 0; k < ii - 1; k++){if (data->current[k] == data->current[k + 1]){data->current[k] *= 2;data->score += data->current[k];data->current[k + 1] = 0;++k;--data->_count;}}ii = 4 - 1;for (int j = 0; j < 4; j++){if (data->current[j])data->_matrix[i][ii--] =data-> current[j];}for (; ii >= 0; ii--)data->_matrix[i][ii] = 0;}random_data_one();}
}
bool CMove::random_data_one()
{if (data->_count == 16)return false;int left = 16 - data->_count;int tmp = random_x(left);int num = random_2_4;int k = 0;for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (data->_matrix[i][j] == 0){if (k++ == tmp){data->_matrix[i][j] = num;break;}}}}++data->_count;return true;
}

上述代码中data是个单例模式的对象,如下定义:

class CData_2048
{
public:int _matrix[4][4];int current[4];int _count;int score;CTextUI* scores;vector<CButtonUI*>buttons;static CData_2048* GetInstance();static void Release();
private:CData_2048();static CData_2048*  t_;
};

关于移动类的方法没有做优化,有点挫了。

图形显示:

void CPrintArray::Print()
{for(int k=0;k<16;k++){data->buttons[k]->SetText(_T(""));data->buttons[k]->SetAttribute(_T("bkcolor"),_T("#FFCCC0B3"));}for (int i = 0; i<4;i++){for (int j=0;j<4;j++){if(data->_matrix[i][j]!=0)showbutton(data->buttons[i*4+j],data->_matrix[i][j]);}}TCHAR str[5];sprintf(str,"%d",data->score);data->scores->SetText(str);
}
void CPrintArray::showbutton(CButtonUI* bt,int num)
{TCHAR str[10];sprintf(str,"%d",num);if(num==2){bt->SetAttribute(_T("bkcolor"),_T("#ffeee4da"));bt->SetAttribute(_T("textcolor"),_T("776e65"));}else if(num==4){bt->SetAttribute(_T("bkcolor"),_T("#ffede0c8"));bt->SetAttribute(_T("textcolor"),_T("ff776e65"));}else if(num==8){bt->SetAttribute(_T("bkcolor"),_T("#fff2b179"));bt->SetAttribute(_T("textcolor"),_T("fff9f6f2"));}else if(num==16){bt->SetAttribute(_T("bkcolor"),_T("#fff59563"));bt->SetAttribute(_T("textcolor"),_T("fff9f6f2"));}else if(num==32){bt->SetAttribute(_T("bkcolor"),_T("#fff67c5f"));bt->SetAttribute(_T("textcolor"),_T("fff9f6f2"));}else if(num==64){bt->SetAttribute(_T("bkcolor"),_T("#fff65e3b"));bt->SetAttribute(_T("textcolor"),_T("fff9f6f2"));}else if(num>=128){bt->SetAttribute(_T("bkcolor"),_T("#ffedcf72"));bt->SetAttribute(_T("textcolor"),_T("fff9f6f2"));}
<span style="white-space:pre">  </span>//......bt->SetText(str);
}

这个显示方式比较笨拙吧,其实套用一个装饰模式可以很好的实现,如下:

class _Button
{
public: CButtonUI* m_ButtonUI;int m_num;_Button(int num,CButtonUI* button):m_num(num),m_ButtonUI(button){}virtual ~_Button() {}  virtual void UpButtonData() {}
};class Num_Button:public _Button
{
public:Num_Button(int num,CButtonUI* button):_Button(num,button){}void UpButtonData(){switch(m_num){case 2:case 4:m_ButtonUI->SetAttribute(_T("textcolor"),_T("776e65"));break;default:m_ButtonUI->SetAttribute(_T("textcolor"),_T("fff9f6f2"));}TCHAR str[10];sprintf(str,"%d",m_num);m_ButtonUI->SetText(str);}
};
class SetButton:public _Button
{
protected: _Button* m_BkButton;
public:  SetButton(_Button* bkbutton):m_BkButton(bkbutton),_Button(bkbutton->m_num,bkbutton->m_ButtonUI){}  virtual void UpButtonData() {  m_BkButton->UpButtonData();}
};
class Color_Button:public SetButton
{
public:Color_Button(_Button* bkbutton):SetButton(bkbutton){}void UpButtonData() {SetButton::UpButtonData();AddSetButton();}
private:void AddSetButton(){switch (m_num){case 0: m_ButtonUI->SetAttribute(_T("bkcolor"),_T("#FFCCC0B3"));break;case 2: m_ButtonUI->SetAttribute(_T("bkcolor"),_T("#ffeee4da"));break;case 4: m_ButtonUI->SetAttribute(_T("bkcolor"),_T("#ffede0c8"));break;case 8: m_ButtonUI->SetAttribute(_T("bkcolor"),_T("#fff2b179"));break;case 16: m_ButtonUI->SetAttribute(_T("bkcolor"),_T("#fff59563"));break;case 32: m_ButtonUI->SetAttribute(_T("bkcolor"),_T("#fff67c5f"));break;case 64: m_ButtonUI->SetAttribute(_T("bkcolor"),_T("#fff65e3b"));break;default:m_ButtonUI->SetAttribute(_T("bkcolor"),_T("#ffedcf72"));}}
};class Form_Button:public SetButton
{
public:Form_Button(_Button* bkbutton):SetButton(bkbutton){}void UpButtonData() {SetButton::UpButtonData();AddSetButton();}
private:void AddSetButton(){SIZE si;si.cx = si.cy =4;m_ButtonUI->SetBorderRound(si);}
};

所以那个CPrintArray::showbutton函数可以这么写了:

         _Button* button1 = new Num_Button(num,bt);_Button* button2= new Form_Button(button1);_Button* button3 = new Color_Button(button2);button3->UpButtonData();

资源下载

实现比较简单,源码几乎全贴了,自己尝试一次,肯定可以搞定,以后再放资源!

Duilib之挑战2048相关推荐

  1. 挑战2048成功,谈谈技巧(无限版已更新+同人作品)

    原版游戏地址:http://gabrielecirulli.github.io/2048/ 好玩的几个同人作品:(持续更新) 1.PRC-合并方块,努力到达 PRC 时代吧 备注:到了"清& ...

  2. python里graphics的使用_使用graphics.py实现2048小游戏

    1.过年的时候在手机上下载了2048玩了几天,心血来潮决定用py写一个,刚开始的时候想用QT实现,发现依赖有点大.正好看到graphics.py是基于tkinter做的封装就拿来练手,并借用了CSDN ...

  3. 微信小程序|使用小程序制作一个2048小游戏

    文章目录 一.文章前言 二.创建小程序 三.功能开发 一.文章前言 此文主要通过小程序实现2048游戏,游戏操作简单,容易上手. 规则:正常打开游戏的界面,会只有两个2,每次移动后都会出现一个2,数字 ...

  4. 微信公众平台开发(100) 2048游戏

    微信开发第100篇了,算上微信支付和微信小店,其实已经超过了,这次完整讲一下2048游戏吧. 一.2048游戏 <2048>是比较流行的一款数字游戏.原版2048首先在github上发布, ...

  5. Android开发自定义View实现数字与图片无缝切换的2048

    本博客地址:http://blog.csdn.net/talentclass_ctt/article/details/51952378 最近在学自定义View,无意中看到鸿洋大神以前写过的2048(附 ...

  6. 网页版《2048游戏》

    源码下载: https://gitee.com/cheng-hanyuan/example_projec/tree/main/%E6%A1%88%E4%BE%8B%E9%A1%B9%E7%9B%AE/ ...

  7. python设计2048小游戏_使用graphics.py实现2048小游戏

    1.过年的时候在手机上下载了2048玩了几天,心血来潮决定用py写一个,刚开始的时候想用QT实现,发现依赖有点大.正好看到graphics.py是基于tkinter做的封装就拿来练手,并借用了CSDN ...

  8. C/C++编程笔记:流行的数字游戏【2048】,C语言400行源代码分享

    游戏介绍 你玩过2048吗?2048是一款流行于各大网页和手机的数字游戏,手机安卓版推出的是<挑战2048>,之后的版本中还加入了双人对战的游戏模式,更加受到玩家的热捧. 2048的游戏规 ...

  9. C语言——应用与游戏

    第四部分 关于C语言的新知识已经不多了,本章节将介绍宏定义.结构体共用体.程序文件层次等知识,接着将与大家一起运用我们所学知识编写具有实际功能意义的C语言程序. 宏定义与别名 宏定义 宏定义就是将一句 ...

  10. 看会、参会、相亲、购物、领奖,1024 程序员节带你嗨玩!

    转眼又是十月,程序员们翘首以盼.相约面基的1024大会又双叒叕要惊喜上线啦!10月23日,楚汉名城--风里雨里,CSDN(长沙等你)! 除了满足程序员对这场技术饕餮盛宴的期待,2022 长沙 · 中国 ...

最新文章

  1. python property装饰器原理,Python @property装饰器不起作用
  2. centeros7网络服务无法启动_Linux网络服务02——DHCP原理与配置
  3. 计算机保研去北科大还是大工,全部保研!大工这寝室太牛
  4. Spring(AbstractRoutingDataSource)实现动态数据源切换
  5. python编程入门p-Python是什么?简单了解pythonp-入门
  6. 自定义控件:广告内容后期加载。以及NamingContainer层次的应用
  7. Axure函数与变量
  8. 杭电计算机组成实验2(二)超前进位加法器设计实验
  9. laravel redis_php session 存储到redis里
  10. Qt安装事件过滤器、过滤子控件事件、截获控件按键、鼠标事件
  11. python划分训练集、验证集和测试集
  12. linux下python网络编程框架-twisted安装手记,Linux下Python网络编程框架-Twisted安装手记 | 学步园...
  13. PHP在线手册 中文版
  14. PyCharm输入法无法切换中英文
  15. (※)中序遍历二叉树的非递归算法
  16. python文件操作3--批量修改文件后缀名
  17. 尚硅谷--Java--基础篇(717集)
  18. matlab实现三自由度机械臂旋转
  19. TCP滑动窗口,流量控制,拥塞控制详解
  20. 3D激光雷达SLAM算法学习01——3D激光SLAM整体框架

热门文章

  1. 【渗透测试】编辑器漏洞
  2. IEC 60068-2 规范介绍
  3. JavaScript格式化日期和时间
  4. C语言程序设计孙家啸第一版,广东(年4月自考各专业课程使用教材.doc
  5. 日常消费软件记账项目
  6. 史上最简便的可以直接用的登录验证码攻略(前后端都有)
  7. 支招功能最强人工智能围棋软件_AI智能棋盘全新上线,围棋的奥秘原来在这里?...
  8. echarts中的自定义tooltip浮层展示
  9. 内核5.4以上, Realtek 8111网卡初始化失败
  10. 9.DLL的入口函数DllMain函数