zoukankan      html  css  js  c++  java
  • C++实现贪吃蛇小游戏

    今天突发奇想想用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 }
    View Code

    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 }
    View Code

    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 }
    View Code

    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 }
    View Code

    这只是个心血来潮做的小demo,读者很容易能看懂,也很容易为它扩展各种功能:例如计分板,根据玩家选难度加快蛇移动速度,加入经典的无边界地图玩法等等。

    游戏项目Github地址:https://github.com/Clno1/Blockade    。改一改玩一玩很是很欢乐的,哈哈哈。

  • 相关阅读:
    团队作业6——展示博客(alpha阶段)
    第八天敏捷冲刺
    第七天敏捷冲刺
    第六天敏捷冲刺
    第五天敏捷冲刺
    第四天敏捷冲刺
    第三天敏捷冲刺
    linux查询内存使用情况
    input hidden 属性
    于Java网络爬虫---模拟txt文件上传操作。
  • 原文地址:https://www.cnblogs.com/clno1/p/12838952.html
Copyright © 2011-2022 走看看