《C++ Qt 设计模式》8|15拼图 小游戏的简单实现。拜托,别乱点!
第零章:介绍
看到这个游戏了,感觉蛮好玩的,实现了一下。
界面如下:
游戏玩法:在3×*3的矩阵中,每个按钮都可以点击,如果按钮四周有一个是空白,则点击此按钮则会移动到这个空白。按钮字母顺序变成“ABCD……”这样有序就赢了,最后空格可以出现在任何地方。
第一章:构思
设计模式基本上没接触过,所以就没有按书上的方式,自己想了大概要怎么实现,可能自己像的没有它给出的方式好吧,但是毕竟是菜鸟嘛,一步一步来!
1、用什么装这些按钮
学习了QGridLayOut,“The QGridLayout class lays out widgets in a grid”,这就好办了,它会把窗体控件放到一个网格里面,也就是说类似与矩阵啦,ABC……这些肯定就是就是一个个QPushButton啦,创建了一个个按钮,再把它装进去即可。最后这个QGridLayOut设置为QDialog的LayOut就可以了。
这个是从显示层面考虑的。
2、如何用代码表示一个3×3的矩阵
虽然可以把一个窗体放到一个QGridLayOut来进行布局,它有如下添加函数:
void addWidget ( QWidget * widget, int row, int column, Qt::Alignment alignment = )
但是由于我对QGridLayOut不熟,不知道是否可以用类似与矩阵的存取方式,即给定行列,获取里面的东西。所以我用了一个矩阵,也就是一个二维数组啦,对应每一个按钮,数组里面放的是指向按钮的指针,空白就放一个NULL指针,因为几个按钮创建好了就在内存那里了,不动了,所以以后我交换一个按钮与一个空白的时候就这要交换这两个指针就加上重新QGridLayOut的方法addWidget就可以了。
3、需要哪些类
需要两个类,一个MyButton,公有继承QPushButton,还有Dialog类,公有继承QDialog,即显示主界面啦。
4、如何实现点击按钮就移动呢
点击按钮时按钮发射clicked()信号,但是Dialog类不知道是哪一个按钮,所以要重新发射一个信号,把指向自己的指针this当做参数,按后Dialog类就可以知道是谁了,在判断时候需要移动。
第三章:MyButton类的实现
直接上代码:
#ifndef MYBUTTON_H
#define MYBUTTON_H #include <QPushButton> struct Coord
{
int x;
int y;
}; class MyButton : public QPushButton
{
Q_OBJECT private:
Coord m_coord; public:
explicit MyButton(char c,Coord coord,QWidget* parent=);
void setCoord(Coord newCd);
Coord getCoord() const; signals:
void myClick(MyButton* p); //signal,argument is poiter to myself,so someone else can identify me private slots:
void btClicked();
}; #endif // MYBUTTON_H
mybutton.h
#include "mybutton.h" #include <QMessageBox> MyButton::MyButton(char c,Coord coord, QWidget *parent) : QPushButton(parent)
{ setText(QString("%1").arg(c));
this->m_coord=coord;
connect(this,SIGNAL(clicked()),this,SLOT(btClicked()));
} void MyButton::setCoord(Coord newCd)
{
m_coord=newCd;
} Coord MyButton::getCoord() const
{
return m_coord;
} void MyButton::btClicked()
{
emit myClick(this);
}
mybutton.cpp
我给每一个按钮一个坐标的数据了,因为按钮创建好了就在内存的某个位置不动了,如何表示他们对应显示的哪一个呢?这个坐标就相当于标示一个按钮,ABCD……只是他们显示的文字,这个是不变的。
构造函数的参数char是它要显示的东西,Coord是自定义结构体表示坐标。
connect(this,SIGNAL(clicked()),this,SLOT(btClicked()));
void MyButton::btClicked()
{
emit myClick(this);
}
注意这个,这样就可以让Dialog类自己写一个槽,这个槽由上面的this参数就可以知道是哪个按钮被点了,在这里居然想了好久……
第四章:Dialog类的实现
1、类的声明:
#ifndef DIALOG_H
#define DIALOG_H #include <QDialog>
#include "mybutton.h" class QGridLayout;
class QPushButton; namespace Ui {
class Dialog;
} class Dialog : public QDialog
{
Q_OBJECT public:
explicit Dialog(QWidget *parent = );
~Dialog(); private:
Ui::Dialog *ui; static const int N=;
QGridLayout* m_lay;
MyButton* m_pbArr[N][N];
QString m_btnTextOrder;
private slots:
void btClicked(MyButton* p); //one of N*N buttons has been clicked private:
void disorder(); //disorder the N*N buttons
void exchangeButton(Coord a,Coord b); //exchange two buttons based on coord
bool isOver() const; //is it in order???
}; #endif // DIALOG_H
dialog.h
一一说明数据成员的含义,源代码没有注释是因为输入不了中文,我才不要鸡鸡比注释短呢……
static const int N=3; 表明是几乘几的矩阵
QGridLayout* m_lay; 布局
MyButton* m_pbArr[N][N]; 对应布局的矩阵,数组里面放的都是指向按钮的指针,移动一个按钮只要交换对应的指针并把按钮的私有坐标改一下并在布局里面弄一下即可
QString m_btnTextOrder; 用到就知道了
2、构造函数:
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
setWindowTitle("Let us have a game!");
setMinimumSize(,);
setMaximumSize(,); m_lay=new QGridLayout(this); for(int i=;i<N;i++)
{
int colums;
if(i<N-) colums=N;
else colums=N-; for(int j=;j<colums;j++)
{
char c=i*N+j+'A';
m_btnTextOrder.append(c); Coord cd={i,j};
m_pbArr[i][j]=new MyButton(c,cd); m_lay->addWidget(m_pbArr[i][j],i,j);
connect(m_pbArr[i][j],SIGNAL(myClick(MyButton*)),this,SLOT(btClicked(MyButton*)));
}
}
m_pbArr[N-][N-]=NULL;
this->setLayout(m_lay); disorder(); //make buttons disorder
}
构造函数
先把窗口大小固定了。
new一个QGridLayout。
然后的双层循环用来创建一个个按钮对象,创建一个对象就把它添加到QGridLayOut,这样就有了秩序了,然后就连接每个按钮被点击的槽了。
最后把最后一个位置的没有按钮的赋值为空指针。
最最后使这些按钮无序,这个稍后介绍。
3、按钮被点击啦
void Dialog::btClicked(MyButton* p)
{
Coord cd=p->getCoord(); //get the button that been clicked
Coord cdTarget=cd; //target position that maybe switch if((cd.x->=)&&(m_pbArr[cd.x-][cd.y]==NULL)) //test top
{
cdTarget.x--;
}
else if((cd.x+<N)&&(m_pbArr[cd.x+][cd.y]==NULL)) //test down
{
cdTarget.x++;
}
else if((cd.y->=)&&(m_pbArr[cd.x][cd.y-]==NULL)) //test left
{
cdTarget.y--;
}
else if((cd.y+<N)&&(m_pbArr[cd.x][cd.y+]==NULL)) //test right
{
cdTarget.y++;
}
else
{
return; //can not move this button
} /*let us switch!*/
exchangeButton(cd,cdTarget); /*check whether game is over*/
if(isOver())
{
QMessageBox::warning(this,"Sucess","You made it! Congratulations!");
}
}
按钮被点击事件
被点击后可以通过按钮发射的信号获得按钮的指针,再通过按钮的获得按钮的坐标。然后看这个坐标上下左右是否有一个是空格,没有就什么都不做,有的话就把这个按钮移动到那个位置,实质上是交换。
void Dialog::exchangeButton(Coord a, Coord b)
{
if((m_pbArr[a.x][a.y]!=NULL)&&(m_pbArr[b.x][b.y]!=NULL)) //no NULL
{
/*remove from pre QGridLayOut*/
m_lay->removeWidget(m_pbArr[a.x][a.y]);
m_lay->removeWidget(m_pbArr[b.x][b.y]); /*add to QGridLayOut*/
m_lay->addWidget(m_pbArr[a.x][a.y],b.x,b.y);
m_lay->addWidget(m_pbArr[b.x][b.y],a.x,a.y); /*change two buttons's coord */
m_pbArr[a.x][a.y]->setCoord(b);
m_pbArr[b.x][b.y]->setCoord(a); /*exchange poiter in m_pbArr[] */
MyButton* temp=m_pbArr[a.x][a.y];
m_pbArr[a.x][a.y]=m_pbArr[b.x][b.y];
m_pbArr[b.x][b.y]=temp;
}
else //one of two buttons' position is NULL (in array m_pbArr[])
{
if(m_pbArr[a.x][a.y]==NULL)
{
Coord temp=a;
a=b;
b=temp;
} /*here,we can make sure that coord b is null*/
m_lay->removeWidget(m_pbArr[a.x][a.y]);
m_lay->addWidget(m_pbArr[a.x][a.y],b.x,b.y);
m_pbArr[a.x][a.y]->setCoord(b);
MyButton* temp=m_pbArr[a.x][a.y];
m_pbArr[a.x][a.y]=m_pbArr[b.x][b.y];
m_pbArr[b.x][b.y]=temp;
}
}
交换按钮
交换分为两周情况,两个按钮的交换,这个再使界面无序化时调用,另一个就是交换按钮与空白,只要看前一个就足够了。
先把待交换的两个按钮从QGridLayOut拿下来,具体表现就是不显示了。
再交叉添加到QGridLayOut的特定坐标。
再把两个按钮的私有数据也就是坐标交换一下,因为坐标通过这个坐标从得到被点按钮的位置的。
再把数据层(QGridLayOut是显示层)的指针也互换一下,让他们指向对的按钮内存。
4、使无序化
void Dialog::disorder()
{
Coord cdA,cdB;
for(int i=;i<;i++)
{
QTime time=QTime::currentTime();
qsrand(time.msec()*+time.second()*);
cdA.x=qrand()%N; //from 0 to N-1
qsrand(time.second()+i*+);
cdA.y=qrand()%N; qsrand(time.msec()*+i);
cdB.x=qrand()%N;
qsrand(time.msec()+i*);
cdB.y=qrand()%N; // qDebug()<<cdA.x<<cdA.y<<"-----"<<cdB.x<<cdB.y<<endl;
if((cdA.x==cdB.x)&&(cdA.y==cdB.y))
{
i--;
}
else //not the same coord
{
exchangeButton(cdA,cdB);
}
}
}
无序化
游戏开始是无序的,这个函数就是干这事的,有了上面的交换,那么只要随即生成坐标,把指定坐标的按钮交换即可。关键这里的产生随即坐标的函数,我写的不太好,调试时可以看出好多对坐标一样,因为计算机太快了。
5、检测是否结束
bool Dialog::isOver() const
{
QString res;
for(int i=;i<N;i++)
{
for(int j=;j<N;j++)
{
if(m_pbArr[i][j]!=NULL)
{
res.append(m_pbArr[i][j]->text());
}
}
} if(res==m_btnTextOrder)
{
return true;
}
else
{
return false;
}
}
是否结束
每一次点击按钮都执行一下,看时候结束了。我写的就是按照矩阵顺序一个一个按钮读,读它的文本,追加到一个字符串,最后和“ABCD……”字符串比较,相等就结束了。
第五章:遗言
1、QGridLayOut
显示与数据表示分离了,这个不太好。
2、啦啦啦啦啦啦
我会告诉你我只有一次成功了吗?
我想随机交换之后会不会本身就有成功不了的可能?数学理论啊!
《C++ Qt 设计模式》8|15拼图 小游戏的简单实现。拜托,别乱点!的更多相关文章
- 使用NGUI实现拖拽功能(拼图小游戏)
上一次用UGUI实现了拼图小游戏,这次,我们来用NGUI来实现 实现原理 NGUI中提供了拖拽的基类UIDragDropItem,所以我们要做的就是在要拖拽的图片上加一个继承于该类的脚本,并实现其中的 ...
- 仿苹果电脑任务栏菜单&&拼图小游戏&&模拟表单控件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- JavaScript版拼图小游戏
慕课网上准备开个新的jQuery教程,花了3天空闲时间写了一个Javascript版的拼图小游戏,作为新教程配套的分析案例 拼图游戏网上有不少的实现案例了,但是此源码是我自己的实现,所以不做太多的比较 ...
- jQuery实现拼图小游戏
小熊维尼拼图 2017-07-23 ...
- jQuery拼图小游戏
jQuery拼图小游戏 最后样式 核心代码部分 <script type="text/javascript" > $(function () { $("td& ...
- 在HTML页面中有jQuery实现实现拼图小游戏
1.用jQuery实现拼图小游戏 2.首先获得td的点击事件.再进行交换位置 3.下面这种仅供参考 4.下面这些是HTMl标签 当这个世界变得越来越复杂的时候,内心最需保持一份简单一份纯真:
- swift 拼图小游戏
依据这位朋友的拼图小游戏改编 http://tangchaolizi.blog.51cto.com/3126463/1571616 改编主要地方是: 原本着我仁兄的代码时支持拖动小图块来移动的,我參照 ...
- 教你用Python自制拼图小游戏,一起来制作吧
摘要: 本文主要为大家详细介绍了python实现拼图小游戏,文中还有示例代码介绍,感兴趣的小伙伴们可以参考一下. 开发工具 Python版本:3.6.4 相关模块: pygame模块: 以及一些Pyt ...
- 打造专属自己的html5拼图小游戏
最近公司刚好有个活动是要做一版 html5的拼图小游戏,于是自己心血来潮,自己先实现了一把,也算是尝尝鲜了.下面就把大体的思路介绍一下,希望大家都可以做出一款属于自己的拼图小游戏,必须是更炫酷,更好玩 ...
随机推荐
- Delphi 7 升级到 Delphi 2010 总结
1 字符串 >>string =unicodeString 字母的处理要定义AnsiString了 >>PChar =PWidechar >>str='普通汉字' ...
- asp.net mvc控制器动作体返回ImageResult,可作验证码
public ActionResult Img() { // 获取博客园空间顶部的banner图片 WebRequest req = WebRequest.Create("http://sp ...
- [Bower] Bower
//search bower search jquery bower search jquery | grep formstyler //info bower info jquery //instal ...
- iOS开发——网络编程Swift篇&(二)同/异&步请求
同/异&步请求 同步: // MARK: - 同步请求 func httpSynchronousRequest() { //创建NSURL对象 var url:NSURL! = NSURL(s ...
- ConfigurationManager.GetSection()方法的使用
GetSection方法读取的是configSections节点,这个节点在web.config配置文件中,它比较特殊,必须放置于首节点,也就是说,在它之前不能有其它类型的节点.configSecti ...
- 申请TexturePacker 或 PhysicsEditor free licenses
有一个跟开发有关的blog,就可以去 http://www.codeandweb.com/request-free-license 申请一个free licenses. 可以申请TexturePack ...
- Linux 学习笔记 cp 和 ln
最近在重温大学的经典课程:Linux.每天工作之余的时间,坐在家里的阳台上,简简单单的纪录一些基本的知识点,对我来说,既温暖又难得. 有朋友问我关于cp和ln建立符号链接(软链接)和硬链接的一些问题, ...
- MYSQL基础笔记(六)- 数据类型一
数据类型(列类型) 所谓数据烈性,就是对数据进行统一的分类.从系统角度出发时为了能够使用统一的方式进行管理,更好的利用有限的空间. SQL中讲数据类型分成三大类:1.数值类型,2.字符串类型和时间日期 ...
- oracle的控制语句if和循环语句loop while for
pl/sql的控制结构if-then if-then-else if-then-elsif-else 案例1:编写一个过程,可以输入一个雇员名,如果该雇员的工资低于2000,就给该雇员工资增加10% ...
- 关于直接创建视图UITableViewController显示(初学)
今天渣渣想直接创建一个UITableView视图作为根视图来用结果发现有警告,才明白TableView和view是不能直接作为根视图的,需要放在ViewController上.做个笔记详细了解下. 参 ...