今天的程序讲课,开始。
前面几讲,涉及程序框架、地图文件、叉子的摆动、旋转拉伸,这几方面都可以归纳为基本数据处理,今天讲“交互”,很简单,判断叉子抓到物品,当拉回后,增加金钱数量。核心是碰撞检测。
网上的这个游戏是FLASH作的,FLASH的碰撞检测就一个函数,即可实现各式各样的图形检测。VC中,就用自己动手。最初的想法,是把叉子看成一个圆形,各种矿石也看成圆形,做两个圆形的检测,只要检测圆心距离就可以了。看起来很好,我还是用了另外一个方法,叉子口的连线是一个线段,矿石看成圆形,检测线段和圆是否相交。代码如下:
{
int i;
int j;
int x0,y0; // 中点
int tempx,tempy;
int xoff,yoff;
// 将爪子边上的直线5等分,依次取点比较
int point[] = { 0 , 2 , 4 , - 2 , - 4 };
if (iCatchId !=- 1 )
{
return 0 ; // 当前已经获得了物品
}
xoff = 8 * cos( 10 * iangle * 1.57 / 90 );
yoff = 8 * sin( 10 * iangle * 1.57 / 90 );
x0 = x + 8 * xoff; // 中点坐标
y0 = y + 8 * yoff;
for (i = 0 ;i < iObjectNum;i ++ )
{
// 如果当前物品已经取走,继续判断下一个
if ( 0 == objectarray[i].id)
continue ;
for (j = 0 ;j < 5 ;j ++ )
{
tempx = x0 + point[j] * yoff;
tempy = y0 - point[j] * xoff;
if (CmpDistance(objectarray[i].x + objecthit[objectarray[i].id - 1 ].x,
objectarray[i].y + objecthit[objectarray[i].id - 1 ].y,
tempx,tempy,
objecthit[objectarray[i].id - 1 ].id))
{
iCatchId = i;
return 1 ;
}
}
}
return 0 ;
}
是不是不像线段和圆的判断?这不是严格的数学检测,我只取了线段的5个等分点,然后判断各点和矿石的距离是否小于矿石的半径。这个计算过程通过一个宏和一个函数实现:
int CmpDistance( int x, int y, int x2, int y2, int l)
{
if (DISTANCE(x,y,x2,y2) <= l * l)
{
return 1 ;
}
return 0 ;
}
有了数学模型,那么,矿石的“圆心”和“半径”怎样获得呢?需要设置一个数组:
//各个物体的检测半径,检测圆心坐标(偏移量)
GAMEOBJECT temp[]={
{14,14,14},
{25,25,25},
{30,30,30},
{23,23,23},
{14,14,14}
};
这是半径、圆心坐标(相对于图形左上角的偏移量)。碰撞检测完成。
矿石的移动
需要把叉子移动的状态、代码,赋予 各个矿石吗?不需要。只要在WM_TIMER消息中,根据叉子的坐标刷新物体的坐标即可。代码为:
void GAMEMAP::MoveObject( int x, int y, int iangle)
{
if ( - 1 == iCatchId)
return ;
objectarray[iCatchId].x = x + 20 * cos(iangle * 10 * 1.59 / 90 );
objectarray[iCatchId].y = y + 20 * sin(iangle * 10 * 1.59 / 90 );
if (y <= 58 )
{
// 增加钱币
iMoneyNow += object_value[objectarray[iCatchId].id - 1 ];
// 一个物品拉到目的地
objectarray[iCatchId].id = 0 ;
iCatchId =- 1 ;
}
}
拉回矿石,增加金钱
这个小游戏核心的逻辑就是“拉回矿石,增加金钱”。如同上方的代码,当叉子的坐标小于58(初始的纵坐标),认为拉回了矿石,金钱增加。同时把物品数组objectarray的ID域清零,即从画面中消除了该物品。
各种物品的金钱值放在一维数组中: int tempvalue[]={50,150,500,15,600};
至此,游戏的主要功能就完成了。
附加功能:道具使用
提供了两种道具:炮和药水。点击“炮”,增加炮的数量;点击“药水”,设置叉子的拉回速度。代码为:
{
iMoneyNow -= money;
if (iMoneyNow < 0 )
{
iMoneyNow = 0 ;
}
switch (iequip)
{
case 0 :
// 增加炮的数量
iFireNum ++ ;
break ;
case 1 :
// 增加拉动速度
c.iSpeedMore = 2 ;
break ;
}
}
炮的使用也很简单,在用户按“上”时,清除当前抓到的物品:代码为:
{
switch (iKey)
{
case VK_UP:
if (iFireNum > 0 && iCatchId >= 0 )
{
iFireNum -- ;
bBombAni.SetAni(objectarray[iCatchId].x,objectarray[iCatchId].y);
// 一个物销毁
objectarray[iCatchId].id = 0 ;
iCatchId =- 1 ;
}
break ;
}
}
至此,所有的交互功能已全部介绍完,游戏制作完成。还有几个部分,像按钮、道具选择界面、动画播放,定时器。概括起来是两项:位图操作、时间控制,应该有很大的优化空间,我就不介绍了。欢迎参考原工程“挖金子VC版源码”(在CSDN下载频道)。
谢谢!