QQ头像连连看总结

发布时间:2020-07-06 13:46:56   来源:文档文库   
字号:

QQ头像连连看

1、程序说明

本程序名为QQ头像连连看,采用QQ头像为图片,利用MFC对话框程序完成连连看 游戏。

2、设计要求及实现功能

1、分级别的连连看。程序中分低、中、高三级模式,每一个级别响应的图片数目不同。

2、提示功能。当游戏者找不到可以消去的图片对时,可以从程序中得到提示,从而继 续进行游戏。

3、重新排列功能。当程序中图片已经没有可以消去的图片对时,提示游戏者可以点击

"重新排列"进行图片重排,从而可以继续进行图片。

4、程序具有计时功能。游戏者完成游戏应在规定时间范围内,否则应算为失败。不同 级别的游戏时间应不同。

三、概要设计

1、游戏设计思路

所谓连连看游戏,它就是在一个背景下有若干的图片,如果连续点击相同的图片, 并且可以用最多两折的线段连接之间还没有其他障碍物,就可以消掉这一对图片, 如果所有的图片都被消掉,就可取得胜利。倘若在规定的时间内没有消完所有图片,则游戏失败。

2、图片显示设计

显示的图片必须要实现点击功能。因此本设计中把图片设计为一个由CBitmapButton派生出的自定义的按钮数组。可以实现显示图片及点击功能。

使每个自定义的按钮都有自己的ID 号,用来存储图片类型,还应该有一个CPoint 类型的成员变量,用来存储每个Button 的位置信息,最后在创建时,将和ID 号对应的图片贴到相应的位置上即可。

保证每种图片都是成对出现的:首先定位到第一个按钮的位置,随机选择一种图片, 生成这个按钮,然后随机选择一个位置,仍然放置这种图片,再定位到第二个按钮的位置,随机选择一种图片,生成这个按钮,然后再随机选择一个位置,如果这个位置已经有按钮了,则重新随机选择一个位置,直到选到一个空的位置,放置相同的图片,以此类推,将整个地图布完。

3、消去算法

如果连续点击相同的图片,并且可以用最多两折的线段连接,之间还没有其他障碍物,就可以消掉这一对图片。

根据此设计思路,可以分为三种情况来实现消去算法:

(1)两个图片在同行或同列 (2)两个图片可用带一个折线的线段连接

(3)两个图片可用带两个折线的线段连接。

4、流程图

总流程图

游戏过程流程

四、详细设计

1、数据结构

(1)主窗口类CMyLLKDlg

class CMyLLKDlg : public CDialog

{ ……

private:

int MAXX;

int MAXY;

int m_left;//显示图片时,左上、右下的坐标

int m_top;

int m_right;

int m_bottom;

bool m_flag;//标记是否按开始游戏

int m_NUM;

int m_index;

CPoint m_ptCross1;

CPoint m_ptCross2;

CPoint m_ptCross3;

CPoint m_ptCross4;

public:

int m_remainBtn;

int m_time;//记录倒计时时间

int m_typeNum; //图片种类数

int map[20][20]; //地图数组,存储图片类型

int m_BtnClkNum;

CPtr m_btnGroup; //Button

CPoint m_firstBtnPoint;

CPoint m_secondBtnPoint;

void Init(void);

void InitMap(int map[][20]);

void ShowMap(int map[][20]);

void ProcessGame(void);

bool FindHelp(void);

bool FindLine(CPoint p1, CPoint p2);

bool FindSide(CPoint p1, CPoint p2);

bool FindOneConner(CPoint p1, CPoint p2);

bool FindTwoConner(CPoint p1, CPoint p2);

afx_msg void OnTimer(UINT_PTR nIDEvent);

afx_msg void OnHelp();

afx_msg void OnRerange();

afx_msg void OnStartLow();

afx_msg void OnStartMid();

afx_msg void OnStartHig();

afx_msg void OnExit();

afx_msg void OnInstruc();

afx_msg void OnOpenmusic(); };

