发布时间 : 星期二 文章03FunCode游戏设计+C++课程设计 - 拼图游戏更新完毕开始阅读
掉“空格开始”精灵。在步骤2的函数里面添加下面的代码:
if( KEY_SPACE == iKey && 0 == m_iGameState ) {
}
m_iGameState =
1;
// 隐藏提示开始文字
m_spGameBegin->SetSpriteVisible(0);
4、 进入Main.cpp函数里面,将系统捕获到的键盘按下消息的参数传给我们自定义的函
数,需要在OnKeyDown函数里面添加下面一行代码:
g_GameMain.OnKeyDown(iKey,bAltPress,bShiftPress,bCtrlPress);
至此,本实验结束。
实验三 初始化随机显示方块
【实验内容】
步骤一、添加一个4x4的二维数组,将图案分成15份,随机摆放,剩下一个位置留空,用于移动方块。
【实验思路】
游戏的原理是在一个4 * 4的方块矩阵(二维数组),前15个的值按顺序从1-15依次递增,第16个留空,我们设置为一个名称为“NULL”的精灵。按照这个顺序排列的矩阵值代表游戏胜利。
精灵名称依次是PictureBlock1,PictureBlock2…PictureBlock15。因此,初始化的时候,用一个数组iRandData顺序保存1到15,对应表示15个方块精灵。再用一个二维数组m_iBlockState[4][4]表示这16个位置。
每次随机从iRandData中取一个值,赋给m_iBlockState,表示某个位置放置哪张方块图片。
为了保证同一张方块图片不会被重复使用,每次从iRandData随机取一个值以后,将该随机数后面的数组值往前移一位,并且数组大小减1。
【实验指导】
1、 进入LessonX.h里面,添加如下的变量声明:
1) 添加成员变量声明:
static const float 的起始坐标 static const float static const float int
m_fBlockStartY m_fBlockSize ;
;
// 屏幕高度75 / 4块 = 18.75每块的大小.
//
二维数组,存储N*N的
m_fBlockStartX;// 按方块大小,在编辑器里摆放的第一块方块
编辑器里预先摆放好的方块宽和高必须与此值一致
m_iBlockState[BLOCK_COUNT][BLOCK_COUNT]; 矩阵方块信息
CSprite* m_spBlock[BLOCK_COUNT*BLOCK_COUNT];//方块精灵
注意,m_fBlockStartX,m_fBlockStartY,m_fBlockSize三个变量是不能改变的,
因此我们需要将它们设置为const类型,const在c++里面表示只读,即后面程
序只能读取使用它的值而不能对其进行赋值改变。C++类中的成员变量如果是const类型,则需要在其前面加上一个static的声明,即静态变量的声明,这样,我们才能在cpp文件里面使用这个变量。 2) 添加BLOCK_COUNT的#define声明:
在LessonX.h的#include后面添加下面一行:
#define BLOCK_COUNT
4
// N * N 的矩阵方块,一个N的大小
#define相当于告诉编译器,如果遇到BLOCK_COUNT则它相当与一个int类型的变量,且值为4。使用#define可以方便改变我们需要的值。
2、 进入LessonX.cpp中在最后面添加下面的成员变量的声明:
const float CGameMain::m_fBlockSize=18.75f; const float CGameMain::m_fBlockStartX=-40.625f; const float CGameMain::m_fBlockStartY=-28.125f;
因为这三个变量的类型是const类型,因此我们不能在构造函数里面定义它,需要单独拿出来进行定义。相当于c里面的全局变量的定义。
3、 进入LessonX.cpp中的GameInit函数里面填写初始化代码。
1) 填写下面几行变量的定义:
int int
iLoopX
= 0, iLoopY
= 0, iLoop = 0;
iOneIndex = 0, iRandIndex = 0;
// 用做随机的数组,当随机抽取到此数组中的一个时,比如随机到第五个,则将第五个取出来用
// 第五个后面的数组都往前移动一位,将第五个覆盖掉,数组总数减一,下次再在这剩余的14个数值里随机抽取
int iDataCount 12, 13, 14, 15};
=
BLOCK_COUNT * BLOCK_COUNT - 1;
int iRandData[BLOCK_COUNT * BLOCK_COUNT - 1] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
iDataCount用于记录方块的数目,iRandData是一个二维数组,里面存放了1至15的int值,对应表示1-15个方块精灵,用于后面对方块进行随机生成。每次随机从此数组中抽取一个值,比如随机到第五个,则将第五个取出来用,第五个后面的数组都往前移动一位,将第五个覆盖掉,数组总数减一,下次再在这剩余的14个数值里随机抽取。这样做的好处是确保不会重复两次以上使用同一个方块。
2) 由于我们用于记录方块位置的成员变量是一个二维数组m_iBlockState,而我们
用于保存所有方块精灵的数组是一个一维数组,所以下面我们需要用到一些自定义的函数用于从二维数组转换到一维数组。其实二维数组的存放在内存里面也是连续存放的,我们在读取他们的值得时候当然可以使用一维数组的方法来读取它,只不过这里需要进行数组下标数值的相应改变。例:二维数组a[x][y]转换为一维数组的计算方法是:x* 二维数组中每行的元素数+y。
进入LessonX.h中添加我们自定义的二维数组索引转换成一维数组索引的函数XYToOneIndex声明:
int XYToOneIndex( const int iIndexX, const int iIndexY );
进入LessonX.cpp中添加上面函数的定义:
int CGameMain::XYToOneIndex( const int iIndexX, const int iIndexY ) {
return (iIndexY * BLOCK_COUNT + iIndexX);
}
4、 我们使用两个for循环来遍历二维数组,第一个for循环遍历二维数组m_iBlockState
的第二个下标,第二个for循环遍历二维数组m_iBlockState的第一个下标。在GameIint函数里面添加下面的代码:
for( iLoopY = 0; iLoopY < BLOCK_COUNT; iLoopY++ )
{
}
for( iLoopX = 0; iLoopX < BLOCK_COUNT; iLoopX++ ) { }
5、 我们首先用刚刚我们自定义的数组下标转换函数XYToOneIndex将二维数组下标转
换成一维数组的下标。在for( iLoopX = 0; iLoopX < BLOCK_COUNT; iLoopX++ )里面填写下面的代码:
iOneIndex =
XYToOneIndex( iLoopX, iLoopY );
iOneIndex即是二维数组在一维数组里面的下标值。
1) 如果遍历到数组的最后一个,我们就将其设定为空位精灵,它的名称为NULL”,
后面我们只要判断一个精灵的周围有没有名称为”NULL”的精灵就可以知道他周围是否有空位,它在二维数组中的值以0来代替。添加下面的代码: // 数组的最后一个 if( BLOCK_COUNT - 1 == iLoopX && BLOCK_COUNT - 1 == iLoopY )
{ }
m_iBlockState[iLoopY][iLoopX] = 0;
m_spBlock[iOneIndex] = new CSprite(\
2) 如果没有遍历到最后一个位置,我们随机从iRandData取一个值赋给
m_iBlockState,并且给对应名字的精灵数组m_spBlock初始化,同时将该精灵移动到对应的位置。添加下面代码:
else
{
// 在当前剩余未使用到的数值里随机一个出来,赋值给二维数组 iRandIndex
=
CSystem::RandomRange( 0, iDataCount - 1 );
m_iBlockState[iLoopY][iLoopX] = iRandData[iRandIndex]; }
m_spBlock[iOneIndex]=new CSprite(tmpName); // 将该精灵移动到对应的位置
MoveSpriteToBlock( m_spBlock[iOneIndex], iLoopX, iLoopY );
char* tmpName=CSystem::MakeSpriteName(\
在这里我们需要添加一个移动精灵到特定位置的函数MoveSpriteToBlock。进入LessonX.h中添加函数的声明:
void MoveSpriteToBlock( CSprite *tmpSprite, const int iIndexX, const int iIndexY ); 进入LessonX.cpp中添加该函数的定义:
void CGameMain::MoveSpriteToBlock( CSprite *tmpSprite, const int iIndexX, const int iIndexY )
{
float fPosX float fPosY }
= =
m_fBlockStartX + iIndexX * m_fBlockSize; m_fBlockStartY + iIndexY * m_fBlockSize;
tmpSprite->SetSpritePosition(fPosX, fPosY );
3) 由于是随机从iRandData数组里面取一个数赋给m_iBlockState,所以我们每次
赋一个需要将iRandData数组后面的值往前面移动覆盖掉改值。因此我们需要用for循环,将抽取到的索引iRandIndex后面的数组值依次往前移动一位,同时方块总数目减一。代码如下:
for( iLoop = iRandIndex; iLoop < iDataCount - 1; iLoop++ )
{ }
// 剩余有效值总数减一 iDataCount--;
iRandData[iLoop] = iRandData[iLoop + 1];
至此,本实验结束。
实验四 移动方块
【实验内容】
步骤一、获取鼠标单击消息 步骤二、判断鼠标点击的方块
步骤三、判断周围是否有空位,移动方块 【实验思路】
遍历一维数组m_spBlock,使用IsPointInSprite 函数判断当前鼠标坐标是否位于某个名字的精灵内部。如果找到某个名字的精灵被点击中,请将当前循环变量iLoop赋值给iClickIndex。再判断该方块精灵周围有没有名称为“NULL”的精灵,有的有的话移动到该位置。 【实验指导】
1、 进入LessonX.h中添加我们自定义的处理鼠标单击的函数声明:
void OnMouseClick( const int iMouseType, const float fMouseX, const float fMouseY ); 2、 进入LessonX.cpp中添加该函数的定义:
void CGameMain::OnMouseClick( const int iMouseType, const float fMouseX, const float fMouseY ) { }
3、 判断游戏是否正在进行,在上面的函数里面添加下面的代码:
// 只处理游戏进行中的鼠标响应 if( 2 != m_iGameState )
return;
4、 获取鼠标点击的坐标,使用一个for循环遍历存储所以方块精灵的一维数组
m_spBlock,判断该坐标是否在某一个方块精灵中,是的话得到该精灵的下标值。
添加下面的代码:
int iClickIndex int iLoop
= =
-1; 0;
for( iLoop = 0; iLoop < BLOCK_COUNT * BLOCK_COUNT; iLoop++ )