晁错没有错 發表於 2025-12-5 09:46:50

用c++写控制台贪吃蛇游戏完整步骤

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>效果图</li><li>创建界面</li><ul class="second_class_ul"><li>了解界面的生成和输入</li><li>下一步设置我们的提示</li><li>构建游戏界面</li></ul><li>游戏本体</li><ul class="second_class_ul"><li>创建蛇</li><li>蛇的行走</li><li>编写失败条件。</li></ul><li>隐藏光标</li><ul class="second_class_ul"></ul><li>总结</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>效果图</h2>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372299.png" /></p>
<p>要使用的东西。</p>
<p>1.链表,2.结构体,3.系统操作。</p>
<p class="maodian"></p><h2>创建界面</h2>
<p class="maodian"></p><h3>了解界面的生成和输入</h3>
<p>先本地化环境用于在控制台输出中文setlocale(LC_ALL, &quot;&quot;);要包含#include &lt;locale.h&gt;</p>
<p>要使用 system函数,要包括头文件windows.h。</p>
<div class="jb51code"><pre class="brush:cpp;">void cj() {
    setlocale(LC_ALL, "");// 设置本地化环境
    system("mode con cols=100 lines=40");// 调整控制台窗口尺寸
    system("pause");// 防止窗口自动关闭
}
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372265.png" /></p>
<p>查看光标发现光标的长宽不匹配,调整cols和lines,来判断那个是长的。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372239.png" /></p>
<p>发现调整cols后长变了所以cols是窗口的长。</p>
<p>调整后发现2个长等于一个宽,所以我们设置时要设置2的倍数长</p>
<p>设置我们的游戏界面为25*25,加上边框长乘2,54*27,再加上提示,36长。凑个整</p>
<p>100*30.</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372226.png" /></p>
<p>发现输出都从左上角开始,所以需要定位光标位置来输出,后续的内容也要运用光标的定位,所以我们要定义一个函数来表示光标定位。</p>
<div class="jb51code"><pre class="brush:cpp;">HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);

// 获取控制台输出句柄
// 使用GetStdHandle(STD_OUTPUT_HANDLE)获取标准输出设备句柄

COORD pos = {x, y};// 定义光标位置坐标(左上角为原点(0,0))

SetConsoleCursorPosition(houtput, pos);// 将光标定位到指定坐标

