![c语言程序设计-坦克大战(提高篇)(funcode环境)_第1页](http://file4.renrendoc.com/view/e7dc85e95c2c86cecd220c41be59c182/e7dc85e95c2c86cecd220c41be59c1821.gif)
![c语言程序设计-坦克大战(提高篇)(funcode环境)_第2页](http://file4.renrendoc.com/view/e7dc85e95c2c86cecd220c41be59c182/e7dc85e95c2c86cecd220c41be59c1822.gif)
![c语言程序设计-坦克大战(提高篇)(funcode环境)_第3页](http://file4.renrendoc.com/view/e7dc85e95c2c86cecd220c41be59c182/e7dc85e95c2c86cecd220c41be59c1823.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C语言课程设计--坦克大战一、游戏介绍间到,一局游戏结束。二、实验目的综合应用C语言知识和设计知识开发一款小游戏。三、实验内容初始界面如下图。按下空格键后游戏开始侧。游戏时间到,比如30秒,玩家坦克被敌方坦克摧毁,或者玩家指挥部被摧毁,一局游戏结束,游戏回到初始界面,并显示上一局的分数。[-26,[26,224,坦克也是正方形,比墙略小一点。玩家用WASDJ1玩家指挥部被坦克或者炮弹(不管玩家还是敌方)碰上,都会被摧毁。312四、实验准备本实验中可能用到的C语言标准库函数和FunCodeStdio.h函数原型 功能与返回值 参数说明与应用举例int sprintf( char把格式化的数组写入某个字*buffer,constchar符串。*format, [argument]Math.h
charszName[128];inti=0;sprintf(szName, feichong_%d”,i);将字符串”feichong_0”写入到szName中函数原型 功能与返回值 参数说明与应用举例doubleatan2(doubley,计算y/x的反正切值。doublex); 返回值:以弧度表示并介-pi到pi之间(-pi转换。String.h
floatftan=atan2((y1-y0),(x1-x0));计算通过点(x1,y1)到点(x0,y0)的连成的直线与X轴之间的夹角。函数原型 功能与返回值 参数说明与应用举extern char找出str2字符串在str1字strstr(szName,*strstr(char *str1,符串中第一次出现的位置“feichong”)!=NULLchar*str2); (不包括str2的串结束符。说明szName中包含feichong返回值:返回该位置的指针,如找不到,返回空指针。extern int比较字符串s1和s2。strcmp(const char当s1<s2时,返回*s1,constchar*s2); s1=s2=0s1>s2>0FunCodeAPI
strcmp(szName,“feichong_0”)==0说明szName与feichong_0等函数原型floatdGetScreenLeft();floatdGetScreenRight();floatdGetScreenTop();floatdGetScreenBottom();floatdGetSpritePositionX(constchar*szName);floatdGetSpritePositionY(constchar*szName);floatdSetSpritePositionX(constchar*szName);floatdSetSpritePositionY(constchar*szName);voiddSetSpritePosition(constchar*szName,constfPosX,constfloatfPosY);
功能与返回值获取屏幕左边界值获取屏幕右边界值获取屏幕上边界值获取屏幕下边界值获取精灵中心点的坐标值获取精灵中心点的坐标值设置精灵中心点的坐标值设置精灵中心点的坐标值设置精灵中心点的Y灵放置在某个指定位置。
参数说明与应用举例szName–精灵名称。所有API均相同。游戏中的精灵的名称不能相同。dSetSpritePosition(“ong_0”,0,0);将名称为”feichong_0”的精灵的中心点设置在坐标(0,0)上void 设置精灵X轴方向速dSetSpriteLinearVelocityX( constchar*szName,constfloatfVelX);void 设置精灵Y轴方向速dSetSpriteLinearVelocityY( constchar*szName,constfloatfVelY);void 设置精灵X轴和YdSetSpriteLinearVelocity(c onstchar*szName,constfloatfVelX,constfloatfVelY);floatdGetSpriteRotation(constchar*szName);
获取精灵的旋转角度
原图的角度float 设置图片的旋转角度dSetSpriteRotation(constchar*szName,floatvoid dSetTextValue(const 设置文字精灵的整char*szName,intiVal); 数值void 设置精灵可见或不可dSetSpriteVisible(const char* szName, boolbVisible);voiddShowCursor(constbool设置鼠标可见或不bShow); 见void dDeleteSprite(const char*szName);bool dIsPointInSprite(const (fPosX,fPosY)char*szName,constfloatfPosX,constfloatfPosY);bool dCloneSprite(const 复制一个精灵。char* szSrcName, const返回值:1–复制char*szTarName); 功;0–复制失败。地图中没有找到对应名称的精灵用于复制。
调整后的角度获得的旋转角度即为两张图片的角度差fRot>0,图片顺时针旋转;fRot<0,图片逆时针旋转。dSetTextValue(“score”,100);名称为score的文字精灵显示100bVisible为truefalsebShowtruefalse常用于判断一个物体是不是碰到另外一个物体做法:一般在地图上摆放一个精灵作为模板,并设置好各种属性。不仅复制图片,还复制属性。szSrcName–作为模板的精灵szTarName–新的精灵名称voiddSetSpriteWorldLimit(constchar*szName, EWorldLimit Limit,floatfLeft,constfTop,constfloatfRight,constfloatfBottom)
fLeft -左边界fTop -上边界值fRight-右边界值fBottom-下边界值Limit -统一使WORLD_LIMIT_NULLvoid 让精灵从当前位置飞dSpriteMoveTo(const char*szName,constfloatfPosX,constfloatfPosY,
fPosXXfPosYYfSpeediAutoStop:移动到终点之后是constfloatconstfloatfSpeed,const true停止falsebooliAutoStop); 不停止intdRandomRange(constint 获取一个位于[iMin,intd=dRandomRange[0,3]iMin,constintiMax); iMax]之间的随机整数d值可能为0,1,2或3五、程序初步设计构和自定义函数。有了比较清晰的思路以后,再开始开发程序。在本项目中,我们要操作的对象有6个:玩家坦克、敌方坦克、玩家子弹、敌方子弹、墙、玩家指挥部。structWeapon{charfloatfloatfloatszName[128];fPosX,fSpeedX,structWeapon{charfloatfloatfloatszName[128];fPosX,fSpeedX,fPosY;fSpeedY;fFireTime;int iHp;int iDir;//精灵名称//精灵坐标//XY//敌方坦克距下一次开炮的剩余时间//生命值//朝向:0123-左方intiType;//类型:0方Weapon*pNext;//子弹;3-敌方子弹//指向下一个节点的指针};其中,iDir和iType用不同整数表示不同含义。如果在小程序中,我们可以在代码里直接调用这些整数,但是想象一下下面情况:如果你连续写了三小时代码,你还能清晰记得1表示什么含义吗?你时不时需要找到Weapon结构体定义查看这些数字的含义,然后再引用,出错的概率有多大?如果你一不小心,在某处搞错了,比如要处理的是敌方坦克,你却引用2,需要多少时间才能把错误找出来?enumDirection{UPRIGHTenumDirection{UPRIGHTDOWN===0,1,2,//上方//右方//下方LEFTLEFT=3//左方};};enumRoleenumRole{MYTANK = 0,ENEMYTANK = 1,MYBULLET = 2,ENEMYBULLET =3//我方坦克//敌方坦克//我方子弹//敌方子弹};的时间等变量;//游戏地图,0表示此处为空,1表示此处有墙。根据游戏空间大小、墙以及坦克大小,//我们把地图分成11行,13列,每格大小刚好放一块墙。intintiMap[11][13];一些全局常量来存储某些数值。constfloatGAME_TIME=30.f;//一局游戏时间constfloatCREATE_TANK_TIME=5.f;//每批次生成坦克的时间间隔constfloatTANK_SPEED=5.f;//坦克速度constfloatBULLET_SPEED=8.f;//子弹速度constfloatFIRE_TIME=2.f;//坦克开炮时间间隔constfloatWORLD_LEFT=-26.f;//游戏场景边界左值constfloatWORLD_TOP=-22.f;//游戏场景边界左值constfloatWORLD_RIGHT=26.f;//游戏场景边界左值constfloatWORLD_BOTTOM=22.f;//游戏场景边界左值程序本身由一个main.cpp7WinMain6碰撞。AddToListDeleteNodeFindeNodeDeleteListAddToListDeleteNodeFindeNodeDeleteList//往链表里添加一个节点;//从链表里删除一个节点;//从链表里查找一个节点;//删除整个链表。一局游戏结束,我们需要把本局游戏中还没删除的精灵全部删除,从而保持下一局游戏LoadMapMoveMyTankCreateEnemyTanksOnFireLoadMapMoveMyTankCreateEnemyTanksOnFire//载入地图//玩家坦克运动//敌方坦克生成//坦克发射炮弹也可能发生碰撞,所以需要同时设置“发送碰撞”和“接受碰撞”的属性参与玩家坦克敌方坦克玩家子弹敌方子弹墙玩家指挥世界边方反应方发送接受发送发送接受发送接受部接受界玩家坦克发送无游戏结束无游戏结束停止游戏结束停止敌方坦克接受停止后面一辆调头;删除不处理停止游戏结束针一发送对撞,都调头个方向玩家子弹发送无删除加分无删除删除游戏结束删除接受发送删除删除删除均删除删除游戏结束删除墙接受不处理不处理删除删除无无无玩家指挥部接受游戏结束游戏结束游戏结束游戏结束无无无根据上面表格,我们可以定义5个碰撞函数OnMyTankColOtherOnMyTankColOtherOnEnemyTankColOtherOnBulletColOther//玩家坦克与其他精灵碰撞//敌方坦克与其他精灵碰撞//子弹与其他精灵碰撞。子弹碰上其他精灵,本身都是被OnWallColOther//删除,比较简单,因此两种子弹合并起来//墙与其他精灵碰撞OnGoalColOtherOnGoalColOther//玩家指挥部与其他精灵碰撞其中,colcollision(碰撞)的缩写。精灵与世界边界的碰撞,比较简单,我们直接在dOnSpriteColWorldLimit函数中完成。会根据细节进一步完善。六、实验指南实验一游戏开始和结束【实验内容】步骤一、按空格键,游戏开始3步骤二、按WASD步骤三、游戏开始后,右上角实时显示剩余时间。步骤四、当超过30秒,游戏结束,重新显示“空格开始“字样,游戏时间设为0,坦克回到初始位置。【实验思路】在List.h中定义Weapon结构体和两个枚举类型。定义全局变量和全局常量。定义MoveMyTank函数,控制玩家坦克上下左右移动。【实验指导】1、创建“”工程,并且添加List.hList.h中定义Weapon和Rol、Direction两个枚举类型。参考“程序初步设计2义我们控制的坦克精灵的对象指针;3、dOnKeyDown戏开始。此时应该“空格开始”消失,显示本局的游戏时间以及得分等信息,4、运行程序,按下空格键,看看游戏是否按要求运行。5、游戏开始后,开始计时。游戏时间到,一局游戏结束,游戏恢复到初始界面。要判断游戏时间,我们需要在WinMain的主循环中进行处理。//游戏主循环while(dEngineMainLoop()){//获取游戏屏幕刷新一次的时间间距float fTimeDelta= dGetTimeDelta();if(g_bStart)if(g_bStart){g_fGameTime-=fTimeDelta;if(g_fGameTime>0.f)//{}else//一局游戏结束if(strcmp(szName,g_pMyTank->szName)==0)//玩家坦克if(strcmp(szName,g_pMyTank->szName)==0)//玩家坦克{g_bStart=false;}}else//游戏结束后处理{}}6、一局游戏开始后,在WinMain函数中的主循环里,通过dSetTextValue把(int)g_fGameTime的数值显示在名为“时间(显示整秒的时间。7、一局游戏进行中,每循环一次,g_fGameTime减去一次刷屏的时间。当g_fGameTime≤0,否则下一局就不能正确判断游戏开始或结束。8、我们定义一个MoveMyTankWA度;按下S键,设置向下的速度,按下D为0。此外,按下键盘时,还需要相应设置坦克朝向iDir如果函数定义写在函数调用之后,需要在函数调用前面进行声明。voidMoveMyTank(intiKey,intiPress){}9、完成函数,我们在dOnKeyDowndOnKeyUp//按下键盘if(g_bStart)//按下键盘if(g_bStart)//一局游戏进行中{if(iKey==KEY_W||iKey==KEY_A||iKey==KEY_S||iKey==KEY_D{MoveMyTank(iKey,1);}}//松开键盘//松开键盘if(g_bStart){if(iKey==KEY_W||iKey==KEY_A||iKey==KEY_S||iKey==KEY_D){MoveMyTank(iKey,0);}}10、玩家坦克开到边界时,让它停止运动。我们在dOnSpriteColWorldLimit函数中,设设置玩家坦克速度为0。{dSetSpriteLinearVelocity(g_pMyTank->szName,0.f,0.f);dSetSpriteLinearVelocity(g_pMyTank->szName,0.f,0.f);}11实验二玩家坦克在街道中运行【实验内容】步骤一、一局游戏开始时载入地图。步骤二、一局游戏结束后删除地图。步骤三、玩家坦克碰到墙的话,不能继续前行。【实验思路】0,说明此处为空;值为1游戏开始后载入地图,但只能载入一次。如果不停载入,会占有大量资源。游戏结束时,需要把地图中墙都删除。响应。【实验指导】1、增加新的全局变量定义intg_iWallCount = 0; //记录墙的数intg_iMap[11][13]; //地图数组墙的数量。intiMap[11][13]={{0,0,0,0,0,0,0,0,0,0,0,0,0},{0,1,0,1,0,1,0,1,0,1,0,1,0},{0,1,0,1,0,1,0,1,0,1,0,1,0},{0,1,0,1,0,1,1,1,0,1,0,1,0},intiMap[11][13]={{0,0,0,0,0,0,0,0,0,0,0,0,0},{0,1,0,1,0,1,0,1,0,1,0,1,0},{0,1,0,1,0,1,0,1,0,1,0,1,0},{0,1,0,1,0,1,1,1,0,1,0,1,0},{0,1,0,1,0,1,0,1,0,1,0,1,0},{0,0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,1,1,1,0,0,0,0,0},{0,1,0,1,0,0,0,0,0,1,0,1,0},{0,1,0,1,0,0,0,0,0,1,0,1,0},{0,1,0,1,0,1,1,1,0,1,0,1,0},{0,0,0,0,0,1,0,1,0,0,0,0,0},};};3、给墙命名,计算墙的数量,并设置墙为“接受碰撞”属性。并将指挥部设置在第11行第7列。for(i=0;i<11;i++)for(i=0;i<11;i++){for(j=0;j<13;j++){if(g_iMap[i][j]==1){sprintf(szName,"wall%d",g_iWallCount++);dCloneSprite("wall",szName);//将wall设为接受碰撞dSetSpriteCollisionReceive(szName,true);x=-24+4*j;y=-20+4*i;x=-24+4*j;y=-20+4*i;dSetSpritePosition(szName,x,y);}}}//指挥部设置在第11行第7列dSetSpritePosition("goal",0.f,20);dSetSpriteVisible("goal",true);4每次循环都载入一次地图,我们设置一个静态布尔变量来控制。intiLoad=1//是否载入地图while(dEngineMainLoop()){…if(g_iStart)intiLoad=1//是否载入地图while(dEngineMainLoop()){…if(g_iStart){if(iLoad)//一局游戏只需要载入一次地图即可{//载入地图LoadMap();iLoad=0;}…}}charszName[128];for(inti=0;i<g_iWallCount;i++){{sprintf(szName,"wall%d",i);dDeleteSprite(szName);}g_iWallCount=0;iLoad=t1;//设置指挥所不可见dSetSpriteVisible("goal",0);6iMap115列,在dOnKeyDownvoidOnMyTankColOther(constchar*szMyTankName,voidOnMyTankColOther(constchar*szMyTankName,constchar*szOtherName){//如果碰到墙上if(strstr(szOtherName,"wall")!=NULL)dSetSpriteLinearVelocity(szMyTankName,0.f,0.f);}灵碰撞的函数。8、我们在dOnSpriteColSprite函数中调用OnMyTankColOther函数。因为,玩家坦克只具备“发送碰撞”属性,因此它的名称只能传递给szSrcName参数。实验三玩家坦克射击【实验内容】步骤一、玩家按下j键,坦克发送炮弹;步骤二、创建链表,用链表管理炮弹;步骤三、子弹击中墙,将墙摧毁;子弹击中目标,游戏结束。【实验思路】度,并将子弹设置在坦克前面一些。子弹碰到墙的时候,删除子弹和墙。子弹击中目标,删除子弹和目标,游戏结束。应删除节点。游戏结束时,删除所有剩余的子弹。【实验指导】1、增加几个全局变量和全局常量的定义。intintconstg_iNumfloat=0;//记录全部精灵的数目,用来给精灵命名BULLET_SPEED=8.f;//子弹速度2、自定义一个函数,OnFire用于完成坦克发射子弹功能。玩家坦克发射子弹,和敌voidOnFire(char*szName,intiType){voidOnFire(char*szName,intiType){}3、在dOnKeyDown中增加对OnFireJ4、运行程序,按J键,看是否能发射子弹。5iHp0需要删除的精灵的iHp0,最后再统一将需要删除的精灵删除。//子弹与其他精灵碰撞void OnBulletColOther(constchar*szBulletName,//子弹与其他精灵碰撞void OnBulletColOther(constchar*szBulletName,constchar*szOtherName){}判断是否与墙碰撞,是的话,将子弹iHp设为0。所有的墙的名称中都包含wall,通过判断szOherName中是否包含该字符串判断是否是墙。//墙与其他精灵碰撞//墙与其他精灵碰撞void{}OnWallColOther(constchar*szWallName,constchar*szOtherName)判断是否与子弹碰撞,是的话,删除墙。所有的子弹的名称中都包含bullet,通过判断szOherName中是否包含该字符串判断是否是子弹。7、在dOnSpriteColSprite撞”属性,因此只需要判断szTarName是否包含wall字符串。子弹具有“发射碰szSrcNameszTarNamebullet8、运行程序,按J键发射子弹。朝墙设计,看是否摧毁墙。9能存在大量bug。10、我们在List.cpp中实现链表操作函数的定义。把链表操作函数和游戏逻辑函数分开,可以让程序结构更清晰。11、定义一个链表头结点:Weapon*g_pHead=NULL;voidAddToList(WeaponvoidAddToList(Weapon*pSprite){Weapon*pTemp=(Weapon*)malloc(sizeof(Weapon))Weapon*pTemp=(Weapon*)malloc(sizeof(Weapon))strcpy(pTemp->szName,pSprite->szName);pTemp->fPosX=pSprite->fPosX;pTemp->fPosY=pSprite->fPosY;pTemp->fSpeedX=pSprite->fSpeedX;pTemp->fSpeedY=pSprite->fSpeedY;pTemp->iDir=pSprite->iDir;pTemp->iType=pSprite->iType;pTemp->pNext=NULL;Weapon*pNode=Weapon*pNode=g_pHead;if(g_pHeadif(g_pHead==NULL)//表头为空,说明加入的是第一个节点{g_pHead=pTemp;}else{//循环读到链表的最后一个节点while(pNode->pNext!=NULL){pNode=pNode->pNext;}pNode->pNext=pTemp;}}13、参考AddToList函数,完成查找结点、删除结点以及删除整个链表的操作。//根据名字获取精灵节点//根据名字获取精灵节点Weapon*FindNode(constchar*szName{}//根据名字删除精灵节点voidDeleteNode(constchar*szName){}//删除整个链表voidDeleteList(){}删除链表时,一般也需要删除界面上相应的精灵,我们在DeleteList函数中完成此功能相应比较容易。14、完成链表操作函数后,我们需要在几个地方进行完善。子弹是通过OnFire发射出来,因此,我们需要在该函数中把子弹节点加入到链表中。子弹与其他精灵碰撞时,会被删除。我们在OnBulletColOther函数中删除该子弹精灵对应链表中的节点。子弹与世界边界碰撞时,也会被删除。我们在dOnSpriteColSprite函数中删除该子弹精灵对应链表中的节点。此通过删除链表就可以了。15LoadMapOnGoalColOther戏都结束。所以,无需做任何判断,只要把g_bStartfalse。16游戏时间并没有变为0。实验四敌方坦克产生与运动【实验内容】有墙。步骤二、敌方坦克遇到墙时停下来。步骤三、敌方坦克遇到边界调头往回走。步骤四、敌方坦克碰到运动中的敌方坦克(这种情况只能是迎头碰上(去,运动的敌方坦克调头。步骤五、敌方坦克碰上我方坦克都被摧毁,游戏结束。步骤六、敌方坦克每隔一段时间,就顺时针变化一个方向,继续前进。【实验思路】敌方坦克生成时间,调用该函数。完善敌方坦克、墙与、我方坦克其他精灵碰撞的函数。增加敌方坦克与世界边界碰撞的处理。定义一个函数专门处理敌方坦克的运动,在主函数中调用。【实验指导】floatg_fCreateTimefloatg_fCreateTime=const
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 明确责任的工作目标设定计划
- 如何提升财务团队的协作效率计划
- 2025年鞋用乳液胶粘剂项目合作计划书
- 2025年医用冷疗项目发展计划
- 2025年其它核材料及相关特殊材料合作协议书
- 远程在线教育平台学习免责协议
- 电动汽车充电桩安装施工合同
- Rac-Ganoderic-acid-C2-生命科学试剂-MCE
- 财务顾问聘用协议
- 工作总结写作培训
- 大学生家长陪读承诺书
- 安全生产事故调查与案例分析(第3版)课件 吕淑然 第5章 事故案例评析
- 学生综合素质评定与职业规划的关联性分析
- 2025云南省贵金属新材料控股集团限公司面向高校毕业生专项招聘144人高频重点提升(共500题)附带答案详解
- 香港及内地传真号码
- 湖北中烟工业限责任公司2025年招聘(技术类和业务类岗位)【43人】高频重点提升(共500题)附带答案详解
- 2024-2025学年成都市成华区七年级上英语期末考试题(含答案)
- 2025年山西杏花村汾酒集团限责任公司人才招聘71名高频重点提升(共500题)附带答案详解
- 石家庄市长安区学年三年级数学第一学期期末检测试题含解析
- 2025年中国一汽招聘笔试参考题库含答案解析
- 特殊家长课后沟通技巧培训
评论
0/150
提交评论