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    。改一改玩一玩很是很欢乐的,哈哈哈。

  • 相关阅读:
    leetcode231 2的幂 leetcode342 4的幂 leetcode326 3的幂
    leetcode300. Longest Increasing Subsequence 最长递增子序列 、674. Longest Continuous Increasing Subsequence
    leetcode64. Minimum Path Sum
    leetcode 20 括号匹配
    算法题待做
    leetcode 121. Best Time to Buy and Sell Stock 、122.Best Time to Buy and Sell Stock II 、309. Best Time to Buy and Sell Stock with Cooldown 、714. Best Time to Buy and Sell Stock with Transaction Fee
    rand7生成rand10,rand1生成rand6,rand2生成rand5(包含了rand2生成rand3)
    依图
    leetcode 1.Two Sum 、167. Two Sum II
    从分类,排序,top-k多个方面对推荐算法稳定性的评价
  • 原文地址:https://www.cnblogs.com/clno1/p/12838952.html
Copyright © 2011-2022 走看看