void dw(int x, int y) {
    HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos = {x, y};
    SetConsoleCursorPosition(houtput, pos);
}
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372225.png" /></p>
<p>构建欢迎界面,(简介版)</p>
<div class="jb51code"><pre class="brush:cpp;">dw(40, 15);
wprintf(L"欢迎来到贪吃蛇游戏");//用wprintf来输出宽字符,L表示后面的是宽字符,如中文等。
dw(40, 16);
system("pause");</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372213.png" /></p>
<p>到下一个界面我们要清空当前界面。</p>
<p>system(&quot;cls&quot;);来清空界面</p>
<div class="jb51code"><pre class="brush:cpp;">system("cls");// 清屏操作
dw(40, 16);   // 调用dw函数,参数为40和16
system("pause");// 暂停程序执行</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372232.png" /></p>
<p class="maodian"></p><h3>下一步设置我们的提示</h3>
<p>按W.S.A.D移动,F4加速,F5减速,space暂停,Esc退出。</p>
<p>定位要的位置输出数据,调整位置让它 看起居中。</p>
<div class="jb51code"><pre class="brush:cpp;">dw(24, 15);
wprintf(L"按W.S.A.D移动,F4加速,F5减速,space暂停,Esc退出。");
dw(40, 16);
printf("加速能得到更高的分数");
dw(40, 17);
system("pause");</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372296.png" /></p>
<p class="maodian"></p><h3>构建游戏界面</h3>
<p>构建蛇的活动范围墙</p>
<p>发现高度不够扩高一点到40;下移墙,在顶上标识提示词表明游戏界面。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372270.png" /></p>
<div class="jb51code"><pre class="brush:cpp;">system("cls");
int i = 0, j = 0;
for (i = 3; i &lt; 30; i++)
{
    dw(0, i);
    for (j = 0; j &lt; 27; j++) {
      if (i == 3 || i == 29 || j == 0 || j == 26)
            wprintf(L"墙");
      else
            wprintf(L"");
    }
    printf("\n");
}
dw(14, 1);
wprintf(L"游戏界面");
dw(0, 32);
system("pause");</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372280.png" /></p>
<p>右边加入提示词</p>
<div class="jb51code"><pre class="brush:cpp;">dw(60, 6);
wprintf(L"时间:%.2f", sj);
dw(60, 10);
wprintf(L"不能撞墙,不能碰到自己");
dw(60, 11);
wprintf(L"按W.S.A.D移动\n");
dw(60, 12);
wprintf(L"F4加速,F5减速\n");
dw(60, 13);
wprintf(L"space暂停,Esc退出");
dw(60, 14);
wprintf(L"fish_xk制作");</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372216.png" /></p>
<p>发现函数太长了,分别封装成函数。</p>
<div class="jb51code"><pre class="brush:cpp;">float sj = 0;
void dw(int x, int y) {
    HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos = { x,y };
    SetConsoleCursorPosition(houtput, pos);
}
void help() {
    dw(60, 6);
    wprintf(L"时间:%.2f", sj);
    dw(60, 10);
    wprintf(L"不能撞墙,不能碰到自己");
    dw(60, 11);
    wprintf(L"按W.S.A.D移动\n");
    dw(60, 12);
    wprintf(L"F4加速,F5减速\n");
    dw(60, 13);
    wprintf(L"space暂停,Esc退出");
    dw(60, 14);
    wprintf(L"fish_xk制作");
    system("pause");
}
void ks() {
    setlocale(LC_ALL, "");
    system("mode con cols=100 lines=40");
    dw(40, 15);
    wprintf(L"欢迎来到贪吃蛇游戏");
    dw(40, 16);
    system("pause");
    system("cls");
}
void zj() {
    dw(24, 15);
    wprintf(L"按W.S.A.D移动,F4加速,F5减速,space暂停,Esc退出。");
    dw(40, 16);
    printf("加速能得到更高的分数");
    dw(40, 17);
    system("pause");
    system("cls");
}
void yxjm() {
int i = 0, j = 0;
    for (i = 3; i &lt; 30; i++)
    {
      dw(0, i);
      for (j = 0; j &lt; 27; j++) {
            if (i == 3 || i == 29 || j == 0 || j == 26)
                wprintf(L"墙");
            else
                wprintf(L"");
      }
      printf("\n");
    }
    dw(22, 1);
    wprintf(L"游戏界面");
    dw(0, 32);
}
void cj() {
    ks();
    zj();
    yxjm();
    help();
}</pre></div>
<p>这样就完成了所有的界面的制作。</p>
<p class="maodian"></p><h2>游戏本体</h2>
<p class="maodian"></p><h3>创建蛇</h3>
<p>蛇由一个个节点组成,用链表来创建。重命名一下方便使用</p>
<div class="jb51code"><pre class="brush:cpp;">typedef struct snakebody {
    struct tcs* next;
    int x;
    int y;
}snake,st;</pre></div>
<p>有蛇,有果子,有速度。用一个结构体来表示。</p>
<p>蛇可以用头节点来表示。</p>
<p>果可以看作一个在外的蛇身。</p>
<div class="jb51code"><pre class="brush:cpp;">typedef struct tcs{
    snake* head;
    int v;
    snake* guo;
}tcs;</pre></div>
<p>还要有状态,方向,总分数,单个果子的权重。</p>
<div class="jb51code"><pre class="brush:cpp;">typedef struct snakebody{
    struct tcs* next;
    int x;
    int y;
}snake;
enum gamezt {
    OK=1,
    FAIL,
    DIE_BYWALL,
    DIE_BYSELF
};
enum snakefx {
    UP = 1,
    DOWN,
    LEFT,
    RIGHT
};
typedef struct tcs{
    snake* head;//蛇
    snake* guo;//果
    int v;//速度
    enum gamezt zt;//状态
    enum snakefx fx;//方向
    int food_weight;//单个分数
    int score;//总分数
}tcs;</pre></div>
<p>初始化一下蛇的身体。</p>
<p>尾插链表来初始蛇身</p>
<div class="jb51code"><pre class="brush:cpp;">void push(snake**ps,int x,int y) {//插入蛇的节点
    snake* news = (snake*)malloc(sizeof(snake));//开辟节点
    news-&gt;next = NULL;
    news-&gt;x = x;
    news-&gt;y = y;
    if (*ps == NULL) {
      *ps = news;
    }
    else
    {
      snake* pos = *ps;
      while (pos-&gt;next) {//链接到末尾
            pos = pos-&gt;next;
      }
      pos-&gt;next = news;
    }
}

