⋯⋯。G^啊EPROBR^啊⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯.⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯..⋯⋯⋯⋯⋯⋯⋯⋯⋯
智慧珠拼盘游戏开发
江 洪
摘 要:利用VisualC++开发一个基于对话框的智慧珠拼盘游戏,描述了游戏的开发思路,以及
所应用的开发技巧,有一定的知识性和趣味性。
关键词:智慧珠拼盘;C++;对话框
1 前言
智慧珠拼盘游戏由日本专家发明。游戏由一个55个小洞
的正三角形的拼盘,和12种形状各异的小珠组成。使用全部
小珠填满整个拼盘即完成游戏。至少有几百种以上不同的布
局。随着固定的小珠数量逐渐减少,游戏难度逐渐增高。有些
布局可能有一个以上答案。玩此游戏.可以逐步提高判断事物
的能力与速度,适合各年龄层的玩者。
下面将使用VisualC++6.0实现智慧珠拼盘游戏。程序基
于MFC对话框开发,支持鼠标和键盘两种操作方式。程序使
用配置文件保存游戏布局和答案,可由玩者进行设计。
2游戏概述
游戏中使用拼盘形状如图1所示。
图1游戏拼盘图
图2游戏小珠图
拼盘形状为一个正三角形,共有10层,第1层有一个小
洞,第2层有2个小洞,然后每层增加1个小洞,直至第lO
层有lO个小洞。
游戏中使用小珠形状如图2所示。
所有小珠均可以进行360度旋转和翻转变形,以适应不同
的拼盘布局。
游戏界面截图如图3所示。
图3游戏界面围
3开发技巧
本游戏需实现拼盘和小珠的显示.小珠键盘移动和变形、
小珠鼠标移动变形这3项基本的功能。下面分别进行描述。
3.1 拼盘和小珠的显示
voidDrawBoard(void},腼拼盘
{
HPENpenl:
HBRUSHbrushl;
}nti,x.y:
for(i=1:i<=55:i++}
{
if(boards[i一1k=,A’)
{
penl=CreatePen(PS_SOLID,1,RGB(255,0,0}}:
嘏‘_裟翟羯
删一*^Ⅳ
。一;;
。兢
万方数据
brushl=CreateSolidBrush(RGB(255,0,O)):
)
∥以下省略若干行,全部为建立小洞画笔和刷子
if(boards[i一1】-=7.7)
(
penl=CreatePenfPS—SOLlD,1,RGB(128,128,128));
brushl=CreateSoIidBrush(RGB(128,128,128)}:
}
SeIectObject(hdc,penl);
SelectObject(hdc.brushl);
if(i==1}
{
y=30;
x=370;
)
if(i>=2&&i<=3I
{
y=50;
if(i==2)x=350;
if(i==3)x=390;
)
,/以下省略若干行,全部为确定小洞的横坐标和纵坐标
Ellipse(hdc,X,Y,x+30,v十30):
DeleteObject(penl):
DeleteObject(brushl}:
l
}
,厕小珠
voidDrawBall(intnumber,intstartx,intstarty,intradius,intflip)
{
HPENpenl:
HBRUSHbrushl:
,/根据当前小珠号创建画笔和刷子
if(number==1)
{
penl=CreatePen《PS—SOLID,1,RGB(255,0.O)):
brushl=CreateSoIId8fush(RGB《255,0,O)):
}
∥以下省略若干行,全部为建立小珠画笔和刷子
SelectObject(hdc,penl):
SelectObject(hdc,brushl):
//根据小珠号、坐标值、角度、翻转标志画小珠
∥省略若干行,全部为根据小珠号、小珠旋转角度、翻转角度画
//4,珠
if(number==3)
{
if(radius==O}
{
if(flip==0}
{
, Ellipse(hdc,startx,st旧n'V,startx+30.starty+30);
Ellipse(hdc.startx一20,starty+20,startx-20+30,stare+
20+30);
Ellipse(hdc,startx一40,starty+40,startx-40+30,starty+
40+30);
Ellipse(hdc,startx+20,starty+20,startx+20+30,starty+
20+30);
)
jf(flip==l}
{
Ellipse(hdc,startx,starty,startx+30,starry+30);
Ellipse《hdc.startx一20,starty+20,startx-20+30.starty+
20+30);
Ellipse(hdc,startx-40,starty+40,startx-40+30,starty+
40+30);
Ellipse(hdc,startx-20,starry-20.startx-20+30,stare一
20+30);
}
)
if(radius==90)
{
if(flip==0)
{
Ellipse(hdc,startx,stare,startx+30,starry+30);
Ellipse(hdc.startx+20,starry+20,startx+20+30,starty+
20+30);
Ellipse《hdc,startx+40,starty+40,startx+40+30.starty+
40+30);
Ellipse{hdc,startx+20,starty+60,startx+20+30,starty+
60+30);
}
if(flip==1)
{
Ellipse(hdc,startx,starry.startx+30,starry+30);
Ellipse{hdc,startx+20,starty+20,start,,<+20+30,starty+
20+30);
Ellipse(hdc,startx+40,starty+40,startx+40+30,starty+
40+30);
Ellipse(hdc.startx+60,starty+20,startx+60+30,stare+
20+30);
}
}
if(radius==l80)
{
if(flip==0)
{
Ellipse(hdc,startx,stare,startx+30,starty+30);
Ellipse《hdc,startx一20,starty+20,startx-20+30.stare’+
20+30);
Ellipse(hdc,startx-40,starty+40,startx-40+30,stare’+
40+30);
Ellipse(hdc。startx-60,starty+20,startx-60+30,stare’+
20+30);
~一一一一~一~一~~~
一集~密一慧一智
.....一....一第一用~实~一一一一一~一一~一一~一
万方数据
⋯⋯。趴啊EPROGR脯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯
}
ffIflip==1)
{
Ellipse(hdc.startx,starry.startx+30,starty+30);
Ellipse(hdc.startx+20.starty+20.startx+20+30,starty+
20+30);
Ellipse(hdc,startx+40,starty+40,startx+40+30,starry+
40+30);
Ellipse(hdc,startx一20,starty+20,startx一20+30。starty+
20+30);
}
}
if(radius==270)
{
if(flip==0》
t
Ellipse(hdc,startx,starty,startx+30,starty+30);
Ellipse(hdc,startx+20,starty+20,startx+20+30,starty+
20+30);
Ellipse(hdc,startx+40,starty+40,startx+40+30,starty+
40+30)
;nti:
iflpiaying==l&&curnumber>=l&&curnumber<=12)
{
DrawBoard0;腼拼盘
脑所有小珠
for(i=1:i<=12:;++)
{
if(curx[i一111=一l&&cury[i-1]!=一1l
DrawBall(i.curx[i一11.cury[i一1l,curradius[i-1],curflip[i一11):
}
if(curx[curnumber一111=一l&&cury[curnumber-1]!=一1),蜃
//当前选定小珠
{
penl=CreatePen(PS—SOLID,1,RGB(255,255,255}):
brushl:CreateSoIidBrush(RGB{255,255,255));
SelectObject(hdc,penl);
SeIectObjectihdc,brushl);
Etlipselhdc.curx[curnumber一11+7,cuw[curnumber一11+7,
cuD([curnumber一11+7+15。cury【curnumber一1J+7+15》:
DeleteObiect{brushl):
DeIeteObject《pen1}:
Ellipse(hdc,startx+20,starty-20,startx+20+30,starty一}
20+30);
}
iflfiip==1)
{
,
Ellipse(hdc,startx,starty,startx+30,starty+30);
Ellipse(hdc.startx一20,starty+20,startx-20+30,starty+
20+30);
Ellipse(hdc。startx一40。starry+40。startx-40+30。starry+
40+30);
Ellipse(hdc。startx一20。starty+60,startx一20+30,starty+
60+30):
}
}
'
,/省略若干行,全部为根据小珠号、小珠旋转角度、翻转角度画小
|陆
DeIeteobiectfbrushl):
DeleteObject(penl):
}
intCheckGame(void),/判断拼盘是否完成0一来完成1-完成
l
if(GetPixel(hdc,385,45)==RGB(128,128,128)&&boards[0]==
’,’)returnO:
,,省略若干行,全部为根据小洞坐标和颜色值确定是否完成
return1:
l
所有画图代码放在OnPaint函数的else分支中,如下:
HPENpenl:
HBRUSHbrushl;
3.2小珠键盘移动和变形
小珠键盘移动和变形代码在PreTranslateMessage函数中:
HPENpenl:
HBRUSHbrushl:
COLORREFcolor;
imi.found;
if(playing==0}returnO:
if(pMsg一>message==WM—KEYDOWN)/,按下键盘
l
if(cumumber==l}
{
penl:CreatePen(PS—SOLID,1,RGB(255,0,o)):
brushl=CreateSolidBrush(RGB(255。0.O)):
}
∥以下省略若干行,全部为根据当前小珠号创建诬笔和刷子
switch(pMsg->wParam》
{
caseVK_PRIOR://PageUD键设置翻转标志
if(curnumber>=l&&cumumber<=12&&
cuⅨIcurnumber一’】l=一l&&cury[curnumber一1ll=一1}
l
curflip[curnumber一1j=curfIip【cumumber一1】+1:
if(curftip[curnumber一1l==2》curflip[cumumber一1】=O:
l
Invalidate();
UpdateWindow0;
OnPaint0;
break:
万方数据
caseVK_NEXT://PageDown键旋转
if(curnumber>=1&&curnumber<=12&&
curx[curnumber一1】!=一1&&cury[curnumber一1】I=一1}
f
SelectObject(hdc,penl):
SeIectObjec“hdc,brushl):
Ellipse(hdc.curx【curnumber一1l+12,cury[curnumber-
"+12,
curx[curnumber-1l+12+5,cury[curnumber一1】+12+5):
DeleteObject(brush1):
De{eteObject(penl}:
curradius[curnumber一1l=curradius[curnumber一1l+90:
if(curradius[curnumber一1l==360)curradius[curnumber-
1j_O:
if(curradius[curnumber一1l==180&&curnumber==2)cur-
radius[curnumber一1】_0:
}
Invalidate0;
UpdateWindow0;
OnPaint0;
break;
caseVK_TAB:,丌ab键切换小珠
SelectObject(hdc,penl}:
SeIectObject《hdc,brushl):
Ellipse(hdc,curx[curnumber-1l+7,cury[curnumber-1]+7,
curx[curnumber-1】+7+15.cury[curnumber-ll+7+l5):
DeleteObject(brushl}:
DeleteObject(penl):
found=O;
for(i=curnumber+1:i<=12:i++)//向后找
{
if(curx[i一1li=一1&&curyli一1】l=一1)
{
found=l:
curnumber=i;
break;
}
}
if(found==0)
{
for(i=1;i<=cumumber一1:i++)//向前找
{
if(curx[i一1】I=一1&&cury[i一1】l=一1)
f
found=l:
curnumber=i;
break;
}
}
}
if(found==1)
l
penl=CreatePen《PS—SOLID,1,RGB(255,255,255)):
brushl=CreateSoIidBrush(RGB《255,255,255)):
SeIectObject(hdc,penl);
SeIectObject《hdc,brushl):
Ellipse(hdc.cuⅨ[curnumber-1l+7,cury[curnumber-1】+7,
curx[curnumber一1】+7+15,cury[curnumber-1】+7+15):
DeleteObIect{bfush1}:
DeIeteObject(penl):
}
break;
caseVK_LEFT:/,左键左移小珠
if(curnumber>=l&&curnumber<=l2&&
curx[curnumber一1】!=一1&&cury[curnumber-11l=-1)
{
if(curxlcurnumber一1】>100)CUFXfcurnumber-1l=
curx[curnumber一1】-40;
coIor=GetPixeI《hdc.curxfcurnumber-11+40,cury[cur-
number一11):
if(color!=RGB(128,128,128))curx[curnumber-1】+=20:
}
Invalidate0;
UpdateWindow0;
OnPaint0;
break;
caseVK—RIGHT://右键右移小球
,,与左移小珠代码类似,省略
break;
caseVK_UP://上键上移小珠
//与左移小珠代码类似,省略
break;
caseVK_DOWN:∥下键下移小珠
∥与左移小珠代码类似,省略
break;
}
if(ptaying==1)
{
if(CheckGame0==1)
{
AfxMessageBox(‘恭喜通过本关i。):
playing=0;
}
}
}
3.3小珠鼠标移动和变形
移动鼠标代码如下:
intx,y.i,layer;
HCURSORhCursor;
if(playing==0)return;
if《abs《point.X—CUFXlcurnumber-1l}<20&&abs(point.y—cury
lcurnumber-11)<20)
{
一~一~一~一一~一~一
一集~密~慧~智
.....一....一第一用一实~一~一~一~~~~~~~~
万方数据
一⋯..。I;_IIlIEPROGRAM......⋯.....。..⋯...⋯..⋯.......⋯..........⋯.⋯....⋯-.-⋯............---⋯⋯..-⋯--·---.一-....
∥改变鼠标形状
hCursor=::LoadCursor(NULL.MAKEINTRESOURCE
lIDC—SlZEALL)}:
SetClassLong(m—hWnd,GCL_HCURSOR,(LONG)hCursor):
}
if(dragnumber>=l&&dragnumber<=12)
f
,厂调髌鼠标坐标
x=point.×一50;y=point.y-20;
while(1)
{
if(abs(y-cury[dragnumber一11)%20==0)break;
.y++;
}
Iayer=O;
if(y==30)layer=l:
if(y==50)layer=2;
if《y==70}layer_3:
if(y==90)layer=4;
iffy==110)layer=5;
if(y==130)layer=6;
if(y==150)layer=7;
jf(y==170)layer=8;
if(y==190)layer=9;
lf(y==210)layer=lO:
if(x>=90&&x<=650&&layer>=1&&layer<=10)
{
for(i=1:i<=1O:l++}
{
if(boardpos[1ayer-1l[i-1》x}
{
x=boardpos[1ayer-1l[i-1];break;
}
}
}
curx[dragnumber-1j=x;cury[dragnumber-1]=y;
}
放开鼠标左键代码如下:
HCURSORhCursor;
COLORREFcolor;
if(playing==O)return;
,,根据当前坐标颜色设置当前小珠号
coIor=GetPixeI(hdc,point.x,point.yI:
if《color==RG8{255,0,O)&&curx[O】l=-1)curnumber=l:
,,省略若干行,全部为根据当前点颜色值确定当前小珠号
dragnumber=O;
InvalidateO;
UpdateWindowO;
0nPaintO;
//恢复默认鼠标形状
hCursor=::LoadCursor(NULL,MAKEINTRESOURCE(IDC_AR—
f{0W)}:
SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)hCursor);
if(playing==1}
{
if(CheckGameO==1)
{
AfxMessageBox(。恭喜通过本关!。):
playing=O;
}
}
放开鼠标右键代码如下:
COLORREFcolor;
if(playing==O}return;
,,根据当前坐标颜色设置当前小珠号
coIor=GetPixeI《hdc,point.X,point.y):
if(coIor==RGB《255,0,O)&&curx[O】!=-1)curnumber=1:
if《coIor==只GB(O,255,O)&&curx[1l!=-1)curnumber=2;
.f(coIof;=RG8(O,0,255)&&curx【2】!=一1)curnumber=3;
if(coIor==RGB{255.128,O)&&curx[3】l=-1}curnumber=4;
if《color=;RGB(255.O.255)&&curx[4l!=-1)curnumber=5;
if(co}or_=RG8(O.255,255)&&cur)(f5l!=-1)curnumber=6;
If《coIof==RGB(255.128,128)&&curx[6]!=一1}curnumber=7;
if《coIof==RGB《128,255,128}&&cur×【7ll=一1}curnumber=8;
if《color==RGB《128,128,255)&&curx[8】l=一1}curnumber=9;
if《coIor==RGB(255,128,255)&&curx[9】I=一1)cumumber=10:
iflcoIor==RG8(128。0,O)&&curx[10”=-1)curnumber=11:
if(color==RGB(128,O.128)&&curx[11l{=一1}curnumber=12:
if(curnumber>=l&&curnumber<=l2》
{
力『i殳置小珠翻转标志
curftip[curnumber一11=curflip[curnumber-1】+1:
if(curflip[curnumber一1】_=2)curflip[curnumber一1扭O:
Invalidate();
UpdateWindowO;
OnPaintO;
l
按下鼠标左键代码如下:
COLORREFcolor,colorl:
{f(playing==O)return;
dragnumber=O;
colorl=GetPixel(hdc,point.X,point.y):
coIor=GetPlxeI(hdc,point.x+l0,point.y};
//根据当前坐标颜色设置当前小珠号和当前拖动小珠号
if(colorl==RGB(255,255.255)&&color==RGB(255,0,O)&&curx
【Ol!=一1l
{dragnumber=l;curnumber=l:}
//省略若干行,全部为根据当前坐标颜色设置当前小珠号和当前
,/拖动小珠号
双击鼠标左键代码如下:
HPENpenl:
HBRUSHbrushl:
COLORREFcolor;
∥k_裂‰⑧
万方数据
,。。。。。。。。‘。‘。‘。。。‘。。‘。。。。。。‘‘。。‘。。。。。。。。。。’。。。。。。。。‘。。‘。‘。。。。。‘’‘‘‘。
实用第一/智慧密集
if(ptaying==0)return;
coIor=GetPI×eI(hdc.point.X,point.y):
if{coIor==RGB《255.O.0)&&curx[0ji=一1)curnumber=1:
,/省略若干行,全部为根据当前坐标颜色设置当前小珠号
lf(curnumber>=1&&curnumber<=12)
{
if(curnumber==1l
{
penl=CreatePen(PS—SOLlD,1,RGB(255,0,O)):
brushl=CreateSoIidBrush(RGB《255,0,O)):
}
∥省略若干行,全部为根据当前小珠号创建画笔和刷子
SeiectObject(hdc,penlJ;
SelectObject(hdc,brushl):
Ellipse(hdc,curx[curnumber一1l+12.cury[curnumber一1】+12,
curx[curnumber一1】+12+5,cury[curnumber一1l+12+5》:
DeIeteObIect(brush1):
DeIeteObject(penl}:
curradius[curnumber一1l=curradius[curnumber一11+90;
if(curradius[curnumber一1l==360)curradius[curnumber一1】#
O:
if(curradiusIcurnumber一11-=180&&curnumber==2)curra-
dius[curnumber一1】=O:
Invalidate0;
UpdateWindow0;
OnPaint0;
}
4 结语
游戏由玩者用鼠标或键盘进行控制。拼盘布局和答案也可
由玩者设计。
参考文献
【1】裴民,赵栋伟,杨彬.如何使用VisualC++6.0.机械工业
出版社.1999.
(收稿日期:2010-09—13)
÷}{·H·}{·}{·}{-}{·}{·}{·H·}{·}{·}{·H·H·H·H·H·}{·H·}{·}{·H·}{·}{·H·}{·}{·}{·}{·H·H·}{·H·}{·}{·}{·}{·H·H·H·}{·H·H·}{·}{·H·}{·}
(上接第67页)
strcpy(szPort,"80。):
strcpy(szHost,szTmp);
}
return1:
}
结构体_SAVEINFO
了待下载文件的相关
——
URL、目标主机名、端口、相对路径和文件名、本地保存目
录、本地文件名。
typedefstructSAVEINFO{
charszUrl[1024];//URL,即下载链接
charszHost[MAX_PATH];//URL中的目标主机名
charszPort[5];//URL中的端口号
charszName[MAX_PATH];//URL中的文件名
charszPathName[MAX_PATH];
删RL中的相对路径和文件名
charszLocalName[MAX_PATH];//本地保存文件名
charszLocalDir[MAX_PATH];//4太地保存目录
lSAVEINFO;
3.9运行和调试环境
#include。stdafx.h。
#include。popClient.h。
#include"winsock2.h’
#include。stdio.h。
#include。shlobi.h。
#include。commctrl.h。
#include‘shellapi.h。
#pragmacomment(1ib,"ws2_32.1ib。)
#pragmacomment(1ib,'comctl32.1ib。)
#defineWM_RECVWM_USER+I
⑩盏器菇&
#defineWMFILESIZEWM—USER+2
#defineWMFINISHEDWMUSER+3
#defineWMPROGRESSWMUSER+4
#defineWMS丁ATUSWMUSER+5
#defineMAXLOADSTRtNG100
#defineMAX_BUF2048//接收缓冲区
#definePROGRESS~RANGE100∥进度条的最大长度
#defineMAX_URL_LENGTH1024
∥全局变最:
SAVEINFOgsi:
SOCKETg_sConn;//连接服务器的TCP套接字
char。g_pszStatusMsg;//状态消息
HWNDg_hDIg;/尉话框旬柄
HWNOhProgress;//进度条的窗口句柄
intg_Range;//进度条的最大值
HANDLEg_hThread;肝载文件线程的句柄
HWNDghwndNextViewer;//ClipboardViewerChain由
∥本窗口的后继窗口的句柄
以上程序是在WindowsXPSP3平台上。VisualStudio2005
VC++环境下。调试通过,因为Winsock2不支持Unicode,所
以在“属性管理器”中把项目的“字符集”修改为“多字节字
符集”。
4 结语
在分析了HTrPl.1工作原理的基础上,设计了H7I耶文件
下载器的
.并采用WindowsSDK和WindowsSocked编程
方法进行了方案实现,因为采用了较底层的编程接口,使得读
者对TCP、HrI-I'P等相关
工作原理的认识更加深刻。
(收稿日期:2010--09一18)
万方数据
智慧珠拼盘游戏开发
作者: 江洪
作者单位:
刊名: 电脑编程技巧与维护
英文刊名: COMPUTER PROGRAMMING SKILLS & MAINTENANCE
年,卷(期): 2010(21)
参考文献(1条)
1.裴民;赵栋伟;杨彬 如何使用Visual C++6.0 1999
本文链接:http://d.g.wanfangdata.com.cn/Periodical_dnbcjqywh201021017.aspx