(2)CMyLLKApp

(3)连连看按钮类CLLKButton

class CLLKButton : public CBitmapButton

{

DECLARE_DYNAMIC(CLLKButton)

public:

CLLKButton(int id,CPoint p);

virtual ~CLLKButton();

CPoint m_clkPoint;//保存点击的点位置

CPoint m_virPoint;

int m_ID;//标记每张图片的ID

int BitmapID;//位图的ID

BOOL IsClick;//判断是否被按下

protected:

DECLARE_MESSAGE_MAP()

public:

afx_msg void OnLButtonDown(UINT nFlags, CPoint point); };

(4)游戏介绍窗口类CInstrcDlg

(5)关于窗口类CAboutDlg

2、主要函数

(1)CLLKButton::CLLKButton(int id,CPoint p)

CLLKButton::CLLKButton(int id,CPoint p)

{ this->m_clkPoint.x=p.x;

this->m_clkPoint.y=p.y;

this->m_ID=id;

BitmapID=m_ID+IDB_BITMAP1-1;//IDB_BITMAP1==130

m_virPoint.x=0;

m_virPoint.y=0;

IsClick=FALSE; }

(2)CLLKButton类成员函数:void OnLButtonDown(UINT nFlags, CPoint point)

void CLLKButton::OnLButtonDown(UINT nFlags, CPoint point)

{ CMyLLKDlg *parent=(CMyLLKDlg *)GetParent();

m_virPoint.x=m_clkPoint.x;

m_virPoint.y=m_clkPoint.y;

//this->ShowWindow(SW_HIDE);

IsClick=TRUE;

parent->m_BtnClkNum++;

if (parent->m_BtnClkNum==1)

{ parent->m_firstBtnPoint.x=m_virPoint.x;

parent->m_firstBtnPoint.y=m_virPoint.y; }

else if (parent->m_BtnClkNum==2)

{ parent->m_secondBtnPoint.x=m_virPoint.x;

parent->m_secondBtnPoint.y=m_virPoint.y;

if ((parent->FindLine(parent->m_firstBtnPoint,parent->m_secondBtnPoint)==TRUE||

parent->FindOneConner(parent->m_firstBtnPoint,parent->m_secondBtnPoint)||

parent->FindTwoConner(parent->m_firstBtnPoint,parent->m_secondBtnPoint))&&

(parent->map[parent->m_firstBtnPoint.x][parent->m_firstBtnPoint.y]==

parent->map[parent->m_secondBtnPoint.x][parent->m_secondBtnPoint.y]))

{

parent->map[parent->m_firstBtnPoint.x][parent->m_firstBtnPoint.y]=0;

parent->map[parent->m_secondBtnPoint.x][parent->m_secondBtnPoint.y]=0;

parent->m_remainBtn-=2;

parent->ProcessGame();

parent->m_BtnClkNum=0;

parent->m_firstBtnPoint=0;

parent->m_secondBtnPoint=0;

}

else

{ parent->m_BtnClkNum=1;

parent->m_firstBtnPoint.x=parent->m_secondBtnPoint.x;

parent->m_firstBtnPoint.y=parent->m_secondBtnPoint.y;

parent->m_secondBtnPoint=0; }

}

CBitmapButton::OnLButtonDown(nFlags, point); }

(3)主窗口构造函数

CMyLLKDlg::CMyLLKDlg(CWnd* pParent /*=NULL*/)

: CDialog(CMyLLKDlg::IDD, pParent)

, m_ptCross1(0)

{ m_hIcon = AfxGetApp()->LoadIcon(IDI_LLK);

m_index=0;

m_BtnClkNum=0;

m_firstBtnPoint=0;

m_secondBtnPoint=0;

m_time=0;

m_flag=0;

m_NUM=10; }

(4)CMyLLKDlg::OnPaint()