snake* body = (snake*)malloc(sizeof(snake));
body = NULL;
int i;
for (i = 22; i &lt; 27; i = i + 1) {
    push(&amp;body,22+(i-22)*2, 16);
}
ps-&gt;head = body;
print(ps);</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372262.png" /></p>
<div class="jb51code"><pre class="brush:cpp;">void print(snake*ps) {//打印蛇
        assert(ps);
        snake* cur = ps;
        while (cur) {//遍历链表
                dw(cur-&gt;x, cur-&gt;y);
                wprintf(L"蛇");
                cur = cur-&gt;next;
        }
}
tcs* cjsnake() {//返回蛇的头位置
        tcs*ps = (tcs*)malloc(sizeof(tcs));
        snake* body = (snake*)malloc(sizeof(snake));
        body = NULL;
        int i;
        for (i = 22; i &lt; 27; i = i + 1) {//循环添加5个节点
                push(&amp;body,22+(i-22)*2, 16);
        }
        ps-&gt;head = body;
        print(ps-&gt;head);//打印开始的蛇身
        cjguo(ps);
        ps-&gt;v = 200;
        ps-&gt;zt = OK;
        ps-&gt;fx = LEFE;
        ps-&gt;score = 0;
        ps-&gt;food_weight = 10;
        return ps;
}</pre></div>
<p>下一步生成果子,要有随机数要包含#include&lt;time.h&gt;</p>
<p>设置随机数</p>
<div class="jb51code"><pre class="brush:cpp;">srand(time(NULL))

void cjguo(tcs* ps) {
    snake* news = (snake*)malloc(sizeof(snake));
    news-&gt;next = NULL;
    snake* cur = ps-&gt;head;
    ag:
    news-&gt;x = (rand()%25+1+1)*2;//第一个+1是保证1到25,后一个+1,是不能是墙
    news-&gt;y = (rand() % 25 + 1+4 );
    cur = ps-&gt;head;
    while (cur){
      if (cur-&gt;x == news-&gt;x &amp;&amp; cur-&gt;y == news-&gt;y)//如果和蛇重叠重新生成。
            goto ag;
      cur = cur-&gt;next;
    }
    ps-&gt;guo = news;
    dw(news-&gt;x, news-&gt;y);
    wprintf(L"果");//打印果的位置
}</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025120509372232.png" /></p>
<p>设置其他数据</p>
<div class="jb51code"><pre class="brush:cpp;">    ps-&gt;v = 200;//速度
    ps-&gt;zt = OK;//状态
    ps-&gt;fx = LEFT;//方向
    ps-&gt;score = 0;//成绩
    ps-&gt;food_weight = 10;//每个果子的分数</pre></div>
<p>创建完毕</p>
<p class="maodian"></p><h3>蛇的行走</h3>
<div class="jb51code"><pre class="brush:cpp;">while (cur-&gt;zt == OK) {
dw(60, 6);
wprintf(L"时间:%.2f秒", sj);
dw(60, 8);
printf("得分:%d", cur-&gt;score);
dw(60, 9);
printf("食物分值:%d", cur-&gt;food_weight);
snakedong(cur);//行动的函数
sj+=cur-&gt;v/1000.0;//行动时间
Sleep(cur-&gt;v);//行动间隔
}</pre></div>
<p>设置循环判断游戏状态。可以再加入时间</p>
<p>设置程序的休息时间,来实现运动间隔。</p>
<p>要控制程序,需要读取输入信息,所以定义一个读取的宏</p>
<div class="jb51code"><pre class="brush:cpp;">#define KEY_PRESS(vk)   ((GetAsyncKeyState(vk)&amp;1)?1:0)</pre></div>
<p>读取一个虚拟键盘值,判断是否按过。</p>
<div class="jb51code"><pre class="brush:cpp;">if (KEY_PRESS(0x53) &amp;&amp; snake-&gt;fx != UP) {//识别W
        snake-&gt;fx = DOWN;
}
else if (KEY_PRESS(0x57) &amp;&amp; snake-&gt;fx != DOWN) {//识别S
        snake-&gt;fx = UP;
}
else if (KEY_PRESS(0x41) &amp;&amp; snake-&gt;fx != RIGHT) {//识别A
        snake-&gt;fx = LEFE;
}
else if (KEY_PRESS(0x44) &amp;&amp; snake-&gt;fx != LEFE) {//识别B
        snake-&gt;fx = RIGHT;
}
else if (KEY_PRESS(VK_SPACE)) {//识别空格
        while (1) {
                Sleep(200);
                if (KEY_PRESS(VK_SPACE)) {//循环停止游戏
                        break;
                }
        }
}
else if (KEY_PRESS(VK_ESCAPE)) {//识别ESC
        snake-&gt;zt = END_NORMAL;
}
else if (KEY_PRESS(VK_F4)) {//识别F4
        snake-&gt;v = snake-&gt;v - 10;
        snake-&gt;food_weight = snake-&gt;food_weight + 5;
}
else if (KEY_PRESS(VK_F5)) {//识别F5
        snake-&gt;v = snake-&gt;v + 10;
        snake-&gt;food_weight = snake-&gt;food_weight - 5;
}</pre></div>
<p>加入一个全局变量防止加速过头</p>
<p>根据蛇的方向来改变蛇的身体坐标</p>
<div class="jb51code"><pre class="brush:cpp;">snake* toupush(snake*ps,int x,int y) {//插入头部,到达的节点
        snake* news = (snake*)malloc(sizeof(snake));
        news-&gt;next = ps;
        news-&gt;x = x;
        news-&gt;y = y;
        dw(news-&gt;x, news-&gt;y);
        wprintf(L"蛇");
        ps = news;
        return ps;
}
snake* pop(snake* ps) {//没吃到果子,删除多出来的节点
        snake* tail = ps;
        while (tail-&gt;next-&gt;next) {
                tail = tail-&gt;next;
        }
        dw(tail-&gt;next-&gt;x, tail-&gt;next-&gt;y);
        wprintf(L"");
        free(tail-&gt;next);
        tail-&gt;next = NULL;
        return ps;
}
if (snake-&gt;fx == UP) {//向上
        snake-&gt;head=toupush(snake-&gt;head, snake-&gt;head-&gt;x, snake-&gt;head-&gt;y - 1);
}
else if (snake-&gt;fx == DOWN) {//向下
        snake-&gt;head=toupush(snake-&gt;head, snake-&gt;head-&gt;x, snake-&gt;head-&gt;y + 1);
}
else if (snake-&gt;fx == LEFE) {//向左
        snake-&gt;head=toupush(snake-&gt;head, snake-&gt;head-&gt;x-2, snake-&gt;head-&gt;y );
}
else if (snake-&gt;fx == RIGHT) {//向右
        snake-&gt;head=toupush(snake-&gt;head, snake-&gt;head-&gt;x+2, snake-&gt;head-&gt;y );
}
if (snake-&gt;head-&gt;x != snake-&gt;guo-&gt;x || snake-&gt;head-&gt;y != snake-&gt;guo-&gt;y)//是否吃到果子
        snake-&gt;head=pop(snake-&gt;head);//没吃到,删除尾节点
