C++语言课程设计一迷你高尔夫
一、实验内容
玩家通过按下键盘上的上下左右方向键控制球的移动,使其最终到达出口则游戏通关。
要求如下:
1、游戏分成3关,第一关、第二关、第三关界面图如下:
第一关
第二关
第三关
2、启动游戏进入第一关,胜利后进入第二关,如果第三关通关,则游戏重新回到第一关。
3、游戏玩法是通关控制键盘上的上下左右方向键控制球的运动,单击方向键,则球获得一个向该方向直线运动的速度。如果球遇到方块,则球停止运动,如果遇到黑洞,则游戏结束,重新开始该游戏,遇到出口则通关。
4、球静止状态下会有箭头指示球可以运动的方向,运动状态下则箭头消失。如果球运动出世界边界,则游戏结束,重新回到该游戏。
二、实验指南
实验一
开始实验
【实验任务】
步骤一、打开FunCode,创建一个的C++语言项目;
步骤二、导入GolfGame场景。
【实验思路】
按实验指导完成。
【实验指导】
1、打开FunCode,点击“项目”菜单,选择“创建C++工程”
注意:工程名名称要求字母开头,只能包含字母和数字,且名字中间不能有空格。
2、点击菜单“项目”中的“导入地图模块”,如图一。跳出一个对话框,选中“GolfGame”模板,点击“导入到工程”按钮,如图二。
图
一
图
二
3、导入成功后的,界面如下图所示:
地图不仅包括界面设计,还包括该游戏可能要用到的其他精灵。添加到“场景”中的精灵,都已经取好名称,并根据程序要求设置好中心点、链接点等,学生只需要直接编程就可以。
实验二
游戏关卡初始化
【实验内容】
步骤一、关卡地图初始化
步骤二、清除上一关卡数据
步骤三、根据当前关卡,选择关卡数据
【实验思路】
游戏开始的时候首先要清除上一关的游戏数据,即将上一关创建的精灵从地图中删掉。
将游戏地图分成12*12的方格界面,游戏总共分成三关,因此我们需要用三个二维数组m_iLevelData1[GRID_COUNT][GRID_COUNT]
m_iLevelData2[GRID_COUNT][GRID_COUNT]
m_iLevelData3[GRID_COUNT][GRID_COUNT]
(其中GRID_COUNT的值为12)
来存放这三关的数据即可。二维数组中0表示该位置不创建精灵,否则根据不同的值创建不同精灵,RIGID_BLOCK(值为1)表示创建一个方块精灵,BLACK_HOLE(值为2)表示创建一个黑洞精灵,GOLF_EXIT(值为3)表示创建一个出口精灵。每次把代表该关卡的二维数组的数据拷贝到存储当前关卡m_iGridData的二维数组中。
【实验指导】
1、进入LessonX.h的CGameMain类中,添加以下成员变量的声明:
static
const
float
m_fGridStartX
;
//
第一块方块的起始坐标
=
-(GRID_COUNT
*
g_fGridSize
*
0.5
g_fGridSize
/
2)
static
const
float
m_fGridStartY
;
static
const
float
m_fGridSize;
//
每块的大小,包括球、出口等都是此大小
int
m_iRigidBlockCount;
//
本关卡创建的阻挡物方块数量
int
m_iBlackHoleCount
;
//
本关卡创建的黑洞数量
int
m_iGolfExitCount;
//
本关卡创建的出口的数量
int
m_iCurLevel;
//
当前关卡
int
m_iMoveState
;
//
控制球的移动状态:0当前静止,可以移动,1、2、3、4:代表上下左右4个方向移动中,按键无响应
int
m_iGridData[GRID_COUNT][GRID_COUNT];
//
二维数组,存储当
前关卡N*N的矩阵方块信息
static
const
int
m_iLevelData1[GRID_COUNT][GRID_COUNT]
;
static
const
int
m_iLevelData2[GRID_COUNT][GRID_COUNT]
;
static
const
int
m_iLevelData3[GRID_COUNT][GRID_COUNT]
;
vector
m_vRigidBlock;
//阻挡物精灵向量数组
vector
m_vBlackHole;
//黑洞精灵向量数组
vector
m_vGolfExit;
//出口精灵向量数组
int
m_iControlStartX;
//控制球的初始X坐标,根据关卡数据自行指定
int
m_iControlStartY;
//球的初始Y坐标
2、进入LessonX.h中在头文件声明的后面添加下面的宏定义代码:
#define
GRID_COUNT
//
N
*
N的矩阵方块,一个N的大小
#define
MAX_LEVEL
//
最大关卡数量。如果要增加关卡,请先修改此值
#define
RIGID_BLOCK
//
以下3个分别为方块阻挡物、黑洞、出口的值
#define
BLACK_HOLE
#define
GOLF_EXIT33、进入LessonX.cpp中添加上面的成员变量的初始化:
1)
在构造函数中把m_iGameState的值由0改为1:
m_iGameState
=
1;
2)
在构造函数中添加下面代码:
m_iRigidBlockCount
=
0;
//
本关卡创建的阻挡物方块数量
m_iBlackHoleCount
=
0;
//
本关卡创建的黑洞数量
m_iGolfExitCount
=
0;
m_iCurLevel
=
1;
m_iControlStartX
=
0;
//球的初始X坐标
m_iControlStartY
=
0;
//球的初始Y坐标
3)
对于const类型的成员变量,我们需要在函数外面单独进行初始化,在文件最后面添加如下代码:
const
float
CGameMain::m_fGridStartX
=-27.5f;
const
float
CGameMain::m_fGridStartY
=-27.5f;
const
float
CGameMain::m_fGridSize
=5.f;
const
int
CGameMain::m_iLevelData1[GRID_COUNT][GRID_COUNT]
=
{
{0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,0,0,0},{0,0,0,RIGID_BLOCK,0,0,0,0,RIGID_BLOCK,0,0,0},{0,0,0,RIGID_BLOCK,0,0,0,0,RIGID_BLOCK,0,0,0},{0,0,0,RIGID_BLOCK,0,0,0,0,BLACK_HOLE,0,0,0},{0,0,0,0,0,0,0,GOLF_EXIT,RIGID_BLOCK,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0}
};
const
int
CGameMain::m_iLevelData2[GRID_COUNT][GRID_COUNT]={
{0,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,0,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,0,0,0,0,0,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,0,0,0,0,0,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,0,0,0,0,0,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,0,0,0,0,0,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,0,0,0,0,0,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,0,0,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,0,0,RIGID_BLOCK,0,0,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,0,0,0,GOLF_EXIT,RIGID_BLOCK,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,0,0,0,0,0,0,0,0,0},{0,RIGID_BLOCK,0,0,0,0,0,0,0,0,RIGID_BLOCK,0},{0,RIGID_BLOCK,0,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,0,RIGID_BLOCK,0}
};
const
int
CGameMain::m_iLevelData3[GRID_COUNT][GRID_COUNT]={
{0,0,0,0,0,0,0,0,RIGID_BLOCK,RIGID_BLOCK,0,0},{0,0,RIGID_BLOCK,RIGID_BLOCK,RIGID_BLOCK,0,0,0,0,0,0,RIGID_BLOCK},{RIGID_BLOCK,0,0,0,0,0,0,0,0,0,0,RIGID_BLOCK},{0,0,0,0,0,0,0,0,0,0,0,RIGID_BLOCK},{0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,GOLF_EXIT,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,RIGID_BLOCK,RIGID_BLOCK,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,RIGID_BLOCK,0},{0,0,0,RIGID_BLOCK,0,0,0,0,0,0,RIGID_BLOCK,0},{0,0,0,0,BLACK_HOLE,RIGID_BLOCK,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0}
};
二维数组中0表示该位置不创建精灵,否则根据不同的值创建不同精灵,RIGID_BLOCK(值为1)表示创建一个方块精灵,BLACK_HOLE(值为2)表示创建一个黑洞精灵,GOLF_EXIT(值为3)表示创建一个出口精灵。
4)
进入GameInit函数里面,将球的运动状态初始化为静止,添加下面代码:
m_iMoveState=0;
4、游戏初始化的时候,首先我们需要将前边添加的精灵全部删除掉,因此需要自定义的创建清除所有精灵函数ClearAllSprite()来实现这个功能。
1)
进入LessonX.h文件的CGameMain类中添加该函数的声明:
void
ClearAllSprite();
2)
在LessonX.cpp最后面添加该函数的定义:
void
CGameMain::
ClearAllSprite()
{
}
3)
再使用3个循环,分别将上一关卡创建的3种精灵删除掉。在上边定义的函数中添加如下代码:
int
iLoop
=
0;
for(iLoop
=
0;
iLoop
m_vRigidBlock.size();
iLoop++)
{
m_vRigidBlock[iLoop]->DeleteSprite();
}
for(iLoop
=
0;
iLoop
m_vBlackHole.size();
iLoop++)
{
m_vBlackHole[iLoop]->DeleteSprite();
}
for(iLoop
=
0;
iLoop
m_vGolfExit.size();
iLoop++)
{
m_vGolfExit[iLoop]->DeleteSprite();
}
其中m_vRigidBlock、m_vBlackHole、m_vGolfExit是存储三种精灵的向量数组,每一个循环都遍历一遍向量数组并调用数组中每个精灵的DeleteSprite函数即可。
m_vRigidBlock.size()、m_vBlackHole.size()、m_vGolfExit.size()表示每种精灵的总数。
4)
最后在GameInit()中添加调用此函数的代码:
ClearAllSprite();
5、在GameInit()中,我们也需要对关卡进行选择初始化。因此我们需要自定义一个初始化关卡函数InitLevel
()来实现这个功能。
1)
进入LessonX.h文件的CGameMain类中添加该函数的声明:
void
InitLevel();
2)
在LessonX.cpp最后面添加该函数的定义:
void
CGameMain::
InitLevel()
{
}
3)
初始化关卡,要根据当前关卡,选择关卡的数据,即将代表关卡的二维数组中的数据拷贝到m_iGridData中,同时设置控制球在每个数组中的起始位置。首先把需要的数据初始化为0,代码如下:
//
总数置0,重新创建
m_iRigidBlockCount
=
0;
m_iBlackHoleCount
=
0;
m_iGolfExitCount
=
0;
4)
选择关卡我们使用了switch-case结构,程序通过判断switch中的参数进入到不同的case中去,每个case就是一种情况的实现。代码如下:
//
根据当前关卡,选择关卡数据
switch(m_iCurLevel)
{
case
2:
{
m_iControlStartX
=
5;
m_iControlStartY
=
9;
memcpy(m_iGridData,m_iLevelData2,sizeof(int)
*
GRID_COUNT
*
GRID_COUNT);
}
break;
case
3:
{
m_iControlStartX
=
3;
m_iControlStartY
=
6;
memcpy(m_iGridData,m_iLevelData3,sizeof(int)
*
GRID_COUNT
*
GRID_COUNT);
}
break;
//
Level1
或者g_iCurLevel错误
case
1:
default:
{
m_iControlStartX
=
5;
m_iControlStartY
=
6;
memcpy(m_iGridData,m_iLevelData1,sizeof(int)
*
GRID_COUNT
*
GRID_COUNT);
}
break;
};
memcpy函数作用是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。因为二维数组在内存中的存放方式是连续的,因此我们将源地址拷贝给m_iGridData的起始地址之后,系统后自动根据m_iGridData的下标来找到正确的值。
5)
最后在GameInit()中添加调用此函数的代码:
InitLevel();
至此,本实验结束。
实验三
初始化游戏精灵
【实验内容】
步骤一、创建精灵
步骤二、初始化精灵位置
【实验思路】
遍历二维数组m_iGridData,根据数组值生成对应的精灵实例:值为0的时候不用创建,需要创建的精灵名字前缀为(按照宏定义的1,2,3顺序):RigidBlock,BlackHole,GolfExit。每创建一种精灵,将其总数加1
:m_iRigidBlockCount,m_iBlackHoleCount,m_iGolfExitCount。
【实验指导】
1、进入LessonX.h,CGameMain类中添加下面成员变量的声明:
CSprite*
m_pControlBall;
//控制球精灵
CSprite*
m_pGolfArrow;
//指示箭头精灵
在LessonX.cpp中CGameMain类在构造函数里面添加上面成员变量的初始化:
m_pControlBall
=
new
CSprite(“ControlBall“);
m_pGolfArrow
=
new
CSprite(“GolfArrow“);
2、创建精灵之后需要将精灵移到特定位置,因此我们需要定义一个自定义的函数MoveSpriteToBlock来实现这个功能。
6)
进入LessonX.h中添加该函数的声明:
void
MoveSpriteToBlock(CSprite*
tmpSprite,const
int
iIndexX,const
int
iIndexY);
7)
在LessonX.cpp最后面添加该函数的定义:
void
CGameMain::MoveSpriteToBlock(CSprite*
tmpSprite,const
int
iIndexX,const
int
iIndexY)
{
}
8)
传入该函数的是精灵实体以及x,y坐标参数。再通过SetSpritePosition函数设置精灵位置,在该函数里面添加如下代码:
float
fPosX
=
m_fGridStartX
+
iIndexX
*
m_fGridSize;
float
fPosY
=
m_fGridStartY
+
iIndexY
*
m_fGridSize;
tmpSprite->SetSpritePosition(fPosX,fPosY);
3、这里定义一个函数CreateAllSprite()来创建控制球、方块精灵、出口精灵和黑洞精灵。然后在函数内部添加代码创建精灵。
原理是通过两个for循环来,判断m_iGridData的值,如果为0,则不创建,如果为RIGID_BLOCK则创建一个方块精灵,为
BLACK_HOLE则创建一个黑洞精灵,为GOLF_EXIT则创建一个出口精灵。由于我们预先在地图中摆放了三个模板精灵,因此只需要使用CloneSprite函数即可创建新的精灵。然后再调用MoveSpriteToBlock函数将精灵移动到指定位置。最后每创建一个实现精灵,将它添加到相应的精灵向量数组中。
1)
进入LessonX.h文件的CGameMain类中添加该函数的声明:
void
CreateAllSprite();
2)
在LessonX.cpp最后面添加该函数的定义:
void
CGameMain::
CreateAllSprite()
{
}
3)
在定义汗的函数中添加变量声明:
int
iLoopX
=
0,iLoopY
=
0;
CSprite*
tmpSprite;
char
*szName
=
NULL;
4)
实现两个for循环:
for(iLoopY
=
0;
iLoopY
GRID_COUNT;
iLoopY++)
{
for(int
iLoopX
=
0;
iLoopX
GRID_COUNT;
iLoopX++)
{
}
}
5)
在里面的循环添加判断代码:
如果是0,则不创建精灵,continue表示跳出本次循环,继续下一个循环。
if(0
==
m_iGridData[iLoopY][iLoopX])
continue;
如果是方块,则创建方块精灵:
if(RIGID_BLOCK
==
m_iGridData[iLoopY][iLoopX])
{
szName
=
CSystem::MakeSpriteName(“RigidBlock“,m_iRigidBlockCount);
tmpSprite=new
CSprite(szName);
tmpSprite->CloneSprite(“RigidBlockTemplate“);
MoveSpriteToBlock(tmpSprite,iLoopX,iLoopY);
m_vRigidBlock.push_back(tmpSprite);
m_iRigidBlockCount++;
}
如果是黑洞,则创建黑洞精灵:
else
if(BLACK_HOLE
==
m_iGridData[iLoopY][iLoopX])
{
szName
=
CSystem::MakeSpriteName(“BlackHole“,m_iBlackHoleCount);
tmpSprite=new
CSprite(szName);
tmpSprite->CloneSprite(“BlackHoleTemplate“);
MoveSpriteToBlock(tmpSprite,iLoopX,iLoopY);
m_vBlackHole.push_back(tmpSprite);
m_iBlackHoleCount++;
}
如果是出口,则创建出口精灵:
else
if(GOLF_EXIT
==
m_iGridData[iLoopY][iLoopX])
{
szName
=
CSystem::MakeSpriteName(“GolfExit“,m_iGolfExitCount);
tmpSprite=new
CSprite(szName);
tmpSprite->CloneSprite(“GolfExitTemplate“);
MoveSpriteToBlock(tmpSprite,iLoopX,iLoopY);
m_vGolfExit.push_back(tmpSprite);
m_iGolfExitCount++;
}
6)
将控制球和指示箭头摆放到初始位置,此时球静止,因此指示箭头可见。在上面的两个循环后面添加下面的代码:
m_pControlBall->SetSpriteLinearVelocity(0.f,0.f);
MoveSpriteToBlock(m_pControlBall,m_iControlStartX,m_iControlStartY);
MoveSpriteToBlock(m_pGolfArrow,m_iControlStartX,m_iControlStartY);
m_pGolfArrow->SetSpriteVisible(1);
7)
最后在GameInit()中调用此函数:
CreateAllSprite();
至此,本实验结束。
实验四
移动球
【实验内容】
步骤一、响应键盘按键按下消息
步骤二、球精灵坐标转换为二维格子数组索引
步骤三、判断移动方向,使球获取速度
【实验思路】
首先响应系统的按键消息函数,然后获取精灵坐标,并将其转换为二维格子中的坐标,判断其旁边的格子是否是方块,如果不是则给球一个移动的速度。
【实验指导】
1、进入LessonX.h中,添加我们自定义的键盘消息处理函数OnKeyDown的声明:
void
OnKeyDown(const
int
iKey,const
int
iAltPress,const
int
iShiftPress,const
int
iCtrlPress);
2、在LessonX.cpp中添加该函数的定义:
void
CGameMain::OnKeyDown(const
int
iKey,const
int
iAltPress,const
int
iShiftPress,const
int
iCtrlPress)
{
}
3、首先判断游戏状态,只有在游戏中已经可以移动状态才响应按键,在上面函数中添加下面的代码:
if(2
!=
m_iGameState
||
0
!=
m_iMoveState)
return;
4、获取控制球精灵坐标转换到二维格子数组索引,这里我们需要定义两个函数SpritePosXToIndexX和SpritePosXToIndexY分别处理精灵坐标转换为二维格子的X索引和Y索引:
1)
进入LessonX.h中添加上面两个函数的声明:
int
SpritePosXToIndexX(const
float
fPosX);
int
SpritePosYToIndexY(const
float
fPosY);
2)
进入LessonX.cpp中添加SpritePosXToIndexX的定义:
int
CGameMain::
SpritePosXToIndexX
(const
float
fPosX)
{
}
3)
首先得到左右边界的坐标值。m_fGridStartX是在方块的中心,所以需要减去半个方块的宽度才是左边边界。在SpritePosXToIndexX函数定义中添加下面的代码:
const
float
fLeftSide
=
m_fGridStartX
m_fGridSize
/
2.f;
const
float
fRightSide
=
fLeftSide
+
m_fGridSize
*
GRID_COUNT;
4)
最后需要判断坐标是否出了左右边界,如果没有则返回X索引值。在上面的函数里面添加下面的判断代码:
if(fPosX
fLeftSide
||
fPosX
fRightSide)
return
-1;
int
iIndexX
=
(int)((fPosX
fLeftSide)
/
m_fGridSize);
return
iIndexX;
5)
在LessonX.cpp中添加SpritePosYToIndexY函数的定义:
int
CGameMain::SpritePosYToIndexY(const
float
fPosY)
{
}
6)
首先获取上下边界坐标值。m_fGridStartY是在方块的中心,所以需要减去半个方块的宽度才是上边边界。在上面的函数定义中添加下面的代码:
const
float
fTopSide
=
m_fGridStartY
m_fGridSize
/
2.f;
const
float
fBottomSide
=
fTopSide
+
m_fGridSize
*
GRID_COUNT;
7)
最后判断是否超过了上下边界,没有则返回Y索引值:
if(fPosY
fTopSide
||
fPosY
fBottomSide)
return
-1;
int
iIndexY
=
(int)((fPosY
fTopSide)
/
m_fGridSize);
return
iIndexY;
5、有了上面的两个函数,我们就可以将控制球精灵坐标转换到二维格子数组索引,并判断坐标是否超出边界,在OnKeyDown函数中添加下面的代码:
float
fPosX
=
m_pControlBall->GetSpritePositionX();
float
fPosY
=
m_pControlBall->GetSpritePositionY();
int
iIndexX
=
SpritePosXToIndexX(fPosX);
int
iIndexY
=
SpritePosYToIndexY(fPosY);
if(iIndexX
0
||
iIndexX
>=
GRID_COUNT
||
iIndexY
0
||
iIndexY
>=
GRID_COUNT)
return;
6、根据上下左右方向键,先判断控制球旁边是否是方块,如果是方块则不能移动。不是方块,则给予控制球一个速度。使用iIndexX,iIndexY的时候,注意要判断是否是边缘的索引,如果不判断就进行加1减1,访问数组会造成下标溢出。即如果要判断左边是否是方块阻挡,则索引值为
IndexX
。此时必须先判断iIndexX大于0,才能减一。如果iIndexX为0,代表直接可以移动。
1)
如果是按下向上方向键:
if(KEY_UP
==
iKey)
{
if(iIndexY
0
&&
RIGID_BLOCK
==
m_iGridData[iIndexY
1][iIndexX])
return;
//
给予控制球一个方向速度,并设置移动状态、隐藏指示箭头
m_iMoveState
=
1;
m_pControlBall->SetSpriteLinearVelocityY(-30.f);
m_pGolfArrow->SetSpriteVisible(0);
}
2)
如果是按下向下方向键:
else
if(KEY_DOWN
==
iKey)
{
if(iIndexY
GRID_COUNT
&&
RIGID_BLOCK
==
m_iGridData[iIndexY
+
1][iIndexX])
return;
//
给予控制球一个方向速度,并设置移动状态、隐藏指示箭头
m_iMoveState
=
2;
m_pControlBall->SetSpriteLinearVelocityY(30.f);
m_pGolfArrow->SetSpriteVisible(0);
}
3)
如果是按下向左方向键:
else
if(KEY_LEFT
==
iKey)
{
if(iIndexX
0
&&
RIGID_BLOCK
==
m_iGridData[iIndexY][iIndexX
1])
return;
//
给予控制球一个方向速度,并设置移动状态、隐藏指示箭头
m_iMoveState
=
3;
m_pControlBall->SetSpriteLinearVelocityX(-30.f);
m_pGolfArrow->SetSpriteVisible(0);
}
4)
如果是按下向右方向键:
else
if(KEY_RIGHT
==
iKey)
{
if(iIndexX
GRID_COUNT
&&
RIGID_BLOCK
==
m_iGridData[iIndexY][iIndexX
+
1])
return;
//
给予控制球一个方向速度,并设置移动状态、隐藏指示箭头
m_iMoveState
=
4;
m_pControlBall->SetSpriteLinearVelocityX(30.f);
m_pGolfArrow->SetSpriteVisible(0);
}
7、最后在Main.cpp中的OnKeyDown函数里面添加我们的自定义函数的调用:
g_GameMain.OnKeyDown(iKey,bAltPress,bShiftPress,bCtrlPress);
至此,本实验结束。
实验五球运动情况的处理
【实验内容】
步骤一、获得球所在边缘格子信息
步骤二、不同格子分情况处理
【实验思路】
获取球精灵的当前坐标并将其转换为二维格子的坐标,判断在运动中球边缘的情况,如果已经出了边界则不需要再判断,否则如果是方块则球停靠、是黑洞则重新开始关卡、是出口则通关。
【实验指导】
1、进入LessonX.cpp中的GameRun函数中,移动状态为移动中,时刻监测控制球的移动情况,根据移动方向的下一个方块,进行对应的处理。添加下面的if判断:
if(0
!=
m_iMoveState)
{
}
2、先将控制球精灵坐标转换到二维格子数组索引,如果控制球已经出了边界,所以不需要再判断。在上面的判断里面添加下面的代码:
float
fPosX
=
m_pControlBall->GetSpritePositionX();
float
fPosY
=
m_pControlBall->GetSpritePositionY();
int
iIndexX
=
SpritePosXToIndexX(fPosX);
int
iIndexY
=
SpritePosYToIndexY(fPosY);
//
控制球已经出了边界,所以不需要再判断
if(iIndexX
0
||
iIndexX
>=
GRID_COUNT
||
iIndexY
0
||
iIndexY
>=
GRID_COUNT)
return;
3、根据当前方向,获得控制球边缘所在的格子信息(球在坐标是在中心点,所以加上球的大小的一半)。总共有4中方向,即上下左右,分别用1、2、3、4来表示,添加下面的代码:
float
fNextPosX
=
fPosX;
float
fNextPosY
=
fPosY;
//
if(1
==
m_iMoveState)
{
fNextPosY
-=
m_fGridSize
*
0.5f;
}
else
if(2
==
m_iMoveState)
{
fNextPosY
+=
m_fGridSize
*
0.5f;
}
else
if(3
==
m_iMoveState)
{
fNextPosX
-=
m_fGridSize
*
0.5f;
}
else
if(4
==
m_iMoveState)
{
fNextPosX
+=
m_fGridSize
*
0.5f;
}
4、将上面得到的坐标再转换为二维格子的坐标,并判断是否越出边界,添加下面的代码:
int
iNextIndexX
=
SpritePosXToIndexX(fNextPosX);
int
iNextIndexY
=
SpritePosYToIndexY(fNextPosY);
//
该边缘已经出了边界,不需要往下判断
if(iNextIndexX
0
||
iNextIndexX
>=
GRID_COUNT
||
iNextIndexY
0
||
iNextIndexY
>=
GRID_COUNT)
return;
5、根据球边缘当前所在的格子的信息,进行不同的处理:是方块则球停靠、是黑洞则重新开始关卡、是出口则通关:
1)
是方块:
if(RIGID_BLOCK
==
m_iGridData[iNextIndexY][iNextIndexX])
{
//
清零移动状态
m_iMoveState
=
0;
//
速度清零,显示指示箭头
m_pControlBall->SetSpriteLinearVelocity(0.f,0.f);
m_pGolfArrow->SetSpriteVisible(1);
//
把球和指示箭头设置在本方块的中心
MoveSpriteToBlock(m_pControlBall,iIndexX,iIndexY);
MoveSpriteToBlock(m_pGolfArrow,iIndexX,iIndexY);
}
2)
是黑洞:
else
if(BLACK_HOLE
==
m_iGridData[iNextIndexY][iNextIndexX])
{
//
将游戏状态设置为1,重新开始关卡
m_iGameState
=
1;
}
3)
是出口:
else
if(GOLF_EXIT
==
m_iGridData[iNextIndexY][iNextIndexX])
{
//
将游戏状态设置为1,开始新关卡
m_iGameState
=
1;
//
往下一关卡,如果已经是最大值,则返回第一关
m_iCurLevel++;
if(m_iCurLevel
MAX_LEVEL)
m_iCurLevel
=
1;
}
至此,本实验结束。
实验六球出边界处理
【实验内容】
步骤、控制球出边界,则游戏重新开始
【实验思路】
此部分比较简单,只要通过系统判断球精灵是否越过世界边界,得到数据之后在我们的自定义函数里面处理即可。
【实验指导】
1、进入LessonX.h中添加我们的自定义处理函数OnSpriteColWorldLimit的声明:
void
OnSpriteColWorldLimit(const
char
*szName,const
int
iColSide);
2、进入LessonX.cpp中添加该函数的定义:
void
CGameMain::OnSpriteColWorldLimit(const
char
*szName,const
int
iColSide)
{
}
3、在上面的函数定义中,我们只要知道系统的OnSpriteColWorldLimit函数中返回的szName是否是球精灵的名称,如果是的话则本局游戏结束,重新开始游戏。在上面的定义里面添加下面的代码:
//
只处理控制的球
if(stricmp(szName,m_pControlBall->GetName())
!=
0)
return;
//
将游戏状态设置为1,重新开始关卡
m_iGameState
=
1;
4、进入Main.cpp文件,在OnSpriteColWorldLimit函数里面添加我们自定义的函数的调用,填入下面一行代码:
g_GameMain.OnSpriteColWorldLimit(szName,iColSide);
5、打开Funcode,点击地图中的球精灵,在右侧的“编辑”->“世界边界限制”中,选择限制模式为NULL,这样系统就会以我们自定义的函数处理球越过边界的事件了。
至此,本实验结束。