标签:line 贪吃蛇 今天 href bool 生成 alt std idt
今天突发奇想想用C++实现一个贪吃蛇小游戏,无奈C++没有自带的GUI框架,蒟蒻博主也不会用C++做GUI,于是只能在黑乎乎的命令行中完成这个游戏了(qwq)。
贪吃蛇游戏还是比较简单的,就用C++的基础知识和一点个Windows的api就可以开发完成了,这里就稍微讲一下思路吧。
总共是GameInit.cpp,Snake.cpp,Food.cpp,Display.cpp,GameStart.cpp 这5个文件。
GameInit是游戏的初始设置类,负责设置游戏窗口大小,设置光标,初始化随机种子等等初始化工作。
1 #include"pch.h" 2 #include "GmaeInit.h" 3 #include<Windows.h> 4 #include<random> 5 #include<ctime> 6 #include <conio.h> 7 8 using namespace std; 9 10 GameInit::GameInit(int s) : speed(s) { 11 //设置游戏窗口大小 12 char buffer[32]; 13 sprintf_s(buffer, "mode con cols=%d lines=%d", windowWidth, windowHeight); 14 system(buffer); 15 16 //隐藏光标 17 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); 18 CONSOLE_CURSOR_INFO CursorInfo; 19 GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息 20 CursorInfo.bVisible = false; //隐藏控制台光标 21 SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态 22 //初始化随机数种子 23 srand((unsigned int)time(0)); 24 }
Snake是控制蛇的类,包括监听鼠标对蛇的方向做出改变,以及在地图上移动蛇两个功能。当然在移动中非常重要的是,判断蛇是否撞到边界,是否撞到自己等等。
这里讲一下移动应该怎么做,首先蛇的身体是用list来存储,移动其实很简单分两种情况:①没吃到食物,那么就是蛇头朝目标方向移动一个作为新的蛇头加入身体list,然后把蛇的尾部删除。②那么如果吃到了食物该怎么办呢?想一想,欸没错就是不把蛇尾删除就是了(相当于增上了一格)。
1 #include"pch.h" 2 #include"Snake.h" 3 #include"GmaeInit.h" 4 #include<iostream> 5 #include<unordered_set> 6 #include<Windows.h> 7 #include <conio.h> 8 9 using namespace std; 10 11 Snake::Snake() { 12 oldDirection = 1; 13 newDirection = -1; 14 body.push_back(point{ 40, 15 }); 15 body.push_back(point{ 39,15 }); 16 body.push_back(point{ 38,15 }); 17 body.push_back(point{ 37, 15 }); 18 body.push_back(point{ 36, 15 }); 19 } 20 21 //监听键盘 22 void Snake::listen_key_borad() { 23 char ch; 24 if (_kbhit()) //kbhit 非阻塞函数 25 { 26 ch = _getch(); //使用 getch 函数获取键盘输入 27 switch (ch) 28 { 29 case ‘w‘: 30 case ‘W‘: 31 if (oldDirection == 2) break; 32 newDirection = 0; 33 break; 34 case ‘s‘: 35 case ‘S‘: 36 if (oldDirection == 0) break; 37 newDirection = 2; 38 break; 39 case ‘a‘: 40 case ‘A‘: 41 if (oldDirection == 1) break; 42 newDirection = 3; 43 break; 44 case ‘d‘: 45 case ‘D‘: 46 if (oldDirection == 3) break; 47 newDirection = 1; 48 break; 49 } 50 } 51 } 52 53 bool Snake::movePoint(point& pt,int dir) { 54 point newpt = pt; 55 newpt.x += dx[dir]; 56 newpt.y += dy[dir]; 57 if (newpt.x<=1 || newpt.x>=GameInit::windowWidth || newpt.y<=1 || newpt.y>=GameInit::windowHeight) return 0; 58 unordered_set<int> snakebody; 59 for (auto pt : body) snakebody.insert(pt.x*1000+pt.y); 60 if (snakebody.count(newpt.x*1000+newpt.y)) return 0; 61 pt = newpt; 62 return 1; 63 } 64 65 bool Snake::moveHead() { 66 if (newDirection == -1) newDirection = oldDirection; 67 68 point newpt = body.front(); 69 if (movePoint(newpt,newDirection) == 0) return 0; 70 body.push_front(newpt); 71 72 oldDirection = newDirection; newDirection = -1; 73 return 1; 74 } 75 76 bool Snake::moveHeadAndTail() { 77 if (newDirection == -1) newDirection = oldDirection; 78 79 body.pop_back(); 80 point newpt = body.front(); 81 if (movePoint(newpt,newDirection) == 0) return 0; 82 body.push_front(newpt); 83 84 oldDirection = newDirection; newDirection = -1; 85 return 1; 86 }
Food是食物类,只有生成食物只一个主要功能(当然生成还要避免生成在蛇身上)。
1 #include"pch.h" 2 #include<iostream> 3 #include<random> 4 #include<cstdlib> 5 #include"Food.h" 6 #include"GmaeInit.h" 7 #include"Snake.h" 8 9 using namespace std; 10 11 bool Food::EatFood(const list<point>& body) { 12 if (x == body.front().x && y == body.front().y) return 1; 13 else return 0; 14 } 15 16 bool Food::FoodOnBody(int tmpx,int tmpy,const list<point>& body) { 17 for (auto pt : body) 18 if (pt.x == tmpx && pt.y == tmpy) return 1; 19 return 0; 20 } 21 22 void Food::CreateFood(const list<point>& body) { 23 int tmpx,tmpy; 24 do { 25 tmpx = rand() % GameInit::windowWidth + 1; 26 tmpy = rand() % GameInit::windowHeight + 1; 27 } while (FoodOnBody(tmpx, tmpy, body)); 28 this->x = tmpx; 29 this->y = tmpy; 30 }
Display是一个比较关键的类,它负责地图上各个资源的展示,包括蛇身体,食物,地图边界,当然也包括各个资源的销毁。
这个函数要用到一个比较有趣的Window API:SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c); 这个函数能够移动命令行光标位置,然后我们就能在那个位置输出符号!!!
1 #include"pch.h" 2 #include"Display.h" 3 #include"GmaeInit.h" 4 #include"Snake.h" 5 #include<iostream> 6 #include<Windows.h> 7 #include <conio.h> 8 9 using namespace std; 10 11 void Display::printBorder() { 12 system("cls"); 13 int n = GameInit::windowHeight; 14 int m = GameInit::windowWidth; 15 for (int i = 1; i <= n; i++) { 16 for (int j = 1; j <= m; j++) { 17 if (i == 1 || i==n || j == 1 || j == m) cout << "#"; else cout << " "; 18 } 19 cout << endl; 20 } 21 } 22 23 //将光标移动到x,y位置 24 void Display::gotoxy(int x, int y) { 25 COORD c; 26 c.X = x; c.Y = y; 27 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c); 28 } 29 30 void Display::printSnake(const list<point> &body) { 31 for (auto pt : body) { 32 gotoxy(pt.x, pt.y); 33 cout << "*"; 34 } 35 } 36 37 void Display::destroySnake(const list<point> &body) { 38 for (auto pt : body) { 39 gotoxy(pt.x, pt.y); 40 cout << " "; 41 } 42 } 43 44 void Display::printFood(int x, int y) { 45 gotoxy(x, y); 46 cout << "@"; 47 } 48 49 void Display::destroyFood(int x, int y) { 50 gotoxy(x, y); 51 cout << " "; 52 } 53 54 void Display::clean() { 55 for (int i = 32; i <= 50; i++) { 56 gotoxy(i, 16); 57 cout << " "; 58 } 59 } 60 61 void Display::gameover() { 62 string over = "游戏结束"; 63 for (int i = 32; i <= 40; i++) { 64 gotoxy(i, 16); 65 cout << over[i-32]; 66 } 67 }
这只是个心血来潮做的小demo,读者很容易能看懂,也很容易为它扩展各种功能:例如计分板,根据玩家选难度加快蛇移动速度,加入经典的无边界地图玩法等等。
游戏项目Github地址:https://github.com/Clno1/Blockade 。改一改玩一玩很是很欢乐的,哈哈哈。
标签:line 贪吃蛇 今天 href bool 生成 alt std idt
原文地址:https://www.cnblogs.com/clno1/p/12838952.html