C语言实现贪吃蛇(简易)

article/2025/10/26 8:42:43

文章目录

目录

文章目录

前言

一、游戏功能和效果

1.游戏功能

2.游戏效果 

二. 游戏初步实现

 1.确定地图大小

2.创建蛇对象,食物对象 

 3.初始化蛇

 4.生成随机食物

5.画蛇 

 6.画食物

7. 游戏内移动控制

1.当按上下左右时移动方向改变 。

 2.开始游戏时的默认方向

 8.判断蛇撞墙,撞身体,撞食物3种情况

1.蛇撞墙:判断蛇头坐标是否和行和列相等,如果相等游戏结束!

2.蛇撞身体:判断蛇头坐标是否和蛇身坐标相等,如果相等游戏结束!

3.蛇撞食物:撞到食物后当前长度增加,再重新生成食物,移动速度变快,分数增加!

4.和蛇移动结合 

 9.画墙和初步实现

 1.画墙 

 2.初步实现

三.游戏的改进与完善

1.解决频闪 

2.去掉蛇尾 

3.去除光标 

四、完整游戏代码

1.game.h文件

 2.test.c文件

总结


前言

本文使用C语言做出简易的贪吃蛇程序,此程序比较简单,适合新手入门或小白。

在这里主要实现一个简易蛇的移动和方向的控制。以及当蛇撞到墙壁,身体,食物这几种情况的判断。

一、游戏功能和效果

1.游戏功能

1.wasd,控制蛇移动的方向。

2.每吃到一个食物移动速度变快。

3.游戏结束显示游戏分数(吃到食物+10分)

2.游戏效果 

二. 游戏初步实现