void CMyLLKDlg::OnPaint()//修改显示画面

{ CPaintDC dc(this);

CPen *pRedPen = new CPen;

pRedPen->CreatePen(PS_SOLID, 2, RGB(255,0,0));//设置字体颜色

CGdiObject *pOldPen = dc.SelectObject(pRedPen);//选择画笔

CFont font;

CString str;

str.Format("剩余时间: %d ",m_time);//m_time 中存储剩余时间信息

font.CreatePointFont(150,"宋体");//设置字体

dc.SelectObject(&font);

dc.SetTextColor(RGB(255,0,0));//设置字体颜色为红色

dc.SetBkColor(RGB(0,0,0));//设背景为黑色

//设置背景为透明,本例中即为黑色TRANSPARENT

dc.TextOut(500,10,str); //显示倒计时

…… }

(5)CMyLLKDlg::InitMap(int map[][20])

void CMyLLKDlg::InitMap(int map[][20])//初始化图片

{ int i,j;

int x,y;

int type;

srand((unsigned int)time(NULL));//随机数种子

for(i=0;i<MAXX;i++)//初始化,全部置零

for(j=0;j<MAXY;j++)

map[i][j]=0;

for(i=1;i<MAXX-1;i++)//设置各图片的类型,最外一圈不放图片

for(j=1;j<MAXY-1;j++)

{ if(map[i][j]!=0)

continue;

else

{ type=rand()%m_typeNum;//图片种类

map[i][j]=type+1;

do //随机产生xy,放置相同图片

{ x = rand()%(MAXX-2)+1;

y = rand()%(MAXY-2)+1; }

while(map[x][y]);

map[x][y]=type+1;

}

}

}

(6)CMyLLKDlg::ShowMap(int map[][20])

void CMyLLKDlg::ShowMap(int map[][20])//显示图片

{ int i, j;

CPoint p;

CString str;

for(i=0;i<m_btnGroup.GetSize();i++)//每次开始时清除原有按钮

delete (CLLKButton *)m_btnGroup.GetAt(i);

m_btnGroup.RemoveAll();

for(i=1;i<=MAXX-2;i++)//添加新按钮*12

for(j=1; j<=MAXY-2; j++)

{ p.x = i;

p.y = j;

m_btnGroup.Add(new CLLKButton(map[i][j], p)); }

for(i=0;i<(MAXX-2)*(MAXY-2);i++)//显示按钮

{ CLLKButton *btn = (CLLKButton *)m_btnGroup.GetAt(i);

btn->Create(str, WS_CHILD|BS_BITMAP,

CRect(m_left+(i%(MAXY-2))*40, m_top+(i/(MAXY-2))*40,

m_right+(i%(MAXY-2))*40, m_bottom+(i/(MAXY-2))*40),this,

IDC_BLOCK+i);

if(btn->m_ID)//如果为则不显示

{ str.Format("res\\%d.bmp", btn->m_ID);

HBITMAP m_fkBmp = (HBITMAP)::LoadImage

(AfxGetInstanceHandle(),

str, IMAGE_BITMAP, 0, 0,

LR_CREATEDIBSECTION|LR_LOADFROMFILE);

//加载图片

if(m_fkBmp == NULL)

if (MessageBox ("缺少图片资源!", "错误",MB_ICONERROR|MB_OK)==IDOK)

return;

btn->SetBitmap(m_fkBmp);

btn->ShowWindow(SW_SHOW);

}

else

btn->ShowWindow(SW_HIDE);

}

}

(7)CMyLLKDlg::Init(void)

void CMyLLKDlg::Init(void)//开始按钮点击初始化

