C++語(yǔ)言課程設(shè)計(jì)一迷你高爾夫
一、實(shí)驗(yàn)內(nèi)容
玩家通過(guò)按下鍵盤上的上下左右方向鍵控制球的移動(dòng),使其最終到達(dá)出口則游戲通關(guān)。
要求如下:
1、游戲分成3關(guān),第一關(guān)、第二關(guān)、第三關(guān)界面圖如下:
第一關(guān)
第二關(guān)
第三關(guān)
2、啟動(dòng)游戲進(jìn)入第一關(guān),勝利后進(jìn)入第二關(guān),如果第三關(guān)通關(guān),則游戲重新回到第一關(guān)。
3、游戲玩法是通關(guān)控制鍵盤上的上下左右方向鍵控制球的運(yùn)動(dòng),單擊方向鍵,則球獲得一個(gè)向該方向直線運(yùn)動(dòng)的速度。如果球遇到方塊,則球停止運(yùn)動(dòng),如果遇到黑洞,則游戲結(jié)束,重新開始該游戲,遇到出口則通關(guān)。
4、球靜止?fàn)顟B(tài)下會(huì)有箭頭指示球可以運(yùn)動(dòng)的方向,運(yùn)動(dòng)狀態(tài)下則箭頭消失。如果球運(yùn)動(dòng)出世界邊界,則游戲結(jié)束,重新回到該游戲。
二、實(shí)驗(yàn)指南
實(shí)驗(yàn)一
開始實(shí)驗(yàn)
【實(shí)驗(yàn)任務(wù)】
步驟一、打開FunCode,創(chuàng)建一個(gè)的C++語(yǔ)言項(xiàng)目;
步驟二、導(dǎo)入GolfGame場(chǎng)景。
【實(shí)驗(yàn)思路】
按實(shí)驗(yàn)指導(dǎo)完成。
【實(shí)驗(yàn)指導(dǎo)】
1、打開FunCode,點(diǎn)擊“項(xiàng)目”菜單,選擇“創(chuàng)建C++工程”
注意:工程名名稱要求字母開頭,只能包含字母和數(shù)字,且名字中間不能有空格。
2、點(diǎn)擊菜單“項(xiàng)目”中的“導(dǎo)入地圖模塊”,如圖一。跳出一個(gè)對(duì)話框,選中“GolfGame”模板,點(diǎn)擊“導(dǎo)入到工程”按鈕,如圖二。
圖
一
圖
二
3、導(dǎo)入成功后的,界面如下圖所示:
地圖不僅包括界面設(shè)計(jì),還包括該游戲可能要用到的其他精靈。添加到“場(chǎng)景”中的精靈,都已經(jīng)取好名稱,并根據(jù)程序要求設(shè)置好中心點(diǎn)、鏈接點(diǎn)等,學(xué)生只需要直接編程就可以。
實(shí)驗(yàn)二
游戲關(guān)卡初始化
【實(shí)驗(yàn)內(nèi)容】
步驟一、關(guān)卡地圖初始化
步驟二、清除上一關(guān)卡數(shù)據(jù)
步驟三、根據(jù)當(dāng)前關(guān)卡,選擇關(guān)卡數(shù)據(jù)
【實(shí)驗(yàn)思路】
游戲開始的時(shí)候首先要清除上一關(guān)的游戲數(shù)據(jù),即將上一關(guān)創(chuàng)建的精靈從地圖中刪掉。
將游戲地圖分成12*12的方格界面,游戲總共分成三關(guān),因此我們需要用三個(gè)二維數(shù)組m_iLevelData1[GRID_COUNT][GRID_COUNT]
m_iLevelData2[GRID_COUNT][GRID_COUNT]
m_iLevelData3[GRID_COUNT][GRID_COUNT]
(其中GRID_COUNT的值為12)
來(lái)存放這三關(guān)的數(shù)據(jù)即可。二維數(shù)組中0表示該位置不創(chuàng)建精靈,否則根據(jù)不同的值創(chuàng)建不同精靈,RIGID_BLOCK(值為1)表示創(chuàng)建一個(gè)方塊精靈,BLACK_HOLE(值為2)表示創(chuàng)建一個(gè)黑洞精靈,GOLF_EXIT(值為3)表示創(chuàng)建一個(gè)出口精靈。每次把代表該關(guān)卡的二維數(shù)組的數(shù)據(jù)拷貝到存儲(chǔ)當(dāng)前關(guān)卡m_iGridData的二維數(shù)組中。
【實(shí)驗(yàn)指導(dǎo)】
1、進(jìn)入LessonX.h的CGameMain類中,添加以下成員變量的聲明:
static
const
float
m_fGridStartX
;
//
第一塊方塊的起始坐標(biāo)
=
-(GRID_COUNT
*
g_fGridSize
*
0.5
g_fGridSize
/
2)
static
const
float
m_fGridStartY
;
static
const
float
m_fGridSize;
//
每塊的大小,包括球、出口等都是此大小
int
m_iRigidBlockCount;
//
本關(guān)卡創(chuàng)建的阻擋物方塊數(shù)量
int
m_iBlackHoleCount
;
//
本關(guān)卡創(chuàng)建的黑洞數(shù)量
int
m_iGolfExitCount;
//
本關(guān)卡創(chuàng)建的出口的數(shù)量
int
m_iCurLevel;
//
當(dāng)前關(guān)卡
int
m_iMoveState
;
//
控制球的移動(dòng)狀態(tài):0當(dāng)前靜止,可以移動(dòng),1、2、3、4:代表上下左右4個(gè)方向移動(dòng)中,按鍵無(wú)響應(yīng)
int
m_iGridData[GRID_COUNT][GRID_COUNT];
//
二維數(shù)組,存儲(chǔ)當(dāng)
前關(guān)卡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;
//阻擋物精靈向量數(shù)組
vector
m_vBlackHole;
//黑洞精靈向量數(shù)組
vector
m_vGolfExit;
//出口精靈向量數(shù)組
int
m_iControlStartX;
//控制球的初始X坐標(biāo),根據(jù)關(guān)卡數(shù)據(jù)自行指定
int
m_iControlStartY;
//球的初始Y坐標(biāo)
2、進(jìn)入LessonX.h中在頭文件聲明的后面添加下面的宏定義代碼:
#define
GRID_COUNT
//
N
*
N的矩陣方塊,一個(gè)N的大小
#define
MAX_LEVEL
//
最大關(guān)卡數(shù)量。如果要增加關(guān)卡,請(qǐng)先修改此值
#define
RIGID_BLOCK
//
以下3個(gè)分別為方塊阻擋物、黑洞、出口的值
#define
BLACK_HOLE
#define
GOLF_EXIT33、進(jìn)入LessonX.cpp中添加上面的成員變量的初始化:
1)
在構(gòu)造函數(shù)中把m_iGameState的值由0改為1:
m_iGameState
=
1;
2)
在構(gòu)造函數(shù)中添加下面代碼:
m_iRigidBlockCount
=
0;
//
本關(guān)卡創(chuàng)建的阻擋物方塊數(shù)量
m_iBlackHoleCount
=
0;
//
本關(guān)卡創(chuàng)建的黑洞數(shù)量
m_iGolfExitCount
=
0;
m_iCurLevel
=
1;
m_iControlStartX
=
0;
//球的初始X坐標(biāo)
m_iControlStartY
=
0;
//球的初始Y坐標(biāo)
3)
對(duì)于const類型的成員變量,我們需要在函數(shù)外面單獨(dú)進(jìn)行初始化,在文件最后面添加如下代碼:
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}
};
二維數(shù)組中0表示該位置不創(chuàng)建精靈,否則根據(jù)不同的值創(chuàng)建不同精靈,RIGID_BLOCK(值為1)表示創(chuàng)建一個(gè)方塊精靈,BLACK_HOLE(值為2)表示創(chuàng)建一個(gè)黑洞精靈,GOLF_EXIT(值為3)表示創(chuàng)建一個(gè)出口精靈。
4)
進(jìn)入GameInit函數(shù)里面,將球的運(yùn)動(dòng)狀態(tài)初始化為靜止,添加下面代碼:
m_iMoveState=0;
4、游戲初始化的時(shí)候,首先我們需要將前邊添加的精靈全部刪除掉,因此需要自定義的創(chuàng)建清除所有精靈函數(shù)ClearAllSprite()來(lái)實(shí)現(xiàn)這個(gè)功能。
1)
進(jìn)入LessonX.h文件的CGameMain類中添加該函數(shù)的聲明:
void
ClearAllSprite();
2)
在LessonX.cpp最后面添加該函數(shù)的定義:
void
CGameMain::
ClearAllSprite()
{
}
3)
再使用3個(gè)循環(huán),分別將上一關(guān)卡創(chuàng)建的3種精靈刪除掉。在上邊定義的函數(shù)中添加如下代碼:
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是存儲(chǔ)三種精靈的向量數(shù)組,每一個(gè)循環(huán)都遍歷一遍向量數(shù)組并調(diào)用數(shù)組中每個(gè)精靈的DeleteSprite函數(shù)即可。
m_vRigidBlock.size()、m_vBlackHole.size()、m_vGolfExit.size()表示每種精靈的總數(shù)。
4)
最后在GameInit()中添加調(diào)用此函數(shù)的代碼:
ClearAllSprite();
5、在GameInit()中,我們也需要對(duì)關(guān)卡進(jìn)行選擇初始化。因此我們需要自定義一個(gè)初始化關(guān)卡函數(shù)InitLevel
()來(lái)實(shí)現(xiàn)這個(gè)功能。
1)
進(jìn)入LessonX.h文件的CGameMain類中添加該函數(shù)的聲明:
void
InitLevel();
2)
在LessonX.cpp最后面添加該函數(shù)的定義:
void
CGameMain::
InitLevel()
{
}
3)
初始化關(guān)卡,要根據(jù)當(dāng)前關(guān)卡,選擇關(guān)卡的數(shù)據(jù),即將代表關(guān)卡的二維數(shù)組中的數(shù)據(jù)拷貝到m_iGridData中,同時(shí)設(shè)置控制球在每個(gè)數(shù)組中的起始位置。首先把需要的數(shù)據(jù)初始化為0,代碼如下:
//
總數(shù)置0,重新創(chuàng)建
m_iRigidBlockCount
=
0;
m_iBlackHoleCount
=
0;
m_iGolfExitCount
=
0;
4)
選擇關(guān)卡我們使用了switch-case結(jié)構(gòu),程序通過(guò)判斷switch中的參數(shù)進(jìn)入到不同的case中去,每個(gè)case就是一種情況的實(shí)現(xiàn)。代碼如下:
//
根據(jù)當(dāng)前關(guān)卡,選擇關(guān)卡數(shù)據(jù)
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錯(cuò)誤
case
1:
default:
{
m_iControlStartX
=
5;
m_iControlStartY
=
6;
memcpy(m_iGridData,m_iLevelData1,sizeof(int)
*
GRID_COUNT
*
GRID_COUNT);
}
break;
};
memcpy函數(shù)作用是從源src所指的內(nèi)存地址的起始位置開始拷貝n個(gè)字節(jié)到目標(biāo)dest所指的內(nèi)存地址的起始位置中。因?yàn)槎S數(shù)組在內(nèi)存中的存放方式是連續(xù)的,因此我們將源地址拷貝給m_iGridData的起始地址之后,系統(tǒng)后自動(dòng)根據(jù)m_iGridData的下標(biāo)來(lái)找到正確的值。
5)
最后在GameInit()中添加調(diào)用此函數(shù)的代碼:
InitLevel();
至此,本實(shí)驗(yàn)結(jié)束。
實(shí)驗(yàn)三
初始化游戲精靈
【實(shí)驗(yàn)內(nèi)容】
步驟一、創(chuàng)建精靈
步驟二、初始化精靈位置
【實(shí)驗(yàn)思路】
遍歷二維數(shù)組m_iGridData,根據(jù)數(shù)組值生成對(duì)應(yīng)的精靈實(shí)例:值為0的時(shí)候不用創(chuàng)建,需要?jiǎng)?chuàng)建的精靈名字前綴為(按照宏定義的1,2,3順序):RigidBlock,BlackHole,GolfExit。每創(chuàng)建一種精靈,將其總數(shù)加1
:m_iRigidBlockCount,m_iBlackHoleCount,m_iGolfExitCount。
【實(shí)驗(yàn)指導(dǎo)】
1、進(jìn)入LessonX.h,CGameMain類中添加下面成員變量的聲明:
CSprite*
m_pControlBall;
//控制球精靈
CSprite*
m_pGolfArrow;
//指示箭頭精靈
在LessonX.cpp中CGameMain類在構(gòu)造函數(shù)里面添加上面成員變量的初始化:
m_pControlBall
=
new
CSprite(“ControlBall“);
m_pGolfArrow
=
new
CSprite(“GolfArrow“);
2、創(chuàng)建精靈之后需要將精靈移到特定位置,因此我們需要定義一個(gè)自定義的函數(shù)MoveSpriteToBlock來(lái)實(shí)現(xiàn)這個(gè)功能。
6)
進(jìn)入LessonX.h中添加該函數(shù)的聲明:
void
MoveSpriteToBlock(CSprite*
tmpSprite,const
int
iIndexX,const
int
iIndexY);
7)
在LessonX.cpp最后面添加該函數(shù)的定義:
void
CGameMain::MoveSpriteToBlock(CSprite*
tmpSprite,const
int
iIndexX,const
int
iIndexY)
{
}
8)
傳入該函數(shù)的是精靈實(shí)體以及x,y坐標(biāo)參數(shù)。再通過(guò)SetSpritePosition函數(shù)設(shè)置精靈位置,在該函數(shù)里面添加如下代碼:
float
fPosX
=
m_fGridStartX
+
iIndexX
*
m_fGridSize;
float
fPosY
=
m_fGridStartY
+
iIndexY
*
m_fGridSize;
tmpSprite->SetSpritePosition(fPosX,fPosY);
3、這里定義一個(gè)函數(shù)CreateAllSprite()來(lái)創(chuàng)建控制球、方塊精靈、出口精靈和黑洞精靈。然后在函數(shù)內(nèi)部添加代碼創(chuàng)建精靈。
原理是通過(guò)兩個(gè)for循環(huán)來(lái),判斷m_iGridData的值,如果為0,則不創(chuàng)建,如果為RIGID_BLOCK則創(chuàng)建一個(gè)方塊精靈,為
BLACK_HOLE則創(chuàng)建一個(gè)黑洞精靈,為GOLF_EXIT則創(chuàng)建一個(gè)出口精靈。由于我們預(yù)先在地圖中擺放了三個(gè)模板精靈,因此只需要使用CloneSprite函數(shù)即可創(chuàng)建新的精靈。然后再調(diào)用MoveSpriteToBlock函數(shù)將精靈移動(dòng)到指定位置。最后每創(chuàng)建一個(gè)實(shí)現(xiàn)精靈,將它添加到相應(yīng)的精靈向量數(shù)組中。
1)
進(jìn)入LessonX.h文件的CGameMain類中添加該函數(shù)的聲明:
void
CreateAllSprite();
2)
在LessonX.cpp最后面添加該函數(shù)的定義:
void
CGameMain::
CreateAllSprite()
{
}
3)
在定義汗的函數(shù)中添加變量聲明:
int
iLoopX
=
0,iLoopY
=
0;
CSprite*
tmpSprite;
char
*szName
=
NULL;
4)
實(shí)現(xiàn)兩個(gè)for循環(huán):
for(iLoopY
=
0;
iLoopY
GRID_COUNT;
iLoopY++)
{
for(int
iLoopX
=
0;
iLoopX
GRID_COUNT;
iLoopX++)
{
}
}
5)
在里面的循環(huán)添加判斷代碼:
如果是0,則不創(chuàng)建精靈,continue表示跳出本次循環(huán),繼續(xù)下一個(gè)循環(huán)。
if(0
==
m_iGridData[iLoopY][iLoopX])
continue;
如果是方塊,則創(chuàng)建方塊精靈:
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++;
}
如果是黑洞,則創(chuàng)建黑洞精靈:
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++;
}
如果是出口,則創(chuàng)建出口精靈:
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)
將控制球和指示箭頭擺放到初始位置,此時(shí)球靜止,因此指示箭頭可見。在上面的兩個(gè)循環(huán)后面添加下面的代碼:
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()中調(diào)用此函數(shù):
CreateAllSprite();
至此,本實(shí)驗(yàn)結(jié)束。
實(shí)驗(yàn)四
移動(dòng)球
【實(shí)驗(yàn)內(nèi)容】
步驟一、響應(yīng)鍵盤按鍵按下消息
步驟二、球精靈坐標(biāo)轉(zhuǎn)換為二維格子數(shù)組索引
步驟三、判斷移動(dòng)方向,使球獲取速度
【實(shí)驗(yàn)思路】
首先響應(yīng)系統(tǒng)的按鍵消息函數(shù),然后獲取精靈坐標(biāo),并將其轉(zhuǎn)換為二維格子中的坐標(biāo),判斷其旁邊的格子是否是方塊,如果不是則給球一個(gè)移動(dòng)的速度。
【實(shí)驗(yàn)指導(dǎo)】
1、進(jìn)入LessonX.h中,添加我們自定義的鍵盤消息處理函數(shù)OnKeyDown的聲明:
void
OnKeyDown(const
int
iKey,const
int
iAltPress,const
int
iShiftPress,const
int
iCtrlPress);
2、在LessonX.cpp中添加該函數(shù)的定義:
void
CGameMain::OnKeyDown(const
int
iKey,const
int
iAltPress,const
int
iShiftPress,const
int
iCtrlPress)
{
}
3、首先判斷游戲狀態(tài),只有在游戲中已經(jīng)可以移動(dòng)狀態(tài)才響應(yīng)按鍵,在上面函數(shù)中添加下面的代碼:
if(2
!=
m_iGameState
||
0
!=
m_iMoveState)
return;
4、獲取控制球精靈坐標(biāo)轉(zhuǎn)換到二維格子數(shù)組索引,這里我們需要定義兩個(gè)函數(shù)SpritePosXToIndexX和SpritePosXToIndexY分別處理精靈坐標(biāo)轉(zhuǎn)換為二維格子的X索引和Y索引:
1)
進(jìn)入LessonX.h中添加上面兩個(gè)函數(shù)的聲明:
int
SpritePosXToIndexX(const
float
fPosX);
int
SpritePosYToIndexY(const
float
fPosY);
2)
進(jìn)入LessonX.cpp中添加SpritePosXToIndexX的定義:
int
CGameMain::
SpritePosXToIndexX
(const
float
fPosX)
{
}
3)
首先得到左右邊界的坐標(biāo)值。m_fGridStartX是在方塊的中心,所以需要減去半個(gè)方塊的寬度才是左邊邊界。在SpritePosXToIndexX函數(shù)定義中添加下面的代碼:
const
float
fLeftSide
=
m_fGridStartX
m_fGridSize
/
2.f;
const
float
fRightSide
=
fLeftSide
+
m_fGridSize
*
GRID_COUNT;
4)
最后需要判斷坐標(biāo)是否出了左右邊界,如果沒有則返回X索引值。在上面的函數(shù)里面添加下面的判斷代碼:
if(fPosX
fLeftSide
||
fPosX
fRightSide)
return
-1;
int
iIndexX
=
(int)((fPosX
fLeftSide)
/
m_fGridSize);
return
iIndexX;
5)
在LessonX.cpp中添加SpritePosYToIndexY函數(shù)的定義:
int
CGameMain::SpritePosYToIndexY(const
float
fPosY)
{
}
6)
首先獲取上下邊界坐標(biāo)值。m_fGridStartY是在方塊的中心,所以需要減去半個(gè)方塊的寬度才是上邊邊界。在上面的函數(shù)定義中添加下面的代碼:
const
float
fTopSide
=
m_fGridStartY
m_fGridSize
/
2.f;
const
float
fBottomSide
=
fTopSide
+
m_fGridSize
*
GRID_COUNT;
7)
最后判斷是否超過(guò)了上下邊界,沒有則返回Y索引值:
if(fPosY
fTopSide
||
fPosY
fBottomSide)
return
-1;
int
iIndexY
=
(int)((fPosY
fTopSide)
/
m_fGridSize);
return
iIndexY;
5、有了上面的兩個(gè)函數(shù),我們就可以將控制球精靈坐標(biāo)轉(zhuǎn)換到二維格子數(shù)組索引,并判斷坐標(biāo)是否超出邊界,在OnKeyDown函數(shù)中添加下面的代碼:
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、根據(jù)上下左右方向鍵,先判斷控制球旁邊是否是方塊,如果是方塊則不能移動(dòng)。不是方塊,則給予控制球一個(gè)速度。使用iIndexX,iIndexY的時(shí)候,注意要判斷是否是邊緣的索引,如果不判斷就進(jìn)行加1減1,訪問數(shù)組會(huì)造成下標(biāo)溢出。即如果要判斷左邊是否是方塊阻擋,則索引值為
IndexX
。此時(shí)必須先判斷iIndexX大于0,才能減一。如果iIndexX為0,代表直接可以移動(dòng)。
1)
如果是按下向上方向鍵:
if(KEY_UP
==
iKey)
{
if(iIndexY
0
&&
RIGID_BLOCK
==
m_iGridData[iIndexY
1][iIndexX])
return;
//
給予控制球一個(gè)方向速度,并設(shè)置移動(dòng)狀態(tài)、隱藏指示箭頭
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;
//
給予控制球一個(gè)方向速度,并設(shè)置移動(dòng)狀態(tài)、隱藏指示箭頭
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;
//
給予控制球一個(gè)方向速度,并設(shè)置移動(dòng)狀態(tài)、隱藏指示箭頭
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;
//
給予控制球一個(gè)方向速度,并設(shè)置移動(dòng)狀態(tài)、隱藏指示箭頭
m_iMoveState
=
4;
m_pControlBall->SetSpriteLinearVelocityX(30.f);
m_pGolfArrow->SetSpriteVisible(0);
}
7、最后在Main.cpp中的OnKeyDown函數(shù)里面添加我們的自定義函數(shù)的調(diào)用:
g_GameMain.OnKeyDown(iKey,bAltPress,bShiftPress,bCtrlPress);
至此,本實(shí)驗(yàn)結(jié)束。
實(shí)驗(yàn)五球運(yùn)動(dòng)情況的處理
【實(shí)驗(yàn)內(nèi)容】
步驟一、獲得球所在邊緣格子信息
步驟二、不同格子分情況處理
【實(shí)驗(yàn)思路】
獲取球精靈的當(dāng)前坐標(biāo)并將其轉(zhuǎn)換為二維格子的坐標(biāo),判斷在運(yùn)動(dòng)中球邊緣的情況,如果已經(jīng)出了邊界則不需要再判斷,否則如果是方塊則球??俊⑹呛诙磩t重新開始關(guān)卡、是出口則通關(guān)。
【實(shí)驗(yàn)指導(dǎo)】
1、進(jìn)入LessonX.cpp中的GameRun函數(shù)中,移動(dòng)狀態(tài)為移動(dòng)中,時(shí)刻監(jiān)測(cè)控制球的移動(dòng)情況,根據(jù)移動(dòng)方向的下一個(gè)方塊,進(jìn)行對(duì)應(yīng)的處理。添加下面的if判斷:
if(0
!=
m_iMoveState)
{
}
2、先將控制球精靈坐標(biāo)轉(zhuǎn)換到二維格子數(shù)組索引,如果控制球已經(jīng)出了邊界,所以不需要再判斷。在上面的判斷里面添加下面的代碼:
float
fPosX
=
m_pControlBall->GetSpritePositionX();
float
fPosY
=
m_pControlBall->GetSpritePositionY();
int
iIndexX
=
SpritePosXToIndexX(fPosX);
int
iIndexY
=
SpritePosYToIndexY(fPosY);
//
控制球已經(jīng)出了邊界,所以不需要再判斷
if(iIndexX
0
||
iIndexX
>=
GRID_COUNT
||
iIndexY
0
||
iIndexY
>=
GRID_COUNT)
return;
3、根據(jù)當(dāng)前方向,獲得控制球邊緣所在的格子信息(球在坐標(biāo)是在中心點(diǎn),所以加上球的大小的一半)??偣灿?中方向,即上下左右,分別用1、2、3、4來(lái)表示,添加下面的代碼:
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、將上面得到的坐標(biāo)再轉(zhuǎn)換為二維格子的坐標(biāo),并判斷是否越出邊界,添加下面的代碼:
int
iNextIndexX
=
SpritePosXToIndexX(fNextPosX);
int
iNextIndexY
=
SpritePosYToIndexY(fNextPosY);
//
該邊緣已經(jīng)出了邊界,不需要往下判斷
if(iNextIndexX
0
||
iNextIndexX
>=
GRID_COUNT
||
iNextIndexY
0
||
iNextIndexY
>=
GRID_COUNT)
return;
5、根據(jù)球邊緣當(dāng)前所在的格子的信息,進(jìn)行不同的處理:是方塊則球???、是黑洞則重新開始關(guān)卡、是出口則通關(guān):
1)
是方塊:
if(RIGID_BLOCK
==
m_iGridData[iNextIndexY][iNextIndexX])
{
//
清零移動(dòng)狀態(tài)
m_iMoveState
=
0;
//
速度清零,顯示指示箭頭
m_pControlBall->SetSpriteLinearVelocity(0.f,0.f);
m_pGolfArrow->SetSpriteVisible(1);
//
把球和指示箭頭設(shè)置在本方塊的中心
MoveSpriteToBlock(m_pControlBall,iIndexX,iIndexY);
MoveSpriteToBlock(m_pGolfArrow,iIndexX,iIndexY);
}
2)
是黑洞:
else
if(BLACK_HOLE
==
m_iGridData[iNextIndexY][iNextIndexX])
{
//
將游戲狀態(tài)設(shè)置為1,重新開始關(guān)卡
m_iGameState
=
1;
}
3)
是出口:
else
if(GOLF_EXIT
==
m_iGridData[iNextIndexY][iNextIndexX])
{
//
將游戲狀態(tài)設(shè)置為1,開始新關(guān)卡
m_iGameState
=
1;
//
往下一關(guān)卡,如果已經(jīng)是最大值,則返回第一關(guān)
m_iCurLevel++;
if(m_iCurLevel
MAX_LEVEL)
m_iCurLevel
=
1;
}
至此,本實(shí)驗(yàn)結(jié)束。
實(shí)驗(yàn)六球出邊界處理
【實(shí)驗(yàn)內(nèi)容】
步驟、控制球出邊界,則游戲重新開始
【實(shí)驗(yàn)思路】
此部分比較簡(jiǎn)單,只要通過(guò)系統(tǒng)判斷球精靈是否越過(guò)世界邊界,得到數(shù)據(jù)之后在我們的自定義函數(shù)里面處理即可。
【實(shí)驗(yàn)指導(dǎo)】
1、進(jìn)入LessonX.h中添加我們的自定義處理函數(shù)OnSpriteColWorldLimit的聲明:
void
OnSpriteColWorldLimit(const
char
*szName,const
int
iColSide);
2、進(jìn)入LessonX.cpp中添加該函數(shù)的定義:
void
CGameMain::OnSpriteColWorldLimit(const
char
*szName,const
int
iColSide)
{
}
3、在上面的函數(shù)定義中,我們只要知道系統(tǒng)的OnSpriteColWorldLimit函數(shù)中返回的szName是否是球精靈的名稱,如果是的話則本局游戲結(jié)束,重新開始游戲。在上面的定義里面添加下面的代碼:
//
只處理控制的球
if(stricmp(szName,m_pControlBall->GetName())
!=
0)
return;
//
將游戲狀態(tài)設(shè)置為1,重新開始關(guān)卡
m_iGameState
=
1;
4、進(jìn)入Main.cpp文件,在OnSpriteColWorldLimit函數(shù)里面添加我們自定義的函數(shù)的調(diào)用,填入下面一行代碼:
g_GameMain.OnSpriteColWorldLimit(szName,iColSide);
5、打開Funcode,點(diǎn)擊地圖中的球精靈,在右側(cè)的“編輯”->“世界邊界限制”中,選擇限制模式為NULL,這樣系統(tǒng)就會(huì)以我們自定義的函數(shù)處理球越過(guò)邊界的事件了。
至此,本實(shí)驗(yàn)結(jié)束。