程序设计实训报告
[黄金矿工]
一、系统界面
图1 开始游戏
图2,游戏进行时
二、功能描述
玩家通过键盘的按键控制矿工抓取金块,将钩子碰触到的金块抓取过来。
要求如下:
1. 游戏的初始界面如图1,单机键盘上的空格键进入游戏,进入后界面如图2,金块的总数是20,大小位置是随机的。
2. 在没有抓取状态下,钩子左右摆动,此时矿工的是静止的。当钩子摆动到一定角度,玩家可以单击键盘上的上下左右键中的下方向键控制矿工伸出长钩,抓取金子,此时矿工是向下摇动转轴。获取到金子往回拉后,矿工是不断转动转轴,知道金子拉动到钩子初始处,矿工恢复静止,钩子继续左右摇摆,直到玩家再次单击向下方向键。
3. 伸出的钩子如果碰触到金子,则钩子和金子一起往回拉,回收的速度根据抓取到的金子的大小变化而变化,金子越大,回拉的速度越慢,反之亦然。如果钩子没有碰触到金子,而是碰触到左右和下的边界,则钩子保持原来的速度往回收。
4. 抓取到的金子拉回到转轴处消失,此时金子数目减少一个。如果玩家将所有金子抓取完,游戏返回到如图1的初始界面。
三、流程图
否 是
四、数据结构
(说明:主要写用到的各类型的全局变量、含义)
1. g_iGameState表示游戏状态 ,初始状态g_iGameState=0.
2. g_fHookStartPosX存储钩子的初始X位置。
3. n 控制金块生成,初始化为1.
4. g_fHookStartPosY存储钩子的初始X位置。
5. szGotGoldName[20] 当前抓到金子的名称
6. count抓取到金子的个数。
7. iSize金子的尺寸。
8. g_fHookRotation钩子与地面的夹角。
9. g_iHookRotToLeft控制钩子转向,1——从右向左 2——从左向右。
10. g_fGoldBornMinX, g_fGoldBornMaxX, g_fGoldBornMinY, g_fGoldBornMaxY分别代表左右上下的值。
11. g_iGoldCount金子的个数,初始化为20.
12. g_fEmptyHookSpeed 钩子发出时速度。
13. fRotateSpeed钩子旋转速度。
五、算法描述
游戏状态g_iGameState分为三种状态0,1,2 ,其中0表示游戏结束状态,1表示游戏初始化,2则表示游戏运行状态;
键盘控制:
1. 空格按下精灵隐藏
2. 游戏有结束状态转为初始化状态
3. 钩子开始转动,金块也显示出来
4. 利用A,D键控制钩子左右摇摆或“↓”释放钩子
5. 游戏自动进入运行状态
钩子旋转:
1. 利用fHookRotatio记录钩子的角度,flag控制钩子的旋转方向,fRotateSpeed控制钩子的摇摆速度
2. 利用fThisRotate = fRotateSpeed * fTimeDelta和g_fHookRotation += fThisRotate使钩子角度发生变化
3. 利用A键使钩子角度向左增加30度(源代码g_fHookRotation+=30)利用D键使钩子角度向右增加30度(源代码g_fHookRotation-=30)
4. 设置钩子旋转的角度范围0~180
5. 使用dSetSpriteRotation函数控制钩子的位置
金块显示:
1. iSize标记金块尺寸,g_iGoldCount标记金块个数
2. 使用名为dMakeSpriteName的数组储存金块
3. 使用dCloneSprite复制金块
4. 使用dSetSpriteWidth和dSetSpriteHeight分别控制金块的宽度和高度
5. 使用dSetSpritePosition函数设置金块位置
绳子连接:
使用dDrawLine函数将钩子与矿工用绳子连接起来并设置绳子的粗细和颜色
精灵碰撞:
调用dOnSpriteColSprite函数实现钩子与金块碰撞之后的连接拉回
边界碰撞:
调用dOnSpriteColWorldLimit函数实现钩子与边界碰撞之后的弹回
六、源代码
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#include "CommonAPI.h"
int g_iGameState=0;//游戏状态
int n=1;//控制生成金子的循环
int count=0;记录钩子抓取金子的数量
int iSize=4;//金子的大小
int flag=1;//控制钩子是否旋转
float g_fHookRotation = 0.f; //钩子与地面的夹角
int g_iHookRotToLeft=1;//控制金子旋转方向
int g_fHookRotatio=0;金子的角度
int g_fGoldBornMinX = 0;
int g_fGoldBornMaxX = 0;
int g_fGoldBornMinY = 0;
int g_fGoldBornMaxY = 0;//边界的值
int g_iGoldCount = 20;//金子的数量
float g_fEmptyHookSpeed = 30.f;//钩子的数量
float fRotateSpeed = 40.f; // 摇摆速度,单位 度/秒
int iHookRotToLeft = 1; //钩子摆动的方向:1 ← ;0 →
float g_fHookStartPosX; //存储钩子的初始X位置
float g_fHookStartPosY; //存储钩子的初始Y位置
char szGotGoldName[20] ; //当前抓到金子的名称
void GameInit(void)
{
dSetSpriteVisible("GameBegin",0);//隐藏精灵
if(n==1)
{
int iLoop = 0; //循环变量控制
int iPosX = 0, iPosY = 0; //iSize表示金块大小的变量
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);
}
n++;
}
}
void GameRun(float fTimeDelta )
{
if(flag==1)
{
float fThisRotate = fRotateSpeed * fTimeDelta; // 本次旋转的角度
if( iHookRotToLeft )
{ //向左转,度数不断变大
g_fHookRotation += fThisRotate;
if( g_fHookRotation >= 180.f )
{ //大于180,置为向右转,即0
g_fHookRotation = 180.f;
iHookRotToLeft = 0;
}
}
else
{ //向右转,度数不断变小
g_fHookRotation -= fThisRotate; //小于0,置为向左转,即 1
if( g_fHookRotation <= 0.f )
{
g_fHookRotation = 0.f;
iHookRotToLeft = 1;
}
}
dSetSpriteRotation("GoldHook",g_fHookRotation); //设置钩子的当前角度
}
// 首先,从矿工精灵上获取一个缆绳链接点作为绳子的起始点(该链接点在编辑器里编辑好)
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 );
}
void GameEnd()
{
n=1;
dSetSpriteVisible("GameBegin",1);//使游戏回到结束状态
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// 主函数入口
//
//////////////////////////////////////////////////////////////////////////////////////////
int PASCAL WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// 初始化游戏引擎
if( !dInitGameEngine( hInstance, lpCmdLine ) )
return 0;
// 游戏初始化代码
dSetWindowTitle("Lesson");
g_iGoldCount=20; //金子数量
g_fGoldBornMinX = dGetScreenLeft() + 5; //金子左边界
g_fGoldBornMaxX = dGetScreenRight() - 5; //金子右边界
g_fGoldBornMinY = dGetScreenTop() + 20; //金子上边界
g_fGoldBornMaxY = dGetScreenBottom() - 5; //金子下边界
dSetSpriteCollisionSend("goldHook", 1);
dSetSpriteCollisionReceive("goldTemplate", 1);
g_fHookStartPosX = dGetSpritePositionX("GoldHook"); //获取钩子的初始X坐标
g_fHookStartPosY = dGetSpritePositionY("GoldHook"); //获取钩子的初始Y坐标
// 引擎主循环,处理屏幕图像刷新等工作
while( dEngineMainLoop() )
{
// 获取两次调用之间的时间差,传递给游戏逻辑处理
float fTimeDelta = dGetTimeDelta();
switch( g_iGameState )
{
// 初始化游戏,清空上一局相关数据
case 1:
{
GameInit();
g_iGameState = 2; // 初始化之后,将游戏状态设置为进行中
}
break;
// 游戏进行中,处理各种游戏逻辑
case 2:
{
// 金子数量大于0的时候,继续游戏
if( g_iGoldCount > 0 )
{
GameRun( fTimeDelta );
}
else
{
// 游戏结束。调用游戏结数函数并把游戏状态修改为结束状态
g_iGameState = 0;
GameEnd();
}
}
break;
// 游戏结束/等待按空格键开始
case 0:
default:
break;
};
dSetTextValue("score",count);
// 执行游戏主循环
};
// 关闭游戏引擎
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==0)
g_iGameState=1;
if( KEY_DOWN == iKey)
{ //按下↓并且游戏状态为 "1"
flag=0;
// 以当前朝向给钩子一个向前的速度
dSetSpriteLinearVelocityPolar("GoldHook",g_fEmptyHookSpeed, g_fHookRotation);
// 播放挖金者的动作(一个胳膊往下压的动作)
dAnimateSpritePlayAnimation("GoldMan","GolderManAnimation1", 0);
//0 表示播放一次,这里胳膊往下压就是一次
}
if(iKey==KEY_A)
g_fHookRotation+=30;//按下A键使钩子向左移动30度
if(iKey==KEY_D) g_fHookRotation-=30;//按下D键使钩子向右移动30度
}
//==========================================================================
//
// 引擎捕捉键盘弹起消息后,将调用到本函数
void dOnKeyUp( const int iKey )
{
// 可以在此添加游戏需要的响应函数
}
//===========================================================================
//
// 引擎捕捉到精灵与精灵碰撞之后,调用此函数
void dOnSpriteColSprite( const char *szSrcName, const char *szTarName )
{
// 发起者为GoldHook,接受者含有GoldBlock字段
dSpriteMountToSpriteLinkPoint( szTarName, "GoldHook", 2 );//将金块锚定在钩子上
flag=0;
iSize=dGetSpriteWidth( szTarName );
dSpriteMoveTo("GoldHook",g_fHookStartPosX, g_fHookStartPosY, ((10.f - iSize) / 10.f) * g_fEmptyHookSpeed, 1);
//使钩子向初始位置移动,即会拉
dAnimateSpritePlayAnimation("GoldMan","GolderManAnimation3", 1 ); //播放拉金块的动作
strcpy(szGotGoldName,szTarName); //复制并保存当前抓取到金块的名称
if(g_iGameState == 2)
{
//获取钩子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);
//删除获取的金块
g_iGoldCount--;
count++;
dDeleteSprite(szGotGoldName);
//回拉结束,设定状态为0
g_iGameState = 0;
//播放矿工的动画,即准备拉金子的动画
dAnimateSpritePlayAnimation("GoldMan","GolderManAnimation2", 0 );
g_iGameState =2;
flag=1;
}
}
}
//===========================================================================
//
// 引擎捕捉到精灵与世界边界碰撞之后,调用此函数.
// iColSide : 0 左边,1 右边,2 上边,3 下边
void dOnSpriteColWorldLimit( const char *szName, const int iColSide )
{
flag=0;
//碰到边界的为钩子时
dSpriteMoveTo(szName,g_fHookStartPosX, g_fHookStartPosY, g_fEmptyHookSpeed, 1);
dAnimateSpritePlayAnimation("GoldMan","GolderManAnimation2", 1 );
//同样设置为回拉,只是没有碰到金子
g_iGameState = 2;
flag=1;
}
}