//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#include "CommonAPI.h"
#include "LessonX.h"
#include
///////////////////////////////////////////////////////////////////////////////////////////
//
// 主函数入口
//
//////////////////////////////////////////////////////////////////////////////////////////
int g_GameState=0;
const int BLOCK_COUNT=4;
// 二维数组,存储N*N的矩阵方块信息
int g_iBlockState[BLOCK_COUNT][BLOCK_COUNT];
// 一维数组,存储上面二维数组中的方块精灵的名字。TO DO 思考一下数 // 组大小一样的二维数组索引与一维数组索引如何相互转换?
char g_szBlockName[BLOCK_COUNT * BLOCK_COUNT][64];
// 按方块大小,在编辑器里摆放的第一块方块的起始坐标
const float g_fBlockStartX = -40.625f;
const float g_fBlockStartY = -28.125f;
// 屏幕高度75 / 4块 = 18.75每块的大小.编辑器里预先摆放好的方块宽和高 // 必须与此值一致
const float g_fBlockSize = 18.75f;
int iLoopX = 0, iLoopY = 0, iLoop = 0;
int iOneIndex = 0, iRandIndex = 0;
/* 用做随机的数组,当随机抽取到此数组中的一个时,比如随机到第五个,则将 * 第五个取出来用。第五个后面的数组都往前移动一位,将第五个覆盖掉,数组 * 总数减一,下次再在这剩余的14个数值里随机抽取
*/
int iDataCount = BLOCK_COUNT * BLOCK_COUNT - 1;
int iRandData[BLOCK_COUNT * BLOCK_COUNT - 1] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int XYToOneIndex( const int iIndexX, const int iIndexY )
{
return (iIndexY * BLOCK_COUNT + iIndexX);
}
void MoveSpriteToBlock( const char *szName, const int iIndexX, const int iIndexY )
{
float fPosX = g_fBlockStartX + iIndexX * g_fBlockSize;
float fPosY = g_fBlockStartY + iIndexY * g_fBlockSize;
dSetSpritePosition( szName, fPosX, fPosY );
}
int IsGameWin()
{
int iLoopX = 0, iLoopY = 0;
int iResult = 1;
for( iLoopY = 0; iLoopY < BLOCK_COUNT; iLoopY++ )
{
for( iLoopX = 0; iLoopX < BLOCK_COUNT; iLoopX++ )
{
// 数组的最后一个
if( BLOCK_COUNT - 1 == iLoopX && BLOCK_COUNT - 1 == iLoopY )
break;
// 其中一个值不等于,那么就没有胜利
if( g_iBlockState[iLoopY][iLoopX] != iResult )
return 0;
iResult++;
}
}
return 1;
}
// 一维数组索引转换到二维数组索引X,注意这2个数组大小必须一致
int OneIndexToX( const int iIndex )
{
return (iIndex % BLOCK_COUNT);
}
// 一维数组索引转换到二维数组索引Y,注意这2个数组大小必须一致
int OneIndexToY( const int iIndex )
{
return (iIndex / BLOCK_COUNT);
}
int PASCAL WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// 初始化游戏引擎
if( !dInitGameEngine( hInstance, lpCmdLine ) )
return 0;
// To do : 在此使用API更改窗口标题
dSetWindowTitle("拼图");
// 引擎主循环,处理屏幕图像刷新等工作
while( dEngineMainLoop() )
{
// 获取两次调用之间的时间差,传递给游戏逻辑处理
float fTimeDelta = dGetTimeDelta();
// 执行游戏主循环
GameMainLoop( fTimeDelta );
};
// 关闭游戏引擎
dShutdownGameEngine();
return 0;
}
//==========================================================================
//
// 引擎捕捉鼠标移动消息后,将调用到本函数
// 参数 fMouseX, fMouseY:为鼠标当前坐标
//
void dOnMouseMove( const float fMouseX, const float fMouseY )
{
// 可以在此添加游戏需要的响应函数
OnMouseMove(fMouseX, fMouseY );
}
//==========================================================================
//
// 引擎捕捉鼠标点击消息后,将调用到本函数
// 参数 iMouseType:鼠标按键值,见 enum MouseTypes 定义
// 参数 fMouseX, fMouseY:为鼠标当前坐标
//
void dOnMouseClick( const int iMouseType, const float fMouseX, const float fMouseY )
{
// 可以在此添加游戏需要的响应函数
if( 2 != iMouseType )
{
}
int iClickIndex = -1;
int iLoop = 0;
for( iLoop = 0; iLoop < BLOCK_COUNT * BLOCK_COUNT; iLoop++ )
{
if( '\0' == g_szBlockName[iLoop][0] )
continue;
// 使用API dIsPointInSprite 判断指定坐标是否位于某个名字的精灵内部
if( dIsPointInSprite( g_szBlockName[iLoop], fMouseX, fMouseY ) )
{
iClickIndex = iLoop;
break;
}
}
// 判断鼠标是否点中方块
if( -1 == iClickIndex )
return;
// 将该一维数组的Index转换成二维数组的X,Y
int iIndexX = OneIndexToX( iClickIndex );
int iIndexY = OneIndexToY( iClickIndex );
// TODO 在二维数组里查找鼠标点击的方块上下左右4个方向上是否有空位:
// 注意边界判断,否则数组访问会越界。比如判断左边时,需要判断是否已经是 //最左边的索引(iIndexX == 0)
// 如果有空位(值为0),则将该空位的索引赋值给下面这2个变量
int iEmptyIndexX = -1, iEmptyIndexY = -1;
// X 左方向(4个方向均需要判断是否是位于边缘,iIndexX > 0 即起此作用)
if( iIndexX > 0 )
{
if( 0 == g_iBlockState[iIndexY][iIndexX - 1] )
{
iEmptyIndexX = iIndexX - 1;
iEmptyIndexY = iIndexY;
}
}
// X 右方向
if( -1 == iEmptyIndexX && iIndexX < BLOCK_COUNT - 1 )
{
if( 0 == g_iBlockState[iIndexY][iIndexX + 1] )
{
iEmptyIndexX = iIndexX + 1;
iEmptyIndexY = iIndexY;
}
}
// Y 上方向
if( -1 == iEmptyIndexY && iIndexY > 0 )
{
if( 0 == g_iBlockState[iIndexY - 1][iIndexX] )
{
iEmptyIndexX = iIndexX;
iEmptyIndexY = iIndexY - 1;
}
}
// Y 下方向
if( -1 == iEmptyIndexY && iIndexY < BLOCK_COUNT - 1 )
{
if( 0 == g_iBlockState[iIndexY + 1][iIndexX] )
{
iEmptyIndexX = iIndexX;
iEmptyIndexY = iIndexY + 1;
}
}
// 判断是否找到空位
if( -1 == iEmptyIndexX || -1 == iEmptyIndexY )
return;
// 有空位,在二维数组里,将该索引对应的值进行交换
g_iBlockState[iEmptyIndexY][iEmptyIndexX] = g_iBlockState[iIndexY][iIndexX];
g_iBlockState[iIndexY][iIndexX] = 0;
// 对应的名字也进行交换
int iOneIndex = XYToOneIndex( iEmptyIndexX, iEmptyIndexY );
strcpy( g_szBlockName[iOneIndex], g_szBlockName[iClickIndex] );
g_szBlockName[iClickIndex][0] = '\0';
// 将该精灵移动到对应的位置
MoveSpriteToBlock( g_szBlockName[iOneIndex], iEmptyIndexX, iEmptyIndexY );
OnMouseClick(iMouseType, fMouseX, fMouseY);
}
//==========================================================================
//
// 引擎捕捉鼠标弹起消息后,将调用到本函数
// 参数 iMouseType:鼠标按键值,见 enum MouseTypes 定义
// 参数 fMouseX, fMouseY:为鼠标当前坐标
//
void dOnMouseUp( const int iMouseType, const float fMouseX, const float fMouseY )
{
// 可以在此添加游戏需要的响应函数
OnMouseUp(iMouseType, fMouseX, fMouseY);
}
//==========================================================================
//
// 引擎捕捉键盘按下消息后,将调用到本函数
// 参数 iKey:被按下的键,值见 enum KeyCodes 宏定义
// 参数 iAltPress, iShiftPress,iCtrlPress:键盘上的功能键Alt,Ctrl,Shift当前是否也处于按下状态(0未按下,1按下)
//
void dOnKeyDown( const int iKey, const int iAltPress, const int iShiftPress, const int iCtrlPress )
{
// 可以在此添加游戏需要的响应函数
if(KEY_SPACE == iKey)
{
g_GameState=1-g_GameState;
}
if(g_GameState)
{
dSetSpriteVisible("GameBegin",0);
for( iLoopY = 0; iLoopY < BLOCK_COUNT; iLoopY++ )
{
for( iLoopX = 0; iLoopX < BLOCK_COUNT; iLoopX++ )
{
iOneIndex = XYToOneIndex( iLoopX, iLoopY );
// 数组的最后一个
if( BLOCK_COUNT - 1 == iLoopX && BLOCK_COUNT - 1 == iLoopY )
{
g_iBlockState[iLoopY][iLoopX] = 0;
g_szBlockName[iOneIndex][0] = '\0';
}
else
{
// 在当前剩余未使用到的数值里随机一个出来,赋值给二维数组
iRandIndex = dRandomRange( 0, iDataCount - 1 );
g_iBlockState[iLoopY][iLoopX] = iRandData[iRandIndex];
/* 给对应的名字数组赋值。该名字的方块已经预先在地图里摆放好,因此只需要生成对应的名字即可,不用创建精灵 */
strcpy( g_szBlockName[iOneIndex], dMakeSpriteName( "PictureBlock", g_iBlockState[iLoopY][iLoopX] ) );
// 将该精灵移动到对应的位置
MoveSpriteToBlock( g_szBlockName[iOneIndex], iLoopX, iLoopY );
}
for( iLoop = iRandIndex; iLoop < iDataCount - 1; iLoop++ )
{
iRandData[iLoop] = iRandData[iLoop + 1];
}
// 剩余有效值总数减一
iDataCount--;
}
}
}
if(KEY_Q == iKey)
{
// for(int item=0; item
// {
//// char szName[100]="PictureBlock",str[10];
//// int len_1=strlen(szName),len_2=0;
//// int cmp=item+1;
//// while(cmp>0)
//// {
//// str[len_2++]=(cmp%10)+'0';
//// cmp/=10;
//// }
//// for(int item=0; item
//// {
//// szName[len_1+item]=str[len_2-1-item];
//// }
// MoveSpriteToBlock(g_szBlockName[item],item%BLOCK_COUNT,item/BLOCK_COUNT);
// }
int len=0;
for( iLoopY = 0; iLoopY < BLOCK_COUNT; iLoopY++ )
{
for( iLoopX = 0; iLoopX < BLOCK_COUNT; iLoopX++ )
{
iOneIndex = XYToOneIndex( iLoopX, iLoopY );
// 数组的最后一个
if( BLOCK_COUNT - 1 == iLoopX && BLOCK_COUNT - 1 == iLoopY )
{
g_iBlockState[iLoopY][iLoopX] = 0;
g_szBlockName[iOneIndex][0] = '\0';
}
else
{
// 在当前剩余未使用到的数值里随机一个出来,赋值给二维数组
iRandIndex = len++;
g_iBlockState[iLoopY][iLoopX] = iRandData[iRandIndex];
/* 给对应的名字数组赋值。该名字的方块已经预先在地图里摆放好,因此只需要生成对应的名字即可,不用创建精灵 */
strcpy( g_szBlockName[iOneIndex], dMakeSpriteName( "PictureBlock", g_iBlockState[iLoopY][iLoopX] ) );
// 将该精灵移动到对应的位置
MoveSpriteToBlock( g_szBlockName[iOneIndex], iLoopX, iLoopY );
}
}
}
OnKeyDown(iKey, iAltPress, iShiftPress, iCtrlPress);
}
}
//==========================================================================
//
// 引擎捕捉键盘弹起消息后,将调用到本函数
// 参数 iKey:弹起的键,值见 enum KeyCodes 宏定义
//
void dOnKeyUp( const int iKey )
{
// 可以在此添加游戏需要的响应函数
OnKeyUp(iKey);
}
//===========================================================================
//
// 引擎捕捉到精灵与精灵碰撞之后,调用此函数
// 精灵之间要产生碰撞,必须在编辑器或者代码里设置精灵发送及接受碰撞
// 参数 szSrcName:发起碰撞的精灵名字
// 参数 szTarName:被碰撞的精灵名字
//
void dOnSpriteColSprite( const char *szSrcName, const char *szTarName )
{
// 可以在此添加游戏需要的响应函数
OnSpriteColSprite(szSrcName, szTarName);
}
//===========================================================================
//
// 引擎捕捉到精灵与世界边界碰撞之后,调用此函数.
// 精灵之间要产生碰撞,必须在编辑器或者代码里设置精灵的世界边界限制
// 参数 szName:碰撞到边界的精灵名字
// 参数 iColSide:碰撞到的边界 0 左边,1 右边,2 上边,3 下边
//
void dOnSpriteColWorldLimit( const char *szName, const int iColSide )
{
// 可以在此添加游戏需要的响应函数
OnSpriteColWorldLimit(szName, iColSide);
}