每天一个C语言小项目,提升你的编程能力!
贪吃蛇游戏大家都玩过,它的玩法也很简单:用游戏按键上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。
不过我们今天要做的贪吃蛇就不是单人本了,你可以理解为C语言贪吃蛇的双人模式——贪吃蛇游戏的双人对战版。
游戏双方分别控制蓝色和红色两条小蛇的前进,碰壁或咬到蛇身体算输。
这个对战版的贪吃蛇游戏网上有不少源代码,这个代码的特点就是为两个游戏者分别增加了命令队列,以实现更舒服的控制。
本项目编译环境:VisualStudio2019/2022,EasyX插件
代码展示:1.定义变量和游戏元素
//游戏区域网格宽度defineITEMSIZE10//游戏元素大小defineCMD_A_DOWN0x2//控制命令:游戏者A向下defineCMD_A_RIGHT0x8//控制命令:游戏者A向右defineCMD_B_DOWN0x20//控制命令:游戏者B向下defineCMD_B_RIGHT0x80//控制命令:游戏者B向右#defineCMD_QUIT0x100//控制命令:退出游戏//定义游戏元素enumITEM{EMPTY=0,WALL,PLAYER_A,PLAYER_B,PLAYER_DEAD,PLAYER_A_NEXT,PLAYER_B_NEXT};//全局变量ITEMg_world[WIDTH][HEIGHT];//保存游戏区POINTg_player_a;//游戏者A的坐标POINTg_player_b;//游戏者B的坐标POINTg_offset_a;//游戏者A的移动偏移方向POINTg_offset_b;//游戏者B的移动偏移方向2.绘制游戏元素
voidDrawItem(intx,inty,ITEMitem){switch(item){caseEMPTY:setfillcolor(BLACK);break;caseWALL:setfillcolor(LIGHTGRAY);break;casePLAYER_A:setfillcolor(BLUE);break;casePLAYER_B:setfillcolor(RED);break;casePLAYER_DEAD:setfillcolor(MAGENTA);break;}bar(x*ITEMSIZE+1,y*ITEMSIZE+1,(x+1)*ITEMSIZE-2,(y+1)*ITEMSIZE-2);g_world[x][y]=item;}3.初始化游戏(将游戏地图和蛇给绘制出来)
voidinit(){intx,y;//绘制墙壁for(x=0;xWIDTH;x++){DrawItem(x,0,WALL);DrawItem(x,HEIGHT-1,WALL);}for(y=1;yHEIGHT-1;y++){DrawItem(0,y,WALL);DrawItem(WIDTH-1,y,WALL);}//绘制游戏区域for(x=1;xWIDTH-1;x++)for(y=1;yHEIGHT-1;y++)DrawItem(x,y,EMPTY);//随机产生两个游戏者的位置(至少间隔5格)do{g_player_=rand()%(WIDTH-6)+3;g_player_=rand()%(HEIGHT-6)+3;g_player_=rand()%(WIDTH-6)+3;g_player_=rand()%(HEIGHT-6)+3;}while((g_player__player_)*(g_player__player_)+(g_player__player_)*(g_player__player_)=25);//画出两个游戏者的位置DrawItem(g_player_,g_player_,PLAYER_A);DrawItem(g_player_,g_player_,PLAYER_B);//随机产生两个游戏者的移动方向//该方法的原理详见:;n=(rand()%4)*2+1;g_offset_=n/3-1;g_offset_=n%3-1;n=(rand()%4)*2+1;g_offset_=n/3-1;g_offset_=n%3-1;//绘制PlayerA空心方块提示移动方向inttx=g_player_+g_offset_;intty=g_player_+g_offset_;setcolor(BLUE);rectangle(tx*ITEMSIZE+1,ty*ITEMSIZE+1,(tx+1)*ITEMSIZE-2,(ty+1)*ITEMSIZE-2);//绘制PlayerB空心方块提示移动方向tx=g_player_+g_offset_;ty=g_player_+g_offset_;setcolor(RED);rectangle(tx*ITEMSIZE+1,ty*ITEMSIZE+1,(tx+1)*ITEMSIZE-2,(ty+1)*ITEMSIZE-2);//按确定开始游戏MessageBox(GetHWnd(),_T("对战贪吃蛇游戏说明:\n\n")_T("游戏目标:两条蛇,先碰到墙壁或碰到任何蛇的身体就算输。\n")_T("PlayerA使用ASDW控制蓝色小蛇移动方向。\n")_T("PlayerB使用上下左右控制红色小蛇移动方向。\n\n")_T("点“确定”按钮开始游戏。"),_T("游戏说明"),MB_OK|MB_ICONINFORMATION);}4.获取游戏双方(用户)的按键指令
intGetCmd(){//定义两个用户的命令队列staticqueueintPLAYER_A_CMD;staticqueueintPLAYER_B_CMD;//定义每次返回的命令intcmd=0;//处理按键while(_kbhit()){switch(_getch()){case27:cmd=CMD_QUIT;break;case'W':case'w':if(PLAYER_A_()16)PLAYER_A_(CMD_A_UP);break;case'S':case's':if(PLAYER_A_()16)PLAYER_A_(CMD_A_DOWN);break;case'A':case'a':if(PLAYER_A_()16)PLAYER_A_(CMD_A_LEFT);break;case'D':case'd':if(PLAYER_A_()16)PLAYER_A_(CMD_A_RIGHT);break;case0:case0xE0:switch(_getch()){case72:if(PLAYER_B_()16)PLAYER_B_(CMD_B_UP);break;case80:if(PLAYER_B_()16)PLAYER_B_(CMD_B_DOWN);break;case75:if(PLAYER_B_()16)PLAYER_B_(CMD_B_LEFT);break;case77:if(PLAYER_B_()16)PLAYER_B_(CMD_B_RIGHT);break;}}}//读取PlayerA的命令intc=0;while(!PLAYER_A_()){c=PLAYER_A_();PLAYER_A_();if((c==CMD_A_UP||c==CMD_A_DOWN)g_offset_!=0)break;if((c==CMD_A_LEFT||c==CMD_A_RIGHT)g_offset_!=0)break;}if(c!=0)cmd|=c;//读取PlayerB的命令c=0;while(!PLAYER_B_()){c=PLAYER_B_();PLAYER_B_();if((c==CMD_B_UP||c==CMD_B_DOWN)g_offset_!=0)break;if((c==CMD_B_LEFT||c==CMD_B_RIGHT)g_offset_!=0)break;}if(c!=0)cmd|=c;//返回命令returncmd;}5.处理用户指令
boolDealCmd(intcmd){if((cmdCMD_A_UP)g_offset_!=0){g_offset_=0;g_offset_=-1;}if((cmdCMD_A_DOWN)g_offset_!=0){g_offset_=0;g_offset_=1;}if((cmdCMD_A_LEFT)g_offset_!=0){g_offset_=-1;g_offset_=0;}if((cmdCMD_A_RIGHT)g_offset_!=0){g_offset_=1;g_offset_=0;}if((cmdCMD_B_UP)g_offset_!=0){g_offset_=0;g_offset_=-1;}if((cmdCMD_B_DOWN)g_offset_!=0){g_offset_=0;g_offset_=1;}if((cmdCMD_B_LEFT)g_offset_!=0){g_offset_=-1;g_offset_=0;}if((cmdCMD_B_RIGHT)g_offset_!=0){g_offset_=1;g_offset_=0;}if(cmdCMD_QUIT)if(MessageBox(GetHWnd(),_T("您要退出游戏吗?"),_T("游戏暂停"),MB_OKCANCEL)==IDOK)returnfalse;returntrue;}6.判断蛇的状态游戏结束后的弹窗选择
boolDealGame(){//PlayerA、B前进g_player_+=g_offset_;g_player_+=g_offset_;g_player_+=g_offset_;g_player_+=g_offset_;//判断PlayerA、B的生死状态booldead_a=false,dead_b=false,dead_ab=false;if(g_player_==g_player__player_==g_player_){DrawItem(g_player_,g_player_,PLAYER_DEAD);dead_ab=true;}elseif(g_world[g_player_][g_player_]!=EMPTY){DrawItem(g_player_,g_player_,PLAYER_DEAD);dead_a=true;}elseif(g_world[g_player_][g_player_]!=EMPTY){DrawItem(g_player_,g_player_,PLAYER_DEAD);dead_b=true;}else{DrawItem(g_player_,g_player_,PLAYER_A);DrawItem(g_player_,g_player_,PLAYER_B);returntrue;}//判断是否要重新开始boolrestart=false;if(dead_ab||(dead_adead_b))restart=MessageBox(GetHWnd(),_T("PlayerA和PlayerB都死了。\n要再来一局吗?"),_T("GAMEOVER"),MB_YESNO|MB_ICONINFORMATION)==IDYES;elseif(dead_a)restart=MessageBox(GetHWnd(),_T("PlayerA死了。\n要再来一局吗?"),_T("GAMEOVER"),MB_YESNO|MB_ICONINFORMATION)==IDYES;elseif(dead_b)restart=MessageBox(GetHWnd(),_T("PlayerB死了。\n要再来一局吗?"),_T("GAMEOVER"),MB_YESNO|MB_ICONINFORMATION)==IDYES;if(restart){init();returntrue;}elsereturnfalse;}7.补上入口函数
voidmain(){initgraph(640,480);srand((unsigned)time(NULL));//初始化init();//游戏主循环while(true){intcmd=GetCmd();//获取用户命令if(!DealCmd(cmd))break;//处理命令if(!DealGame())break;//处理游戏Sleep(200);//延时}//关闭绘图窗口closegraph();}大家赶紧去动手试试吧!
此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C++项目案例,帮助大家在学习C语言的道路上披荆斩棘!
编程学习书籍分享: