“黄金矿工”实验报告
游戏截图
图一:开始游戏
图二:矿工准备就绪
图三:矿工在努力采金矿
功能描述:
玩家通过键盘的按键控制矿工抓取金块,将钩子碰触到的金块抓取过来。
1. 进入游戏,初始界面出现“空格开始”。
2. 单击键盘上的空格键开始游戏, “空格开始”精灵消失,同时出现20块金块,大小有三个尺寸,位置是随机的。
3. 钩子左右摆动,玩家单击键盘上的上下左右键中的下方向键控制矿工伸出长钩,抓取金子
4. 获取到金子往回拉后,直到回到钩子初始处,矿工恢复静止,钩子上的金块消失,钩子继续左右摇摆,直到玩家再次单击向下方向键。
5. 如果钩子没有碰触到金子,而是碰触到左右和下的边界,则钩子保持原来的速度往回收。
6. 如果玩家将所有金子抓取完,游戏返回初始界面。
流程图:
数据结构:
1. g_iHookRotToLeft表示钩子当前是往左摆动还是往右摆动
2. g_fHookRotation表示钩子当前转动的朝向
3. g_fHookRotation表示钩子当前角度
4. g_iGoldCount表示金矿数量
5. g_iGameState表示游戏状态,0——游戏初始化,1——伸出钩子,2——回收钩子
6. flag控制控制金块的初始化,初始值为1
7. lag表示钩子是否捉住金块的状态,初始值为1
8. iSize表示金块大小的变量
9. iPosX,iPosY表示金块的位置
算法描述:
有20块金块,储存在szGotGoldName数组里,位置储存在dSetSpritePosition里。
1.游戏状态g_iGameState分为四种状态,,3——游戏初始化,0——表示游戏进行中,1——伸出钩子,2——回收钩子:
3à 0的转换是“空格开始”;
0 à 1的转换是按下“↓”键;
1à2 的转换是钩子钩住金块或者碰到边界;
当3à 0时,游戏开始随机生成20块金块,钩子开始转动;
当0à1时,钩子伸出
当1à2,钩子原速度返回
2. 当游戏状态g_iGameState由3à 0,生成金子,flag由1à0,金子停止生成。
3.当钩子捉到金子,游戏状态g_iGameState由1à 2,lag由1à2,金子数量g_iGoldCount减少一个。当g_iGoldCount变成0,flag由0à1,金子重新进入初始化。
源代码
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#include "CommonAPI.h"
#include "stdio.h"
int g_fGoldBornMinX = 0;
int g_fGoldBornMaxX = 0;
int g_fGoldBornMinY = 0;
int g_fGoldBornMaxY = 0;
int g_iGoldCount = 20 ;
float g_fHookRotation = 0.f;
int g_iGameState=3;
float g_fEmptyHookSpeed = 15.f;
float fTimeDelta;
float g_fHookStartPosX; //存储钩子的初始X位置
float g_fHookStartPosY; //存储钩子的初始Y位置
char szGotGoldName[20] ; //当前抓到金子的名称
int flag=1;
int lag=1;
///////////////////////////////////////////////////////////////////////////////////////////
//
// 主函数入口
//
//////////////////////////////////////////////////////////////////////////////////////////
int PASCAL WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// 初始化游戏引擎
if( !dInitGameEngine( hInstance, lpCmdLine ) )
return 0;
// 游戏初始化代码
dSetWindowTitle("黄金矿工");
g_fGoldBornMinX = dGetScreenLeft() + 5; //金子左边界
g_fGoldBornMaxX = dGetScreenRight() - 5; //金子右边界
g_fGoldBornMinY = dGetScreenTop() + 20; //金子上边界
g_fGoldBornMaxY = dGetScreenBottom() - 5; //金子下边界
g_fHookStartPosX = dGetSpritePositionX("GoldHook"); //获取钩子的初始X坐标
g_fHookStartPosY = dGetSpritePositionY("GoldHook"); //获取钩子的初始Y坐标
dSetSpriteCollisionSend("goldHook", 1);
dSetSpriteCollisionReceive("goldTemplate", 1);
//生成金子
int iLoop = 0; //循环变量控制
int iSize = 4, iPosX = 0, iPosY = 0; //iSize表示金块大小的变量
const float fRotateSpeed = 45.f; // 摇摆速度,单位 度/秒
int iHookRotToLeft = 1; //钩子摆动的方向:1 ← ;0 →
dSetWindowTitle("Lesson");
// 引擎主循环,处理屏幕图像刷新等工作
while( dEngineMainLoop() )
{
// 获取两次调用之间的时间差,传递给游戏逻辑处理
float fTimeDelta = dGetTimeDelta();
// 执行游戏主循环
if(g_iGameState == 0)
{
float fThisRotate = fRotateSpeed * fTimeDelta;
if( iHookRotToLeft )
{
g_fHookRotation += fThisRotate;
if( g_fHookRotation >= 180.f )
{
g_fHookRotation = 180.f;
iHookRotToLeft = 0;
}
}
else
{
g_fHookRotation -= fThisRotate;
if( g_fHookRotation <= 0.f )
{
g_fHookRotation = 0.f;
iHookRotToLeft = 1;
}
}
dSetSpriteRotation("GoldHook",g_fHookRotation);
}
else if(g_iGameState == 2)
{
if(flag){
for( iLoop = 0; iLoop < g_iGoldCount; iLoop++ )
{
if( iLoop < 10 ) //生成10个小金块,大小为4
{
iSize = 4;
}
else if( iLoop >= 10 && iLoop < 16 ) //生成6个中金块,大小为6
{
iSize = 6;
}
else //生成4个大金块,大小为8
{
iSize = 8;
}
//初始化金子精灵实例
char* tmpName;
tmpName=dMakeSpriteName("GoldBlock",iLoop); //生成金块名字
dCloneSprite("goldTemplate",tmpName);
dSetSpriteWidth(tmpName,(float)iSize); //设置金块的宽度
dSetSpriteHeight(tmpName,(float)iSize); //设置金块的高度
//设置金子精灵位置
iPosX = dRandomRange(g_fGoldBornMinX, g_fGoldBornMaxX);
iPosY = dRandomRange(g_fGoldBornMinY, g_fGoldBornMaxY);
dSetSpritePosition(tmpName,(float)iPosX, (float)iPosY);
flag=0;}
}
//获取钩子X方向的速度
float fSpeedX = dGetSpriteLinearVelocityX("GoldHook");
//获取钩子Y方向的速度
float fSpeedY = dGetSpriteLinearVelocityY("GoldHook");
//当速度接近为0时,即可判定其已到达初始点
if( fSpeedX < 0.00001f && fSpeedX > -0.00001f && fSpeedY < 0.00001f && fSpeedY > -0.00001f )
{
//解除金块与钩子的锚定
dSpriteDismount(szGotGoldName);
//删除获取的金块
dDeleteSprite(szGotGoldName);
g_fEmptyHookSpeed = 15.f;
if( lag==2)
{
g_iGoldCount=g_iGoldCount-1;
lag=1;
}
//回拉结束,设定状态为0
g_iGameState = 0;
//播放矿工的动画,即准备拉金子的动画
dAnimateSpritePlayAnimation("GoldMan","GolderManAnimation2", 0 ); }
}
// 播放挖金者的动作(恢复初始守候动作)
//dAnimateSpritePlayAnimation( "GoldMan", "GolderManAnimation2", 0 );
if(g_iGoldCount==0)
{
dSetSpriteVisible("GameBegin",1);
flag=1;
g_iGoldCount = 20;
}
// 首先,从矿工精灵上获取一个缆绳链接点作为绳子的起始点(该链接点在编辑器里编辑好)
float fStartX = dGetSpriteLinkPointPosX("GoldMan",1);
float fStartY = dGetSpriteLinkPointPosY("GoldMan",1);
// 绳子终点在钩子精灵上获取(该链接点在编辑器里编辑好)
float fEndX = dGetSpriteLinkPointPosX("GoldHook",1);
float fEndY = dGetSpriteLinkPointPosY("GoldHook",1);
// 在这两点之间划线.线的颜色红绿蓝值都为50,即灰色;255表示不透明,2.0f表示线的粗细, 0表示所在的层
dDrawLine(fStartX, fStartY, fEndX, fEndY, 2.f, 0, 50, 50, 50, 255 );
};
// 关闭游戏引擎
dShutdownGameEngine();
return 0;
}
//==========================================================================
//
// 引擎捕捉鼠标移动消息后,将调用到本函数
void dOnMouseMove( const float fMouseX, const float fMouseY )
{
// 可以在此添加游戏需要的响应函数
}
//==========================================================================
//
// 引擎捕捉鼠标点击消息后,将调用到本函数
void dOnMouseClick( const int iMouseType, const float fMouseX, const float fMouseY )
{
// 可以在此添加游戏需要的响应函数
}
//==========================================================================
//
// 引擎捕捉键盘按下消息后,将调用到本函数
// iAltPress iShiftPress iCtrlPress 分别为判断Shift,Alt,Ctrl当前是否也处于按下状态。比如可以判断Ctrl+E组合键
void dOnKeyDown( const int iKey, const int iAltPress, const int iShiftPress, const int iCtrlPress )
{
// 可以在此添加游戏需要的响应函数
if(iKey==KEY_SPACE )
{
g_iGameState = 2; // 初始化之后,将游戏状态设置为进行中
dSetSpriteVisible("GameBegin",0);
}
if( iKey == KEY_DOWN )
{
//按下↓并且游戏状态为 "1"
g_iGameState = 1; //置游戏状态为1,可用于控制钩子是否摆动
// 以当前朝向给钩子一个向前的速度
dSetSpriteLinearVelocityPolar("GoldHook",g_fEmptyHookSpeed, g_fHookRotation);
// 播放挖金者的动作(一个胳膊往下压的动作)
dAnimateSpritePlayAnimation("GoldMan","GolderManAnimation1", 1);
//0 表示播放一次,这里胳膊往下压就是一次
}
}
//==========================================================================
//
// 引擎捕捉键盘弹起消息后,将调用到本函数
void dOnKeyUp( const int iKey )
{
// 可以在此添加游戏需要的响应函数
}
//===========================================================================
//
// 引擎捕捉到精灵与精灵碰撞之后,调用此函数
void dOnSpriteColSprite( const char *szSrcName, const char *szTarName )
{
int iSize;
// 发起者为GoldHook,接受者含有GoldBlock字段
if(strcmp(szSrcName,"GoldHook")== 1 && strstr(szTarName,"GoldBlock")!=NULL )
{
dSpriteMountToSpriteLinkPoint( szTarName, "GoldHook", 2 );//将金块锚定在钩子上
// 找到哪个是金子的名字
const char *szGoldName = NULL;
if( strstr( szSrcName, "GoldBlock" ) )
szGoldName = szSrcName;
else if( strstr( szTarName, "GoldBlock" ) )
szGoldName = szTarName;
else
return;
// 算法:之前设置的金子大小为4,6,8,用10减去该大小再除以10,得到3个小// 数:0.6,0.4,0.2.该小数乘以空钩子的速度即得到挂接不同金子后的实际速度
float fWidth = dGetSpriteWidth( szGoldName );
float fSpeed = ((10.f - fWidth) / 10.f) * g_fEmptyHookSpeed;
// 钩子往初始位置移动
dSpriteMoveTo( "GoldHook", g_fHookStartPosX, g_fHookStartPosY, fSpeed, 1);
// 播放挖金者的动作(胳膊来回动的动作)
dAnimateSpritePlayAnimation( "GoldMan", "GolderManAnimation3", 0 );
strcpy(szGotGoldName,szTarName); //复制并保存当前抓取到金块的名称
g_iGameState = 2;
lag=2;
}
}
//===========================================================================
//
// 引擎捕捉到精灵与世界边界碰撞之后,调用此函数.
// iColSide : 0 左边,1 右边,2 上边,3 下边
void dOnSpriteColWorldLimit( const char *szName, const int iColSide )
{
if(strcmp(szName,"GoldHook")!=0)
{
//碰到边界的为钩子时
dSpriteMoveTo(szName,g_fHookStartPosX, g_fHookStartPosY, g_fEmptyHookSpeed, 1);
dAnimateSpritePlayAnimation("GoldMan","GolderManAnimation3", 1 );
//同样设置为回拉,只是没有碰到金子
g_iGameState = 2;
lag=1;
}
}