else {
        free(snake-&gt;guo);//释放果子的节点
        snake-&gt;guo = NULL;
        cjguo(snake);//重新生成果子
        snake-&gt;score += snake-&gt;food_weight;//加分
}</pre></div>
<p>吃到果子就不删尾,分数加权重,没吃到就删尾。</p>
<p class="maodian"></p><h3>编写失败条件。</h3>
<div class="jb51code"><pre class="brush:cpp;">if (snake-&gt;head-&gt;x == 0 || snake-&gt;head-&gt;x == 52 || snake-&gt;head-&gt;y == 4 || snake-&gt;head-&gt;y == 29)//到达墙体
        snake-&gt;zt = DIE_BYWALL;//改变状态
st* self = snake-&gt;head-&gt;next;
        while (self) {//遍历自身,看是否相交
                if (snake-&gt;head-&gt;x == self-&gt;x &amp;&amp; snake-&gt;head-&gt;y == self-&gt;y)
                        snake-&gt;zt = DIE_BYSELF;//如相交更新状态
                self = self-&gt;next;
        }</pre></div>
<p>结束后输出分数</p>
<div class="jb51code"><pre class="brush:cpp;">system("cls");
dw(40, 15);
if (cur-&gt;zt == DIE_BYSELF)
        wprintf(L"失败于撞到自己");
if (cur-&gt;zt == DIE_BYWALL)
        wprintf(L"失败于撞墙");
if (cur-&gt;zt == END_NORMAL)
        wprintf(L"正常退出");
dw(40, 16);
wprintf(L"你坚持的时间是%.2f秒", sj);
dw(40, 17);
wprintf(L"你的得分是%d",cur-&gt;score);</pre></div>
<p class="maodian"></p><h2>隐藏光标</h2>
<div class="jb51code"><pre class="brush:cpp;">void gbyc() {
        //获取标准输出设备的句柄;
        HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
        //定义一个光标结构体
        CONSOLE_CURSOR_INFO cursor_info = { 0 };
        //获取houtput句柄相关的控制台上的光标信息,存放cursor_info
        GetConsoleCursorInfo(houtput, &amp;cursor_info);
        //设置吧光标的占比
        cursor_info.bVisible = false;//光标消失
        //设置和houtput句柄相关的控制台的光标信息
        SetConsoleCursorInfo(houtput, &amp;cursor_info);
}
void ck() {
        //创建窗口
        setlocale(LC_ALL, "");
        COORD pos = { 0,0 };
        system("mode con cols=100 lines=40");
        system("title.贪吃蛇");
        gbyc();
        //打印开始界面
}</pre></div>
<p>到这里已经全部完成了。</p>
<p class="maodian"></p><h2>总结</h2>
<p>到此这篇关于用c++写控制台贪吃蛇游戏完整步骤的文章就介绍到这了,更多相关c++写控制台贪吃蛇内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>C++基于控制台实现的贪吃蛇小游戏</li><li>C++控制台实现贪吃蛇游戏</li><li>C++通过类实现控制台贪吃蛇</li><li>C++控制台循环链表实现贪吃蛇</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: 用c++写控制台贪吃蛇游戏完整步骤