连连看游戏设计Word文件下载.docx
《连连看游戏设计Word文件下载.docx》由会员分享,可在线阅读,更多相关《连连看游戏设计Word文件下载.docx(20页珍藏版)》请在冰豆网上搜索。
如果两个图形可以通过0个拐角连通,则从第一个选中的图片一次向右,向下,向左,向上搜索可以和当前选中图片消除的另一图片,当搜索到与之相同的图片时,则与之消去;
图片布局刷新;
如果两个图片之间存在1个拐角可以消去,则广度搜索从当前图片出发,向左,右上下一次寻找一个路径节点(没有图片的点),使得寻找到的路径节点可以与选中的图片一线连通,并且可以与第二次选中的图片一线连通,则可以判断为可消除图片;
图片布局重新刷新;
如果连个图片之间存在两个拐角可以连通,则分为两种情况:
一种是两个图片在矩形区域的最外沿,则通过判断是否存在一条线使得在两待消除的图片周围一个单位,若存在则消去。
二是两图片在矩形区域内部,则在两待消除的图片水平方向和垂直方向上寻找另外两个中间点能使两中间点之间连通,并且其中一个中间点能和待消图片1一线连通,另一中间点能和待消图片2一线连通,如若找到这样的点,则判断两图片能消去,找不到则不能消去。
1.1需求分析
(1)初始化游戏界面
该部分主要由执行窗口创建函数及游戏地图加载函数来实现。
通过数据的初始化及游戏地图资源的加载为用户呈现一个游戏初始的界面。
(2)图片的选择
该功能主要由鼠标来完成。
在OnLButtonDown()事件函数中通过鼠标的点击事件选取所要消除的两个相同图片。
(3)图形的判断与消除
对于第
(2)步所选的两个图片,对其连通性进行判断:
如果两图片直线连通,则相互消去;
如果两图片连接为一个拐点且相通,则相互消去;
如果两图片连接为两个拐点且相通,则相互消去;
否则,不能消去。
(4)判断游戏是否死锁或结束
如果所有的图片全部消去,则提示“游戏结束!
”的信息。
当游戏玩家不可能在消去任意两个图片时,游戏进入死锁状态。
此时提示相关信息。
(5)游戏的提示
当玩家找不到两个可以消去的函数时,可以通过点击提示按钮获取系统帮助,继续游戏。
无具体要求,当玩家第一次点击图片时,对应图片响应点击消息,图片变成红色底片,若第二次点击的图片能和第一次的图片连通,则同时消失,否则选中的图片为红色的底。
1.2系统设计
a.主要组成类:
LLK
LLKDLG类
LLKBUTTON类
OnInitDialog
OnLButtonDown
OnPaint
FindLine
OnClickedStart
FindOneConner
InitMap
FindSide
ShowMap
FindTwoConner
OnClickedTips
OnClickedSwap
IsWin
OnClickedClose
图1
b.构成结构图
图2
1.3调试测试
图3
图4
图5
(1)在设计时没有要求去设计提示次数,所以在设计时没有设计点击提示次数的限制条件,玩家可以一直点击提示。
(2)还有分数是固定的,玩家完成所有图片的连接消除,所得的分数是一致的。
(3)为了提高算法的执行效率,鼠标点击图片的次序不同,可能导致出现本可以消除的一对图片不能消去,但解决方案很简单,就是颠倒鼠标点击的次序。
(4)待消除的两图片在矩形区域内部并且有两个拐角时,为了提高执行效率,附加了一些判断条件,导致代码量增多。
(1)根据实际玩家需求,对系统提示次数加以限制,比如最多可以提示5次之类的具体方案,或者没使用一次提示,则所得分为5分而不是10分。
(2)找一个良好的分数与时间的函数,使得玩家用时少的时候,所得分数相对要高一些。
1.4程序界面
图6
1.5核心程序清单
(1)LLKDLG.cpp中
//在重画函数中添加时间信息,关卡信息和路径线条,通过窗口重绘,来画路径和改变时间
voidCLLKDlg:
:
OnPaint()
{
CPaintDCdc3(this);
CWindowDCdc(this);
CPenlPen(PS_SOLID,2,RGB(222,211,140));
//画笔的样式,宽度,颜色
//设置字体颜色
dc.SelectObject(&
lPen);
//选择画笔
CFontfont;
//字体类
CStringstr;
str.Format(_T("
剩余时间:
%3d秒"
),m_time);
//m_time中存储剩余时间信息
font.CreatePointFont(100,_T("
宋体"
));
//请求的的大小,取其1/10为其字体大小,这个函数提供了一种简单的方法来创建指定字体类型和字体大小
//设置字体
font);
dc.SetTextColor(RGB(222,211,140));
dc.SetBkColor(TRANSPARENT);
dc.TextOut(10,40,str);
//显示时间
//显示分数
font.DeleteObject();
dc.SetBkColor(RGB(201,186,131));
/*m_score=m_time-30;
*/
分数:
%d"
),m_score);
dc.SetTextColor(RGB(255,255,255));
dc.TextOut(610,35,str);
CWindowDCdc2(this);
CPenpen(PS_SOLID,3,RGB(161,23,21));
dc2.SelectObject(pen);
//画出路径
if(LLKButton:
ms_firstBtn!
=NULL&
&
LLKButton:
ms_secondBtn!
=NULL)
{
//设置计时器,0.2秒后擦除路径线条
SetTimer(2,100,NULL);
pt1.x=LLKButton:
ms_firstBtn->
m_location.y*50+45;
pt1.y=LLKButton:
m_location.x*50+70;
pt2.x=LLKButton:
ms_secondBtn->
pt2.y=LLKButton:
pt3.x=LLKButton:
ms_ptCross1.y*50+45;
pt3.y=LLKButton:
ms_ptCross1.x*50+70;
pt4.x=LLKButton:
ms_ptCross2.y*50+45;
pt4.y=LLKButton:
ms_ptCross2.x*50+70;
//无拐点
if(LLKButton:
ms_ptCross1.x==-1)
{
dc2.MoveTo(pt1);
dc2.LineTo(pt2);
}
//一个拐点
elseif(LLKButton:
ms_ptCross2.x==-1)
dc2.LineTo(pt3);
dc2.MoveTo(pt3);
//两个拐点
else
dc2.LineTo(pt4);
dc2.MoveTo(pt4);
}
}
//初始化地图
InitMap(intmap[][MAXY])
inti,j;
intx,y;
inttype;
//随机数种子
srand((unsignedint)time(NULL));
//srand函数是随机数发生器的初始化函数。
原型:
voidsrand(unsignedintseed);
为了防止随机数每次重复,常常使用系统时间来初始化,即使用time函数来获得系统时间,它的返回值为从00:
00:
00GMT,January1,1970到现在所持续的秒数,然后将time_t型数据转化为(unsigned)型再传给srand函数,
//map值表示图片类型,0表示没有图片
for(i=0;
i<
MAXX;
i++)
for(j=0;
j<
MAXY;
j++)
map[i][j]=0;
}
//map的最外层空出来,不放置图片
for(i=1;
MAXX-1;
for(j=1;
MAXY-1;
if(map[i][j]!
=0)
continue;
else
{
//保证了图片成对出现
type=rand()%m_typeNum;
//图片种类
map[i][j]=type+1;
do
{
x=rand()%(MAXX-2)+1;
y=rand()%(MAXY-2)+1;
}
while(map[x][y]);
map[x][y]=type+1;
}
}
//根据map构造按钮
ShowMap(intmap[][MAXY])
inti,j;
CPointp;
CStringstr=_T("
"
);
//清除原有按钮
i<
m_btnGroup.GetSize();
i++)
delete(LLKButton*)m_btnGroup.GetAt(i);
m_btnGroup.RemoveAll();
//删除所有btn组
//添加新按钮
=MAXX-2;
j<
=MAXY-2;
j++)
p.x=i;
p.y=j;
//将按钮放入m_btnGroup指针数组中
m_btnGroup.Add(newLLKButton(map[i][j],p));
//显示按钮
for(i=0;
(MAXX-2)*(MAXY-2);
LLKButton*btn=(LLKButton*)m_btnGroup.GetAt(i);
//构造按钮的大小和位置
btn->
Create(str,WS_CHILD|BS_BITMAP|WS_VISIBLE,
CRect(70+(i%(MAXY-2))*50,70+(i/(MAXY-2))*50,
120+(i%(MAXY-2))*50,120+(i/(MAXY-2))*50),this,
IDC_BLOCK+i);
if(btn->
m_ID)//如果为0则不显示
//尽量用绝对路径
str.Format(_T("
res\\%d.bmp"
),btn->
m_ID);
HBITMAPm_fkBmp=(HBITMAP):
LoadImage//VC中显示bmp要用到CBitmap类
(AfxGetInstanceHandle(),
str,IMAGE_BITMAP,0,0,
LR_CREATEDIBSECTION|LR_LOADFROMFILE);
//加载图片
if(m_fkBmp==NULL)
if(MessageBox(_T("
缺少图片资源!
"
),_T("
错误"
),
MB_ICONERROR|MB_OK)==IDOK)
{
CDialog:
OnCancel();
return;
}
btn->
SetBitmap(m_fkBmp);
ShowWindow(SW_SHOW);
ShowWindow(SW_HIDE);
//是否通关了
BOOLCLLKDlg:
IsWin(void)
//时间结束,没有过关
if(m_time==0)
KillTimer
(1);
MessageBox(_T("
GameOver!
),_T("
时间结束"
m_time=30;
//清除桌面的按钮
for(inti=0;
delete(LLKButton*)m_btnGroup.GetAt(i);
m_btnGroup.RemoveAll();
returnFALSE;
for(inti=0;
i<
MAXX;
for(intj=0;
j<
MAXY;
returnFALSE;
//过关后停止计时
KillTimer
(1);
恭喜你,已经通关"
胜利"
m_score=m_time-30;
returnTRUE;
CBUTTON.cpp类
//两按钮在同一条直线上
BOOLLLKButton:
FindLine(CPointp1,CPointp2)
intmax,min;
inti;
//在同一行
if((p1.x)==(p2.x))
max=(p1.y>
p2.y)?
p1.y:
p2.y;
min=(p1.y<
if(max==min+1)//相邻的两个格子
returnTRUE;
for(i=min+1;
max;
if(parent->
map[p1.x][i]!
//在同一列
if((p1.y)==(p2.y))
max=(p1.x>
p2.x)?
p1.x:
p2.x;
min=(p1.x<
if(max==min+1)
//相邻的两个格子
map[i][p1.y]!
=0)
returnFALSE;
//有一个拐点的路径
FindOneConner(CPointp1,CPointp2)
intmaxx,maxy,minx,miny;
maxx=(p1.x>
maxy=(p1.y>
minx=(p1.x<
miny=(p1.y<
//4个点分别进行判断,看能否找到到两个目标点的直线路径
if(parent->
map[minx][maxy]==0)
ms_ptCross1.x=minx;
ms_ptCross1.y=maxy;
if((FindLine(p1,ms_ptCross1))&
(FindLine(ms_ptCross1,p2)))
map[minx][miny]==0)
ms_ptCross1.y=miny;
if((FindLine(p1,ms_ptCross1))&
map[maxx][miny]==0)
ms_ptCross1.x=maxx;
map[maxx][maxy]==0)
FindSide(CPointp1,CPointp2)
BOOLline=TRUE;
BOOLcol=TRUE;
for(i=min;
=max;
i++)//上侧
map[p1.x-1][i]!
line=FALSE;
break;
if(line)
ms_ptCross1.x=p1.x-1;
ms_ptCross1.y=p1.y;
ms_ptCross2.x=p1.x-1;
ms_ptCross2.y=p2.y;
line=TRUE;
map[p1.x+1][i]!
=0)//下侧
ms_ptCross1.x=p1.x+1;
ms_ptCross2.x=p1.x+1;
else
line=FALSE;
map[i][p1.y-1]!
=0)//左侧
col=FALSE;
if(col)
ms_ptCross1.x=p1.x;
ms_ptCross1.y=p1.y-1;
ms_ptCross2.x=p2.x;
ms_ptCross2.y=p2.y-1;
col=TRUE;
map[i][p1.y+1]!
=0)//右侧
ms_ptCross1.y=p1.y+1;
ms_ptCross2.y=p2.y+1;
col=FALSE;
if(line||col)