嵌入式技术
每天一个C语言小项目,提升你的编程能力!
贪吃蛇游戏大家应该都不陌生了,要说没玩过的话,可能你是15后吧?
贪吃蛇游戏最初为单机模式,后续又陆续推出团战模式、赏金模式、挑战模式等多种玩法。
用游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。
贪吃蛇的唯一的目标就是长成最长的一条蛇!滑动摇杆控制小蛇走位,吃掉地图上彩色的小圆点,就会变长。
效果展示:
改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难。如果有编程技术比较强大的伙伴也可以去尝试一下哦!做出一个趋近完美的贪吃蛇那可就是能力的展现啦~
本项目编译环境:Visual Studio 2019/2022,EasyX插件
代码展示:
#include#include #include #include #define UP 1 #define DOWN 2 #define LEFT 3 #define RIGHT 4 //////////////////////////////////////////// //格子类,定义一个格子的属性及行为 //////////////////////////////////////////// class Cell { public: friend class GameArea; //设置友元函数 void setxy(short x, short y) //设置格子左上角坐标 { m_x = x, m_y = y; } void setfull(short full) //设置格子属性,0为空,1为障碍,2为食物 { m_full = full; } void display(COLORREF color) //设置格子颜色并显示 { m_color = color; setfillstyle(m_color); bar(m_x, m_y, m_x+7, m_y+7); } void LaserDisplay() //显示镭射状态的格子 { IMAGE image(10,10); SetWorkingImage(&image); DWORD* pMem = GetImageBuffer(&image); for(int i = 0; i < 10 * 10; i++) pMem[i] = BGR(RGB(0, 0, i * 256 / (10*10) )); SetWorkingImage(NULL); putimage(m_x,m_y,&image); } short ReturnFull() //返回格子状态 { return m_full; } Cell() //构造函数 { m_x = 0,m_y = 0,m_full = 0; m_color = BLACK; } private: short m_x; //格子的左上角X坐标 short m_y; //格子的左上角Y坐标 short m_full; //0为空,1为阻挡,2为食物 COLORREF m_color; //格子颜色 }; //////////////////////////////////////////// //游戏区类,编写有关游戏区的一些操作 //////////////////////////////////////////// class GameArea //游戏区域 { public: Cell m_game[60][60]; //定义游戏区域(由360个格子组成) friend void MessageDispose(); //设置友元函数 bool CreatFood() //产生随机食物 { srand(time(NULL)); //初始化随机数种子 m_random1 = rand()%58+1; //随机生成一个0 - 58的整数 m_random2 = rand()%58+1; //随机一个0 - 58的整数 if(m_game[m_random2][m_random2].m_full == 0) //检查生成的食物坐标是否在障碍上 { m_game[m_random1][m_random2].display(GREEN); m_game[m_random1][m_random2].m_full = 2; return true; } //如果随机的食物正好出现在蛇身上,则进入下面的循环寻找可以生成食物的地方 for(m_random1 = 1;m_random1 < 59;m_random1++) { for(m_random2 = 1;m_random2 < 59;m_random2++) { if(m_game[m_random2][m_random2].m_full == 0) { m_game[m_random1][m_random2].display(GREEN); m_game[m_random1][m_random2].m_full = 2; return true; } } } //如果没有找到可以生成食物的地方,则通关 return false; //返回false即表示通关 } void DelFood() //删除食物 { m_game[m_random1][m_random2].m_full = 0; //设置为0即代表格子属性为空 } void ChangeColor(int flag1,int flag2,COLORREF color) //设置指定格子的颜色 { m_game[flag1][flag2].display(color); } void Init() //初始化GAME区域 { int flag1,flag2; //标识变量 BeginBatchDraw(); //开始批量绘图 setfillstyle(BLACK); //设置当前颜色 bar(0,0,600,600); //画无边框填充矩形(在这里的用途是用黑色清空游戏区域) for(flag1 = 0;flag1 < 60;flag1++) { for(flag2 = 0;flag2 < 60;flag2++) { if(flag1 == 0 || flag1 == 59 || flag2 == 0 || flag2 == 59) //创建边界 { m_game[flag1][flag2].setfull(1); m_game[flag1][flag2].setxy(flag1*10,flag2*10); m_game[flag1][flag2].display(RGB(237,28,36)); } else //创建游戏区域 { m_game[flag1][flag2].setfull(0); m_game[flag1][flag2].setxy(flag1*10,flag2*10); m_game[flag1][flag2].display(BLACK); } } } CreatFood(); EndBatchDraw(); } private: int m_random1, m_random2; }; //////////////////////////////////////////// //蛇类,定义蛇的数据结构以及蛇的行为 //////////////////////////////////////////// class Snake { public: int toward; //蛇头朝向 friend void MessageDispose(); friend int HitDetect(); friend void ReInit(); Snake() { head = NULL; last = NULL; now = NULL; } void Init() //初始化蛇的结构 { if(head!=NULL) //重玩游戏时,释放原先的链表所有结点 { for(now = head->next;now->next != NULL;now = now->next) { free(now->prior); } } head = (struct node*)malloc(sizeof(struct node)); //为蛇头分配内存 head->prior = NULL; head->m_x = 300; head->m_y = 300; now = (struct node*)malloc(sizeof(struct node)); head->next = now; now->prior = head; now->next = NULL; now->m_x = 300; now->m_y = 290; last = now; toward = DOWN; } void SnakeAdd() { now = head; //当前指向蛇头 now->prior = (struct node*)malloc(sizeof(struct node)); //为新增的结点分配内存 now = now->prior; //让当前指向新分配的结点 now->prior = NULL; //置空当前结点的前趋 now->next = head; //让当前结点的后继指向蛇头 switch(toward) //根据当前蛇头方向确定新增部分的坐标 { case UP: now->m_x = head->m_x; now->m_y = head->m_y -10; break; case DOWN: now->m_x = head->m_x; now->m_y = head->m_y + 10; break; case LEFT: now->m_x = head->m_x - 10; now->m_y = head->m_y; break; case RIGHT: now->m_x = head->m_x + 10; now->m_y = head->m_y; break; } head = now; //设置当前结点为蛇头 } void SnakeDel() //释放蛇尾结点(删除蛇尾) { last = last->prior; free(last->next); last->next = NULL; } void SnakeMove() //蛇身移动一格 { SnakeAdd(); //增加蛇头 SnakeDel(); //删除蛇尾 } private: struct node //蛇身链表 { int m_x; int m_y; struct node *next; //下个结点 struct node *prior; //上个结点 }; struct node *head; struct node *last; struct node *now; }; //////////////////////////////////////////// //游戏类,用来初始化游戏的参数,及实现其他游戏操作 //////////////////////////////////////////// class Game { public: void Init() { closegraph(); initgraph(800,600); setbkmode(TRANSPARENT); //设置输出文字背景为透明 LOGFONT f; getfont(&f); // 获取当前字体设置 f.lfHeight = 50; // 设置字体高度为 48(包含行距) _tcscpy(f.lfFaceName, _T("黑体")); // 设置字体为“黑体” f.lfQuality = ANTIALIASED_QUALITY; // 设置输出效果为抗锯齿 setfont(&f); // 设置字体样式 } void FailGame() //游戏失败显示的画面 { setcolor(RED); setfont(70, 0, _T("微软雅黑")); outtextxy(150, 265, _T("YOU LOSE!")); } void WinGame() //游戏胜利时显示的画面 { setcolor(RED); setfont(70, 0, _T("微软雅黑")); outtextxy(150, 265, _T("YOU WIN!")); FlushBatchDraw(); Sleep(10000); exit(0); } }; //////////////////////////////////////////// //管理区类,定义管理区域的相关操作 //////////////////////////////////////////// class ManageArea { public: friend void MessageDispose(); void TimeAdd(double add) //增加时间(可在类外直接调用实现动态刷新时间) { m_time += add; DisplayTime(); } void ScoreAdd(short add) //增加分数(可在类外直接调用实现动态刷新分数) { m_score += add; DisplayScore(); } void DisplayPause() //显示暂停或者开始 { BeginBatchDraw(); _stprintf(m_str_score, _T("%d"), m_score); setfont(25, 0, _T("微软雅黑")); setfillstyle(m_bgcolor); bar(625,490,800,515); setcolor(BLUE); if(m_pause) outtextxy(625, 490, _T("开始(P键)")); else outtextxy(625, 490, _T("暂停(P键)")); EndBatchDraw(); } void Init() //初始化管理界面 { m_time = 0.0; m_score = 0; m_leave = 1; m_pause = false; _stprintf(m_str_score, _T("%d"), m_score); //格式化转换类型 _stprintf(m_str_time, _T("%.1lf"), m_time); m_bgcolor = BLACK; BeginBatchDraw(); setfillstyle(BLACK); bar(601,0,800,600); setfont(60, 0, _T("微软雅黑")); setcolor(GREEN); outtextxy(625, 30, _T("贪吃蛇")); setfont(30, 0, _T("微软雅黑")); setcolor(RGB(128,0,255)); outtextxy(625, 140, _T("制作:轻雨漫步")); setfont(25, 0, _T("微软雅黑")); setcolor(BLUE); outtextxy(625, 430, _T("时间:")); outtextxy(625, 460, _T("分数:")); outtextxy(625, 490, _T("暂停(P键)")); outtextxy(625, 520, _T("重新游戏(R键)")); setcolor(RED); outtextxy(720, 400, m_str_leave); outtextxy(680, 460, m_str_score); outtextxy(680, 430, m_str_time); EndBatchDraw(); } private: double m_time; short m_score; short m_leave; bool m_pause; TCHAR m_str_leave[2], m_str_time[33], m_str_score[5]; COLORREF m_bgcolor; void DisplayTime() //显示当前耗时 { BeginBatchDraw(); _stprintf(m_str_time, _T("%.1lf"), m_time); setfont(25, 0, _T("微软雅黑")); setfillstyle(m_bgcolor); bar(680,430,800,455); setcolor(RED); outtextxy(680,430,m_str_time); EndBatchDraw(); } void DisplayScore() //显示当前分数 { BeginBatchDraw(); _stprintf(m_str_score, _T("%d"), m_score); setfont(25, 0, _T("微软雅黑")); setfillstyle(m_bgcolor); bar(680,460,800,485); setcolor(RED); outtextxy(680,460,m_str_score); EndBatchDraw(); } }; //////////////////////////////////////////// //声明游戏需要的类 //////////////////////////////////////////// Game game; //用于初始化游戏、设置游戏相关参数 GameArea a; //用于初始化游戏区域,设置,改变游戏区域相关参数 ManageArea manager; //用于初始化管理区域,设置管理区相关参数 Snake s; //用于初始化蛇,数据化蛇,操作蛇 //////////////////////////////////////////// //游戏的消息控制,流程控制函数 //////////////////////////////////////////// void MessageDispose() //消息处理函数 { char c; s.now = NULL; bool Keepdown = false; while(true) { Keepdown = false; //是否持续按W A S D 中的一个按键 if(kbhit()) { switch(c = getch()) //处理按键消息(W A S D) { case 'w': case 'W': if(s.toward == UP)Keepdown = true; else if(s.toward != DOWN&&s.toward != UP)s.toward = UP; break; case 's': case 'S': if(s.toward == DOWN)Keepdown = true; else if(s.toward != UP&&s.toward != DOWN)s.toward = DOWN; break; case 'a': case 'A': if(s.toward == LEFT)Keepdown = true; else if(s.toward != RIGHT&&s.toward != LEFT)s.toward = LEFT; break; case 'd': case 'D': if(s.toward == RIGHT)Keepdown = true; else if(s.toward != LEFT&&s.toward != RIGHT)s.toward = RIGHT; break; case 'p': case 'P': manager.m_pause = !manager.m_pause; //设置暂停或开始 manager.DisplayPause(); //显示暂停或开始 break; case 'r': case 'R': ReInit(); break; } } if(true == manager.m_pause) //如果暂停,直接进行下次循环 { continue; } BeginBatchDraw(); switch(a.m_game[s.head->m_x/10][s.head->m_y/10].ReturnFull()) //检测蛇头遇到的情况 { case 2: //遇到食物,蛇身加长 a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE); s.SnakeAdd(); //蛇增长 a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE); a.DelFood(); //删除食物 if(a.CreatFood() == false) //创建新食物,并检查是否通关 { game.WinGame(); //游戏通关(当地图没地方创建食物时) } manager.ScoreAdd(1); //加一分 break; case 0: a.m_game[s.last->m_x/10][s.last->m_y/10].setfull(0); //设置蛇尾经过处无障碍 a.ChangeColor(s.last->m_x/10,s.last->m_y/10,BLACK); s.SnakeMove(); //蛇移动一次 a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE); a.m_game[s.head->next->m_x/10][s.head->next->m_y/10].setfull(1); //设置蛇头经过处有障碍 break; case 1: //遇到障碍物 game.FailGame(); a.ChangeColor(s.head->m_x/10,s.head->m_y/10,RGB(255,127,39)); FlushBatchDraw(); { char c = ' '; while(c != 'r' && c != 'R') //当游戏失败时,按R键可重新进行游戏 { if(kbhit()) { c = getch(); } Sleep(10); } } ReInit(); //重新开始游戏 break; } EndBatchDraw(); if(Keepdown==false) { Sleep(100); manager.TimeAdd(0.1); //增加时间 } else //当持续按下按方向键时 { Sleep(40); //适当休眠可以增加游戏流畅性 manager.TimeAdd(0.04); //增加时间 } } } //////////////////////////////////////////// //游戏初始化函数 //////////////////////////////////////////// void ReInit() { a.Init(); //初始化游戏区 s.Init(); //初始化蛇 manager.Init(); //初始化管理区 //绘制蛇的开始状态 s.now = s.head; a.ChangeColor(s.now->m_x/10,s.now->m_y/10,BLUE); s.now = s.last; a.ChangeColor(s.now->m_x/10,s.now->m_y/10,BLUE); } //////////////////////////////////////////// //main函数,程序入口 //////////////////////////////////////////// int main(void) { game.Init(); //初始化游戏参数、设置 ReInit(); //初始化其他 MessageDispose(); //消息处理函数 return 0; }
大家赶紧去动手试试吧!
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !