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

 更新时间:2025年12月05日 09:46:50   作者:fish_xk  
用C++制作贪吃蛇游戏是一个经典的编程练习,它涉及多个方面的编程知识,包括数据结构、图形界面、事件处理等,这篇文章主要介绍了用c++写控制台贪吃蛇游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

效果图

要使用的东西。

1.链表,2.结构体,3.系统操作。

创建界面

了解界面的生成和输入

先本地化环境用于在控制台输出中文setlocale(LC_ALL, "");要包含#include <locale.h>

要使用 system函数,要包括头文件windows.h。

void cj() {
    setlocale(LC_ALL, "");  // 设置本地化环境
    system("mode con cols=100 lines=40");  // 调整控制台窗口尺寸
    system("pause");  // 防止窗口自动关闭
}

查看光标发现光标的长宽不匹配,调整cols和lines,来判断那个是长的。

发现调整cols后长变了所以cols是窗口的长。

调整后发现2个长等于一个宽,所以我们设置时要设置2的倍数长

设置我们的游戏界面为25*25,加上边框长乘2,54*27,再加上提示,36长。凑个整

100*30.

发现输出都从左上角开始,所以需要定位光标位置来输出,后续的内容也要运用光标的定位,所以我们要定义一个函数来表示光标定位。

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);
}

构建欢迎界面,(简介版)

dw(40, 15);
wprintf(L"欢迎来到贪吃蛇游戏");//用wprintf来输出宽字符,L表示后面的是宽字符,如中文等。
dw(40, 16);
system("pause");

到下一个界面我们要清空当前界面。

system("cls");来清空界面

system("cls");  // 清屏操作
dw(40, 16);     // 调用dw函数,参数为40和16
system("pause");// 暂停程序执行

下一步设置我们的提示

按W.S.A.D移动,F4加速,F5减速,space暂停,Esc退出。

定位要的位置输出数据,调整位置让它 看起居中。

dw(24, 15);
wprintf(L"按W.S.A.D移动,F4加速,F5减速,space暂停,Esc退出。");
dw(40, 16);
printf("加速能得到更高的分数");
dw(40, 17);
system("pause");

构建游戏界面

构建蛇的活动范围墙

发现高度不够扩高一点到40;下移墙,在顶上标识提示词表明游戏界面。

system("cls");
int i = 0, j = 0;
for (i = 3; i < 30; i++)
{
    dw(0, i);
    for (j = 0; j < 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");

右边加入提示词

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制作");

发现函数太长了,分别封装成函数。

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 < 30; i++)
    {
        dw(0, i);
        for (j = 0; j < 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();
}

这样就完成了所有的界面的制作。

游戏本体

创建蛇

蛇由一个个节点组成,用链表来创建。重命名一下方便使用

typedef struct snakebody {
    struct tcs* next;
    int x;
    int y;
}snake,st;

有蛇,有果子,有速度。用一个结构体来表示。

蛇可以用头节点来表示。

果可以看作一个在外的蛇身。

typedef struct tcs{
    snake* head;
    int v;
    snake* guo;
}tcs;

还要有状态,方向,总分数,单个果子的权重。

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;

初始化一下蛇的身体。

尾插链表来初始蛇身

void push(snake**ps,int x,int y) {//插入蛇的节点
    snake* news = (snake*)malloc(sizeof(snake));//开辟节点
    news->next = NULL;
    news->x = x;
    news->y = y;
    if (*ps == NULL) {
        *ps = news;
    }
    else
    {
        snake* pos = *ps;
        while (pos->next) {//链接到末尾
            pos = pos->next;
        }
        pos->next = news;
    }
}

snake* body = (snake*)malloc(sizeof(snake));
body = NULL;
int i;
for (i = 22; i < 27; i = i + 1) {
    push(&body,22+(i-22)*2, 16);
}
ps->head = body;
print(ps);

void print(snake*ps) {//打印蛇
	assert(ps);
	snake* cur = ps;
	while (cur) {//遍历链表
		dw(cur->x, cur->y);
		wprintf(L"蛇");
		cur = cur->next;
	}
}
tcs* cjsnake() {//返回蛇的头位置
	tcs*ps = (tcs*)malloc(sizeof(tcs));
	snake* body = (snake*)malloc(sizeof(snake));
	body = NULL;
	int i;
	for (i = 22; i < 27; i = i + 1) {//循环添加5个节点
		push(&body,22+(i-22)*2, 16);
	}
	ps->head = body;
	print(ps->head);//打印开始的蛇身
	cjguo(ps);
	ps->v = 200;
	ps->zt = OK;
	ps->fx = LEFE;
	ps->score = 0;
	ps->food_weight = 10;
	return ps;
}

下一步生成果子,要有随机数要包含#include<time.h>

设置随机数

srand(time(NULL))

void cjguo(tcs* ps) {
    snake* news = (snake*)malloc(sizeof(snake));
    news->next = NULL;
    snake* cur = ps->head;
    ag:
    news->x = (rand()%25+1+1)*2;//第一个+1是保证1到25,后一个+1,是不能是墙
    news->y = (rand() % 25 + 1+4 );
    cur = ps->head;
    while (cur){
        if (cur->x == news->x && cur->y == news->y)//如果和蛇重叠重新生成。
            goto ag;
        cur = cur->next;
    }
    ps->guo = news;
    dw(news->x, news->y);
    wprintf(L"果");//打印果的位置
}

设置其他数据

    ps->v = 200;//速度
    ps->zt = OK;//状态
    ps->fx = LEFT;//方向
    ps->score = 0;//成绩
    ps->food_weight = 10;//每个果子的分数

创建完毕

蛇的行走

while (cur->zt == OK) {
dw(60, 6);
wprintf(L"时间:%.2f秒", sj);
dw(60, 8);
printf("得分:%d", cur->score);
dw(60, 9);
printf("食物分值:%d", cur->food_weight);
snakedong(cur);//行动的函数
sj+=cur->v/1000.0;//行动时间
Sleep(cur->v);//行动间隔
}

设置循环判断游戏状态。可以再加入时间

设置程序的休息时间,来实现运动间隔。

要控制程序,需要读取输入信息,所以定义一个读取的宏

#define KEY_PRESS(vk)   ((GetAsyncKeyState(vk)&1)?1:0)

读取一个虚拟键盘值,判断是否按过。

if (KEY_PRESS(0x53) && snake->fx != UP) {//识别W
	snake->fx = DOWN;
}
else if (KEY_PRESS(0x57) && snake->fx != DOWN) {//识别S
	snake->fx = UP;
}
else if (KEY_PRESS(0x41) && snake->fx != RIGHT) {//识别A
	snake->fx = LEFE;
}
else if (KEY_PRESS(0x44) && snake->fx != LEFE) {//识别B
	snake->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->zt = END_NORMAL;
}
else if (KEY_PRESS(VK_F4)) {//识别F4
	snake->v = snake->v - 10;
	snake->food_weight = snake->food_weight + 5;
}
else if (KEY_PRESS(VK_F5)) {//识别F5
	snake->v = snake->v + 10;
	snake->food_weight = snake->food_weight - 5;
}

加入一个全局变量防止加速过头

根据蛇的方向来改变蛇的身体坐标

snake* toupush(snake*ps,int x,int y) {//插入头部,到达的节点
	snake* news = (snake*)malloc(sizeof(snake));
	news->next = ps;
	news->x = x;
	news->y = y;
	dw(news->x, news->y);
	wprintf(L"蛇");
	ps = news;
	return ps;
}
snake* pop(snake* ps) {//没吃到果子,删除多出来的节点
	snake* tail = ps;
	while (tail->next->next) {
		tail = tail->next;
	}
	dw(tail->next->x, tail->next->y);
	wprintf(L"  ");
	free(tail->next);
	tail->next = NULL;
	return ps;
}
if (snake->fx == UP) {//向上
	snake->head=toupush(snake->head, snake->head->x, snake->head->y - 1);
}
else if (snake->fx == DOWN) {//向下
	snake->head=toupush(snake->head, snake->head->x, snake->head->y + 1);
}
else if (snake->fx == LEFE) {//向左
	snake->head=toupush(snake->head, snake->head->x-2, snake->head->y );
}
else if (snake->fx == RIGHT) {//向右
	snake->head=toupush(snake->head, snake->head->x+2, snake->head->y );
}
if (snake->head->x != snake->guo->x || snake->head->y != snake->guo->y)//是否吃到果子
	snake->head=pop(snake->head);//没吃到,删除尾节点
else {
	free(snake->guo);//释放果子的节点
	snake->guo = NULL;
	cjguo(snake);//重新生成果子
	snake->score += snake->food_weight;//加分
}

吃到果子就不删尾,分数加权重,没吃到就删尾。

编写失败条件。

if (snake->head->x == 0 || snake->head->x == 52 || snake->head->y == 4 || snake->head->y == 29)//到达墙体
	snake->zt = DIE_BYWALL;//改变状态
st* self = snake->head->next;
	while (self) {//遍历自身,看是否相交
		if (snake->head->x == self->x && snake->head->y == self->y)
			snake->zt = DIE_BYSELF;//如相交更新状态
		self = self->next;
	}

结束后输出分数

system("cls");
dw(40, 15);
if (cur->zt == DIE_BYSELF)
	wprintf(L"失败于撞到自己");
if (cur->zt == DIE_BYWALL)
	wprintf(L"失败于撞墙");
if (cur->zt == END_NORMAL)
	wprintf(L"正常退出");
dw(40, 16);
wprintf(L"你坚持的时间是%.2f秒", sj);
dw(40, 17);
wprintf(L"你的得分是%d",cur->score);

隐藏光标

void gbyc() {
	//获取标准输出设备的句柄;
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//定义一个光标结构体
	CONSOLE_CURSOR_INFO cursor_info = { 0 };
	//获取houtput句柄相关的控制台上的光标信息,存放cursor_info
	GetConsoleCursorInfo(houtput, &cursor_info);
	//设置吧光标的占比
	cursor_info.bVisible = false;//光标消失
	//设置和houtput句柄相关的控制台的光标信息
	SetConsoleCursorInfo(houtput, &cursor_info);
}
void ck() {
	//创建窗口
	setlocale(LC_ALL, "");
	COORD pos = { 0,0 };
	system("mode con cols=100 lines=40");
	system("title.贪吃蛇");
	gbyc();
	//打印开始界面
}

到这里已经全部完成了。

总结

到此这篇关于用c++写控制台贪吃蛇游戏完整步骤的文章就介绍到这了,更多相关c++写控制台贪吃蛇内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++使用CriticalSection实现线程同步实例

    C++使用CriticalSection实现线程同步实例

    这篇文章主要介绍了C++使用CriticalSection实现线程同步实例,是使用CriticalSection对前文实例的扩展,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-10-10
  • C语言实现简易贪吃蛇游戏的示例代码

    C语言实现简易贪吃蛇游戏的示例代码

    这篇文章主要介绍了如何利用C语言实现一个经典的小游戏——贪吃蛇,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
    2022-10-10
  • Qt实现卡牌对对碰游戏(附demo)

    Qt实现卡牌对对碰游戏(附demo)

    本文主要介绍了Qt实现卡牌对对碰游戏,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-10-10
  • 详解如何使用C++写一个线程安全的单例模式

    详解如何使用C++写一个线程安全的单例模式

    这篇文章主要为大家详细介绍了如何使用C++写一个线程安全的单例模式,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2022-10-10
  • C语言实现清空指定文件夹中所有文件的方法

    C语言实现清空指定文件夹中所有文件的方法

    这篇文章主要介绍了C语言实现清空指定文件夹中所有文件的方法,实例分析了C语言实现文件删除的相关技巧,需要的朋友可以参考下
    2015-06-06
  • 解析鸿蒙轻内核静态内存的使用

    解析鸿蒙轻内核静态内存的使用

    摘要:静态内存实质上是一个静态数组,静态内存池内的块大小在初始化时设定,初始化后块大小不可变更。静态内存池由一个控制块和若干相同大小的内存块构成。控制块位于内存池头部,用于内存块管理。内存块的申请和释放以块大小为粒度
    2021-06-06
  • C++ Futures与Promises线程使用示例讲解

    C++ Futures与Promises线程使用示例讲解

    future和promise的作用是在不同线程之间传递数据。使用指针也可以完成数据的传递,但是指针非常危险,因为互斥量不能阻止指针的访问;而且指针的方式传递的数据是固定的,如果更改数据类型,那么还需要更改有关的接口,比较麻烦
    2022-11-11
  • C语言异常处理机制案例讲解

    C语言异常处理机制案例讲解

    这篇文章主要介绍了C语言异常处理机制案例讲解,本文讲解了异常处理机制所用的函数和具体的代码实现等,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言中的内存泄露 怎样避免与检测

    C语言中的内存泄露 怎样避免与检测

    堆经常会出现两种类型的问题:1.释放或改写仍在使用的内存(称为:“内存损坏”)。2.未释放不再使用的内存(称为:“内存泄露”)。这是最难被调试发现的问题之一
    2013-09-09
  • 在C++17中实现无锁数据结构的方法详解

    在C++17中实现无锁数据结构的方法详解

    在探索 C++17 中的无锁数据结构之前,我们首先需要理解无锁编程的基本概念及其在现代软件开发中的重要性,在这个章节中,我们将深入探讨无锁编程的概念,以及它如何满足人类对于更高效、更可靠软件的本能需求,文中通过代码示例介绍的非常详细,感兴趣的朋友可以参考下
    2023-12-12

最新评论