{ switch(m_index)

{

case 1:

MAXX=10;

MAXY=15;

m_left=90;

m_top=90;

m_right=130;

m_bottom=130;

m_typeNum=52;

m_time=300;

break;

case 2:

MAXX=12;

MAXY=17;

m_left=90;

m_top=90;

m_right=130;

m_bottom=130;

m_typeNum=75;

m_time=400;

break;

case 3:

MAXX=14;

MAXY=19;

m_left=50;

m_top=50;

m_right=90;

m_bottom=90;

m_typeNum=102;

m_time=520;

break;

default:

break;

}

m_flag=1;

m_NUM=10;

m_remainBtn=(MAXX-2)*(MAXY-2);//剩余的图片数目

}

(8)开始按钮中三个不同等级函数

void CMyLLKDlg::OnStartLow()//初级

{ m_index=1;

Init();

InitMap(map);

ShowMap(map);

SetTimer(1,1000,NULL);//开始计时 }

void CMyLLKDlg::OnStartMid()//中级

{ m_index=2;

Init();

InitMap(map);

ShowMap(map);

SetTimer(1,1000,NULL);//开始计时 }

void CMyLLKDlg::OnStartHig()//高级

{ m_index=3;

Init();

InitMap(map);

ShowMap(map);

SetTimer(1,1000,NULL);//开始计时 }

(9)主流程函数

void CMyLLKDlg::ProcessGame(void)

{ for (int i=1;i<MAXX-1;i++)

for (int j=1;j<MAXY-1;j++)

if (map[i][j]==0)

{

CLLKButton *pBtn=(CLLKButton *)m_btnGroup.GetAt((i-1)*(MAXY-2)+j-1);

pBtn->ShowWindow(SW_HIDE);

}

if (m_remainBtn==0)

{ MessageBox("恭喜您完成游戏!");

KillTimer(1); }

}

(10)查找可消去图片算法

bool CMyLLKDlg::FindLine(CPoint p1, CPoint p2)//判断是否可以直连

{ int max,min;

int i;

if(p1.x!=p2.x||p1.y!=p2.y)//判断点击的是不是同一个点

{ if (p1.x==p2.x)//如果是同一个同一列上的

{ max=(p1.y>p2.y)?p1.y:p2.y;

min=(p1.y<p2.y)?p1.y:p2.y;

if (max==min+1)//判断是否是相邻的

return TRUE;

for (i=min+1;i<max;i++)//判断中间有没有图片隔着

if (map[p1.x][i]!=0)

return FALSE;

return TRUE;

}

if (p1.y==p2.y)

{ max=(p1.x>p2.x)?p1.x:p2.x;

min=(p1.x<p2.x)?p1.x:p2.x;

if (max==min+1)

return TRUE;

for (i=min+1;i<max;i++)

if (map[i][p1.y]!=0)

return FALSE;

return TRUE;

}

}

return FALSE; }

bool CMyLLKDlg::FindSide(CPoint p1, CPoint p2)//游戏初期找在一边的图

{ int max, min;

int i;

BOOL line=TRUE;

BOOL col=TRUE;

if( (p1.x) == (p2.x) )

{ max = (p1.y>p2.y)?p1.y:p2.y;

min = (p1.y<p2.y)?p1.y:p2.y;

for(i=min; i<=max; i++) //上侧

{ if(map[p1.x-1][i]!=0)

{ line=FALSE;

break; }

}

if(line)

{ m_ptCross1.x = p1.x-1;

m_ptCross1.y = p1.y;

m_ptCross2.x = p1.x-1;

m_ptCross2.y = p2.y;

return TRUE; }

else

line=TRUE;

for(i=min;i<=max;i++)

{ if(map[p1.x+1][i]!=0) //下侧

{ line=FALSE;

break; }

}

if(line)

{ m_ptCross1.x = p1.x+1;

m_ptCross1.y = p1.y;

m_ptCross2.x = p1.x+1;

m_ptCross2.y = p2.y;

return TRUE; }

}

else

line=FALSE;

if( (p1.y) == (p2.y) )

{ max = (p1.x>p2.x)?p1.x:p2.x;

min = (p1.x<p2.x)?p1.x:p2.x;

for(i=min; i<=max; i++)

{ if(map[i][p1.y-1]!=0) //左侧

{ col=FALSE;

break; } }

if(col)

{ m_ptCross1.x = p1.x;

m_ptCross1.y = p1.y-1;

m_ptCross2.x = p2.x;

m_ptCross2.y = p2.y-1;

return TRUE; }

else

col=TRUE;

for(i=min; i<=max; i++)

{ if(map[i][p1.y+1]!=0) //右侧

{ col=FALSE;

break; } }

if(col)

{ m_ptCross1.x = p1.x;

m_ptCross1.y = p1.y+1;

m_ptCross2.x = p2.x;

m_ptCross2.y = p2.y+1;

return TRUE; }

}

else

col=FALSE;

if(line || col)

return TRUE;

else

return FALSE;

return false; }

bool CMyLLKDlg::FindOneConner(CPoint p1, CPoint p2)

{ int maxx,maxy,minx,miny;

maxx=(p1.x>p2.x)?p1.x:p2.x;

minx=(p1.x<p2.x)?p1.x:p2.x;

maxy=(p1.y>p2.y)?p1.y:p2.y;

miny=(p1.y<p2.y)?p1.y:p2.y;

CPoint m_ptCross;

if(p1.x!=p2.x&&p1.y!=p2.y)//不同行也不同列

{ if (map[minx][maxy]==0)//如果角点被消去了

{ m_ptCross.x=minx;

m_ptCross.y=maxy;

if ((FindLine(p1,m_ptCross))&&(FindLine(m_ptCross,p2)))

return TRUE;

}

else if (map[maxx][miny]==0)

{ m_ptCross.x=maxx;

m_ptCross.y=miny;

if ((FindLine(p1,m_ptCross))&&(FindLine(m_ptCross,p2)))

return TRUE; }

else if (map[minx][miny]==0)

{ m_ptCross.x=minx;

m_ptCross.y=miny;

if ((FindLine(p1,m_ptCross))&&(FindLine(m_ptCross,p2)))

return TRUE; }

else if (map[maxx][maxy]==0)

{ m_ptCross.x=maxx;

m_ptCross.y=maxy;

if ((FindLine(p1,m_ptCross))&&(FindLine(m_ptCross,p2)))

return TRUE; }

}

return false; }

bool CMyLLKDlg::FindTwoConner(CPoint p1, CPoint p2)

{ int i;

CPoint tempPoint1=0;

CPoint tempPoint2=0;

for (i=0;i<MAXY;i++)

{ if (i==p1.y||i==p2.y)

continue;

tempPoint1.x=p1.x;

tempPoint1.y=i;

if (map[tempPoint1.x][tempPoint1.y]==0)

if (FindLine(tempPoint1,p1))

{ tempPoint2.x=p2.x;

tempPoint2.y=tempPoint1.y;

if (map[tempPoint2.x][tempPoint2.y]==0)

if (FindLine(tempPoint2,tempPoint1)&&FindLine(tempPoint2,p2))

return TRUE;

}

}

for (i=0;i<MAXX;i++)

{ if (i==p1.x||i==p2.x)

continue;

tempPoint1.x=i;

tempPoint1.y=p1.y;

if (map[tempPoint1.x][tempPoint1.y]==0)

if (FindLine(tempPoint1,p1))

{ tempPoint2.x=tempPoint1.x;

tempPoint2.y=p2.y;

if (map[tempPoint2.x][tempPoint2.y]==0)

if (FindLine(tempPoint2,tempPoint1)&&FindLine(tempPoint2,p2))

return TRUE;

}

}

return FALSE; }

(11)定时器函数

void CMyLLKDlg::OnTimer(UINT_PTR nIDEvent)

{ m_time--;

if (m_time==0)

{ KillTimer(1);

MessageBox("时间到了,游戏失败!请重新开始!");

m_flag=0;

for (int i=1;i<MAXX-1;i++)

for (int j=1;j<MAXY-1;j++)

map[i][j]=0;

ProcessGame();

}

InvalidateRect(CRect(450,5,750,60));

CDialog::OnTimer(nIDEvent); }

(12)点击"提示一下"按钮响应函数

void CMyLLKDlg::OnHelp()

{ if (m_flag)

{ if (m_NUM)

{ m_NUM--;

if(FindHelp())

ProcessGame();

else

MessageBox("没有可消的成对图片,请按重新排列!”");

}

else

MessageBox("您本局的次提示已用完!");

}

else

MessageBox("您还没选择开始游戏!"); }

bool CMyLLKDlg::FindHelp(void)

{ int x1,x2,y1,y2;

CPoint tempPoint1=0;

CPoint tempPoint2=0;

for (x1=1;x1<MAXX-1;x1++)

for (y1=1;y1<MAXY-1;y1++)

for (x2=1;x2<MAXX-1;x2++)

for (y2=1;y2<MAXY-1;y2++)

{ tempPoint1.x=x1;

tempPoint1.y=y1;

tempPoint2.x=x2;

tempPoint2.y=y2;

if ((map[tempPoint1.x][tempPoint1.y]==0||map[tempPoint2.x][tempPoint2.y]==0)||

(map[tempPoint1.x][tempPoint1.y]!=map[tempPoint2.x][tempPoint2.y])||

(x1==x2&&y1==y2))

continue;

if (FindLine(tempPoint1,tempPoint2)||FindOneConner(tempPoint1,tempPoint2)||

FindTwoConner(tempPoint1,tempPoint2))

{ CLLKButton *pBtn1=(CLLKButton *)m_btnGroup.GetAt((tempPoint1.x-1)*(MAXY-2)+

tempPoint1.y-1);

CLLKButton *pBtn2=(CLLKButton *)m_btnGroup.GetAt((tempPoint2.x-1)*(MAXY-2)+

tempPoint2.y-1);

pBtn1->SetButtonStyle(BS_DEFPUSHBUTTON);

pBtn2->SetButtonStyle(BS_DEFPUSHBUTTON);

return TRUE; }

}

return false; }

(13)点击"重新排列"按钮响应函数

void CMyLLKDlg::OnRerange()//没有可消得,重新排列

{ int x,y;

srand((unsigned int)time(NULL));

if(m_flag)

{ for(int i=MAXX-2;i>0;i--)

for (int j=MAXY-2;j>0;j--)

{ if(map[i][j]==0)

continue;

else

{ do

{ x=rand()%(MAXX-2)+1;

y=rand()%(MAXY-2)+1;

} while (map[x][y]!=0);

map[x][y]=map[i][j];

map[i][j]=0;

}

}

ShowMap(map);

}

else

MessageBox("您还没选择开始游戏!"); }

(14)程序说明以及推出按钮响应函数

void CMyLLKDlg::OnInstruc()

{ CInstrcDlg ins;

ins.DoModal(); }

void CMyLLKDlg::OnExit()

{ KillTimer(1);

OnCancel(); }

五、效果图

6、设计中问题及解决方案

1、提示时,怎样显示提示的两个图片,可以让游戏者看到。

2、当点击"重新排列"后,继续游戏当全部消去后,时间不会停止,也不会提示游戏者 已成功完成游戏。

七、未完成的问题

1、当点击重排后,消去所有图片,时间不会停止,也不会提示"全部消去"

解决方法:

m_remainBtn=(MAXX-2)(MAXY-2)的赋值应该在MAXXMAXY赋值 之后。

2、当点击可以消去的两个图片时,应该用线段显示两图片之间的连线。

本文来源:https://www.2haoxitong.net/k/doc/9b58b75bb8d528ea81c758f5f61fb7360b4c2ba3.html

《QQ头像连连看总结.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式