根据上图可以看到游戏界面大致可以分为3个:1.蛇的图形 2.产生的食物 3.周围的墙壁。(这里‘#’代表食物,‘*’代表蛇身,‘@’代表蛇头)

再细分的话:1.创建蛇的结构体,初始化,改变光标位置,画蛇。2.创建食物结构体,在地图中随机放食物。3.让蛇动起来,用4个键控制蛇的方向,撞到食物身体增长,碰到墙壁结束。4.画墙。 

 1.确定地图大小

 实现程序要有一个适当的范围,行和列可以使用两层for循环来确定:例如20行80列

 

 确定后在头文件定义row和col为20,80就可以了。

2.创建蛇对象,食物对象 

//蛇身对象
struct BODY
{
int X;
int Y;
};
//蛇对象
struct SNAKE
{
struct BODY body[ROW*COL];//蛇身最大长度
int size;//当前长度
}snake;//食物对象
struct FOOD
{
int X;
int Y;
}food;

 3.初始化蛇

 这里根据效果图,蛇要居中,那么x,y坐标是行和列的1半。

 蛇头是正中间,坐标是第一个:snake.body[0]。

蛇身就是从1开始的下标,第1个下标减1:snake.body[1].X = COL / 2 - 1;是第一节蛇身,第2个下标减2是第二节蛇身,那么使用for循环控制蛇身的长度。

void Initsnake()
{//初始化蛇头snake.size = 4;snake.body[0].X = COL / 2;snake.body[0].Y = ROW / 2;//初始化蛇身int i = 0;for (i = 1; i <= snake.size; i++){snake.body[i].X = COL / 2 - i;snake.body[i].Y = ROW / 2;}
}

 4.生成随机食物

将生成的随机数%上行和列,控制在范围内,赋值到food的X,Y坐标上。 

void Initfood()//生成食物
{food.X = rand() % COL;food.Y = rand() % ROW;
}

5.画蛇 

在画蛇时我们要在地图的中间进行画蛇,那么怎么才能在中间呢?

一般在我们打字时,后面都有一个光标,光标在哪字就打在哪。所以在这里需要设置光标的位置,使他在中间就可以了。这里要用到光标修改函数:我们把相应的坐标给这个函数,就会定位到相应的位置。

void InitUI()
{//画蛇COORD coord = { 0 };int i = 0;for (i = 0; i < snake.size; i++)//改变光标位置{coord.X = snake.body[i].X;coord.Y = snake.body[i].Y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);if (i == 0){putchar('@');}else{putchar('*');}}

 在这里我们直接使用就可以,当i==0时,就画蛇头,其他情况就是蛇尾,画‘*’号。

 6.画食物

和画蛇相同 

//画食物    
            coord.X = food.X;
            coord.Y = food.Y;
            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
            putchar('#'); 

7. 游戏内移动控制

1.当按上下左右时移动方向改变 。

这里可以看图:这里蛇头的坐标是(6,4),当按下上键坐标为(6,3),按下键为(6,5)当按左键右键时,坐标为(5,4),(7,4)。

那么改变方向只需要将X与Y坐标进行+1,-1就可以实现,这里我们定义两个全局变量kx,ky。

 2.开始游戏时的默认方向

 当我们打开游戏,如果不按方向键,蛇也会默认向一个方向移动,这里我们要使用非阻塞方式检测是否有输入:kbhit()函数和无回显的取一个字符:getch()函数。

 

 具体写法如下:默认向右移动,当有键盘输入时改变方向。

 8.判断蛇撞墙,撞身体,撞食物3种情况

 这里可以使用while()来将这3种情况和蛇移动放在一起,进行实现。

1.蛇撞墙:判断蛇头坐标是否和行和列相等,如果相等游戏结束!

while (snake.body[0].X >= 0 && snake.body[0].X < COL&&
        snake.body[0].Y >= 0 && snake.body[0].Y < ROW)
    {

2.蛇撞身体:判断蛇头坐标是否和蛇身坐标相等,如果相等游戏结束!

//蛇头撞身体
        int i = 0;
        for (i = 1; i < snake.size; i++)
        {
            if (snake.body[0].X == snake.body[i].X&&snake.body[0].Y == snake.body[i].Y)
            {
                return;
            }
        }

3.蛇撞食物:撞到食物后当前长度增加,再重新生成食物,移动速度变快,分数增加!

//蛇头撞食物
        if (snake.body[0].X == food.X&&snake.body[0].Y == food.Y)
        {
            snake.size++;//身体增长
            Initfood();//食物消失
            result += 10;//加分
            if (speed != 60)
            {
                speed -= 30;//速度增加,到最大速度时停止
            }
        } 

4.和蛇移动结合 

void Playgame()//游戏控制
{
    char key = 'd';
    //蛇撞墙    
    while (snake.body[0].X >= 0 && snake.body[0].X < COL&&
        snake.body[0].Y >= 0 && snake.body[0].Y < ROW)
    {
     
        //接收按键输入
        if (_kbhit())
        {
            key = _getch();
        }
        switch (key)
        {
        case 'w':kx = 0; ky = -1; break;
        case 's':kx = 0; ky = +1; break;
        case 'd':kx = +1; ky = 0; break;
        case 'a':kx = -1; ky = 0; break;
        default:
            break;
        }
        //蛇头撞身体
        int i = 0;
        for (i = 1; i < snake.size; i++)
        {
            if (snake.body[0].X == snake.body[i].X&&snake.body[0].Y == snake.body[i].Y)
            {
                return;
            }
        }
        //蛇头撞食物
        if (snake.body[0].X == food.X&&snake.body[0].Y == food.Y)
        {
            snake.size++;//身体增长
            Initfood();//食物消失
            result += 10;//加分
            if (speed != 60)
            {
                speed -= 30;//速度增加,到最大速度时停止
            }
        }
 

 9.画墙和初步实现

 1.画墙 

void Initwall()//画墙
{int i = 0;int j = 0;for (i = 0; i <= ROW; i++){for (j = 0; j <= COL; j++){if (i == 0){printf("-");}else if (i == ROW){printf("-");}else if (j == 0){printf("|");}else if (j == COL){printf("|");}else{printf(" ");}}printf("\n");}
}

 2.初步实现

将墙画好后,蛇还不能移动,我们先看图:

蛇原来的坐标是(6,5)(6,4)6,3)(6,2),当向前走1格后是(6,6)(6,5)(6,4)(6,3)。

原来蛇头的坐标(6,5)给第一节蛇身,第一节蛇身给第2节,以此类推。也就是蛇头的坐标根据方向进行+1或-1,蛇身由上一节的进行赋值。

写好后再用清屏函数system("cls")进行更新,就可以初步实现!

但是运行后发现不断清屏会出现频闪,游戏效果非常不好!

 

三.游戏的改进与完善

1.解决频闪 

初步完成后,蛇确实可以跑起来,但游戏体验太差!下面解决频闪问题! 

这里第一想到的便是将清屏函数去掉换成延时函数:Sleep(),这样不需要一直更新,但又会出现新的问题:后面蛇尾会一直在,不会消失!那么就需要将最后一节蛇尾去掉。 

2.去掉蛇尾 

首先我们将蛇尾的坐标存起来:

//存储蛇尾的坐标
        lastX = snake.body[snake.size - 1].X;
        lastY = snake.body[snake.size - 1].Y;
 

然后我们在画蛇的函数中InitUI() ,将蛇尾坐标变成空格:

//去除蛇尾
    coord.X = lastX;
    coord.Y = lastY;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
    putchar(' ');
 

到这里我们就完美的解决掉问题了! 最后将光标去除就好了!!

3.去除光标 

这里直接使用此函数就可以! 

 

四、完整游戏代码

1.game.h文件

#ifndef __GAME_H__
#define __GAME_H__
//定义行和列
#define ROW 20
#define COL 80
//头文件
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<conio.h>
#include<string.h>
#include<windows.h>void Initsnake();//初始化蛇
void Initfood();//初始化食物
void InitUI();//画蛇
void Initwall();//画墙
void Playgame();//游戏:控制int speed = 300;//初始速度
int result = 0;//游戏分数
lastX = 0;//存放蛇尾坐标
lastY = 0;
int kx = 0;//方向控制
int ky = 0;//蛇身结构体
struct BODY
{int X;int Y;
};//创建蛇结构体
struct SNAKE
{struct BODY body[ROW*COL];//蛇身最大长度int size;//长度
}snake;//创建食物结构体
struct FOOD
{int X;int Y;
}food;#endif

 2.test.c文件

#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"void Initsnake()
{//初始化蛇头snake.size = 4;snake.body[0].X = COL / 2;snake.body[0].Y = ROW / 2;//初始化蛇身int i = 0;for (i = 1; i <= snake.size; i++){snake.body[i].X = COL / 2 - i;snake.body[i].Y = ROW / 2;}
}void Initfood()//生成食物
{food.X = rand() % COL;food.Y = rand() % ROW;
}void InitUI()
{//画蛇COORD coord = { 0 };int i = 0;for (i = 0; i < snake.size; i++)//改变光标位置{coord.X = snake.body[i].X;coord.Y = snake.body[i].Y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);if (i == 0){putchar('@');}else{putchar('*');}}//去除蛇尾coord.X = lastX;coord.Y = lastY;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);putchar(' ');//画食物	coord.X = food.X;coord.Y = food.Y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);putchar('#');//结束时,改变位置coord.X = 0;coord.Y = ROW + 2;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void Initwall()//画墙
{int i = 0;int j = 0;for (i = 0; i <= ROW; i++){for (j = 0; j <= COL; j++){if (i == 0){printf("-");}else if (i == ROW){printf("-");}else if (j == 0){printf("|");}else if (j == COL){printf("|");}else{printf(" ");}}printf("\n");}
}void Playgame()//游戏控制
{char key = 'd';//蛇撞墙	while (snake.body[0].X >= 0 && snake.body[0].X < COL&&snake.body[0].Y >= 0 && snake.body[0].Y < ROW){InitUI();//更新蛇//接收按键输入if (_kbhit()){key = _getch();}switch (key){case 'w':kx = 0; ky = -1; break;case 's':kx = 0; ky = +1; break;case 'd':kx = +1; ky = 0; break;case 'a':kx = -1; ky = 0; break;default:break;}//蛇头撞身体int i = 0;for (i = 1; i < snake.size; i++){if (snake.body[0].X == snake.body[i].X&&snake.body[0].Y == snake.body[i].Y){return;}}//蛇头撞食物if (snake.body[0].X == food.X&&snake.body[0].Y == food.Y){snake.size++;//身体增长Initfood();//食物消失result += 10;//加分if (speed != 60){speed -= 30;//速度增加,到最大速度时停止}}//存储蛇尾的坐标lastX = snake.body[snake.size - 1].X;lastY = snake.body[snake.size - 1].Y;//蛇移动,前一节身体给后一节身体赋值for (i = snake.size - 1; i > 0; i--){snake.body[i].X = snake.body[i - 1].X;snake.body[i].Y = snake.body[i - 1].Y;}snake.body[0].X += kx;snake.body[0].Y += ky;Sleep(speed);}return;
}void game()//游戏函数
{	//去除光标CONSOLE_CURSOR_INFO cci;cci.dwSize = sizeof(cci);cci.bVisible = FALSE;SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);//初始化蛇Initsnake();//初始化食物Initfood();//画墙Initwall();//画蛇InitUI();//游戏控制Playgame();//成绩printf("Game over!游戏结束!\n");printf("游戏分数:%d\n", result);
}int main()
{srand((unsigned int)time(NULL));game();//游戏函数return 0;
}


总结

以上就是今天贪吃蛇的内容,主要就是蛇移动的实现比较难。这里就是比较简单实现方法,230行左右就可以实现,还是比较容易理解的!可以根居其他的加一些功能来进行完善!


http://chatgpt.dhexx.cn/article/fCgLgrtD.shtml

相关文章

C语言贪吃蛇小游戏,贪吃蛇C语言代码实现大全

一、C语言贪吃蛇代码实现前言 设计贪吃蛇游戏的主要目的是让大家夯实C语言基础&#xff0c;训练编程思维&#xff0c;培养解决问题的思路&#xff0c;领略多姿多彩的C语言。 贪吃蛇是非常经典的一款游戏&#xff0c;本次我们模拟在控制台实现贪吃蛇游戏&#xff0c;也就是实现…

C语言实现贪吃蛇[内附详细步骤]

C语言贪吃蛇项目 今天给分享一下使用C语言写个贪吃蛇小游戏&#xff0c;主要包含以下10部分内容&#xff1a; 1、windows光标定位与隐藏 2、欢迎界面 3、打印围墙 4、产生食物 5、初始化蛇身 6、响应按键 7、蛇身运动 8、碰撞检测 9、结束界面 10、程序运行 windows…

C语言实现贪吃蛇小游戏!(超简单详细)详细思路+源码分享

贪吃蛇&#xff08;也叫做贪食蛇&#xff09;游戏是一款休闲益智类游戏&#xff0c;有PC和手机等多平台版本。既简单又耐玩。该游戏通过控制蛇头方向吃蛋&#xff0c;从而使得蛇变得越来越长。 我们的今天的目标就是&#xff1a;用C语言来实现一个贪吃蛇项目&#xff0c;也不用…

C语言 贪吃蛇

基于C语言编写的贪吃蛇 编写环境&#xff1a;VS2019x86 这是一个基于C语言链表开发的贪吃蛇游戏 其实贪吃蛇游戏要解决的主要问题就是 1、这个游戏的基本组成元素和数据结构 2、如何初始化贪吃蛇并正常行走 3、如何判断事件发生 代码中运用到了键盘虚拟键判断、终端窗口大小的…

游戏贪吃蛇(c语言)

游戏贪吃蛇&#xff08;c语言&#xff09; 一、项目背景二、设计目的三、项目功能需求1、初始化游戏2、控制蛇的运行轨迹3、控制蛇的长度4、控制食物生成5、计算分数6、结束条件 四、系统的功能结构图五、总体设计1、初始化模块2、游戏控制模块3、运行控制模块4、食物生成模块 …

C语言实现贪吃蛇(详细版)

一、需要掌握的知识&#xff1a; C语言基础语法&#xff08;结构体、指针、链表&#xff09;、<windows.h>库、<stdlib.h>库、<time.h>库中的一些函数&#xff08;不需要额外学习&#xff0c;本文后面会讲贪吃蛇需要用到的相关函数&#xff09; 由于作者水平…

贪吃蛇(C语言实现)

文章目录 游戏说明游戏效果展示游戏代码游戏代码详解游戏框架构建隐藏光标光标跳转初始化界面颜色设置初始化蛇随机生成食物打印蛇与覆盖蛇移动蛇游戏主体逻辑函数执行按键判断得分与结束从文件读取最高分更新最高分到文件主函数 游戏说明 游戏界面当中没有打印相关的按键说明…

SDRAM控制器(初始化)

SDRAM控制器&#xff08;初始化&#xff09; 文章目录 SDRAM控制器&#xff08;初始化&#xff09;初始化模块时序逻辑图代码仿真结果 初始化模块 SDRAM 在上电之后&#xff0c;执行正常操作之前需要被初始化&#xff0c;实际上就是对上文提到的SDRAM 内部逻辑控制单元进行初始…

SDRAM 控制器设计基本完结

项目可以拓展的地方&#xff1a; 1、接口为AXI 2、接口为AXI与AXI DMA 交互 2、优化读写时序&#xff0c;使得SDRAM输出效率最大&#xff1b; 总结&#xff1a; 项目不足&#xff1a;没有进行效率的优化&#xff0c;无地址映射&#xff0c;无外接交互接口&#xff0c;功能单一…

SDRAM读写控制

SDRAM读写控制器&#xff0c;这里分为三个部分&#xff0c;分别是SDRAM的基本操作实现&#xff0c;SDRAM控制器&#xff0c;封装成FIFO,以方便使用。 一、SDRAM的基本操作&#xff1a;初始化模块、自动刷新模块、写操作模块、读操作模块、SDRAM仲裁模块&#xff0c;顶层模块。 …

SDRAM 控制器(二)——初始化模块

1、初始化模块 SDRAM 的初始化是芯片上电后必须进行的一项操作&#xff0c;只有进行了初始化操作的 SDRAM 芯片才可被正常使用。SDRAM 的初始化是一套预先定义好的流程&#xff0c;除此之外的其 他操作会导致 SDRAM 出现不可预知的后果。 初始化时序图&#xff1a; CK&#xf…

SDRAM详细介绍

概念介绍&#xff1a; SDRAM&#xff1a;Synchronous Dynamic Random Access Memory&#xff0c;同步动态随机存储器。同步是指其时钟频率和CPU前端总线的系统时钟相同&#xff0c;并且内部命令的发送与数据的传输都以它为基准&#xff1b;动态是指存储阵列需要不断的刷新来保证…

sdram简易控制器设计

耗时一周&#xff0c;终于完成sdram简易控制器的所有代码设计&#xff0c;其中感谢开源骚客 – 邓堪文老师在b站发布的相关视频学习教材&#xff1b;其中仿真模块及所使用到的sdram仿真文件来源于开源骚客&#xff1b; 因为时间较为紧迫&#xff0c;其中就不做代码的一些注释&…

基于FPGA的SDRAM控制器设计(一)

基于FPGA的SDRAM控制器设计&#xff08;一&#xff09; 1. SDRAM控制器整体框架2.UART_RX模块3.UART_TX模块4. RX与TX模块的整合5.需要注意的问题6.代码7.参考资料 1. SDRAM控制器整体框架 图1.1整体框架 PC端通过串口模块UART_RX发送读写命令以及数据到Cmd_encode模块&#xf…

基于FPGA的SDRAM控制器设计(1)

基于FPGA的SDRAM初始化配置 SDRAM简述SDRAM的引脚及作用SDRAM初始化时序控制SDRAM上电时序代码SDRAM测试模块的代码仿真测试结果参考文献总结 SDRAM简述 SDRAM&#xff08; Synchronous Dynamic Random Access Memory&#xff09;&#xff0c;同步动态随机存储器。同步是指 Me…

FPGA进阶(3):SDRAM读写控制器的设计与验证

文章目录 第50讲&#xff1a;SDRAM读写控制器的设计与验证理论部分设计与实现1. sdram_ctrlsdram_initsdram_a_refsdram_writesdram_readsdram_arbitsdram_ctrl 2. sdram_topfifo_ctrlsdram_top 3. uart_sdramuart_rxuart_txfifo_readuart_sdram 第50讲&#xff1a;SDRAM读写控…

SDRAM

简介、优缺点、历史 1、译为“同步动态随机存取内存”&#xff0c;区别于异步DRAM。SRAM是异步静态存储器。 2、同步(Synchronous)&#xff1a;与通常的异步 DRAM 不同&#xff0c; SDRAM 存在一个同步接口&#xff0c;其工作时钟的时钟频率与对应控制器(CPU/FPGA上的读写控制…

关于SDRAM存储器

一、对SDRAM的初步认识 1.1 什么是SDRAM SDRAM&#xff08;Synchronous Dynamic Random Access Memory&#xff09;&#xff0c;同步动态随机存取存储器。 同步&#xff1a;工作频率与对应控制器的系统时钟频率相同&#xff0c;且内存内部的命令以及数据的传输都以此为基准 …

内存控制器与SDRAM

内存接口概念&#xff1a; 通常ARM芯片内置的内存很少&#xff0c;要运行Linux&#xff0c;需要扩展内存。ARM9扩展内存使用SDRAM内存&#xff0c;ARM11使用 DDR SDRAM。S3C2440通常外接32位64MBytes的SDRAM&#xff0c;采用两片16位32M的SDRAM芯片&#xff0c;SDRAM芯片通过地…

SDRAM驱动篇之简易SDRAM控制器的verilog代码实现

在Kevin写的上一篇博文《SDRAM理论篇之基础知识及操作时序》中&#xff0c;已经把SDRAM工作的基本原理和SDRAM初始化、读、写及自动刷新操作的时序讲清楚了&#xff0c;在这一片博文中&#xff0c;Kevin来根据在上一篇博文中分析的思路来把写一个简单的SDRAM控制器。 我们在上一…