C语言贪吃蛇游戏的实现-链表的使用

前言

本文使用C语言在STM32内实现贪吃蛇游戏,然后用LCD显示屏讲整个游戏显示出来。
在编写贪吃蛇的过程工涉及到只是有,结构体的定义,指针,链表,以及一些STM32微处理器的相关知识。贪吃蛇对流程控制以及相关知识运用是检验学习C语言的成果水平,以下让我们学习一下贪吃蛇的编写。

初始化定义

定义蛇身结构体并且此结构体包含链表。
解释:U8为unsigned char 。下面出现的U8同属:
此结构体包含XY以及下一个食物的地址。

struct snake_body{U8 Snake_X; U8 Snake_Y;struct snake_body *snake_next;
}; //蛇身链表typedef struct snake_body SNAKE_BODY;

然后规定一些主要边界参数:
主要以宏定义为主,由于LCD限制的原因只能设置蛇左右运动宽度为16,高度为5。
随机数也是,随机数用于控制食物地点。因此需要绘制出16*5的画布。

#define SNAKE_STRUCT_LEN sizeof(SNAKE_BODY)
#define SNAKE_AXIS_X  16           //XY轴设置
#define SNAKE_AXIS_Y  5
#define SNAKE_RAND_X  17           //随机数据上限
#define SNAKE_RAND_Y  6

变量定义

以下为变量定义以及相关解释

SNAKE_BODY* Sanke_Body;   //蛇身链表
U8 Sanke_Len = 1;         //蛇身长度
U8 Direct_Flag = 4;       //方向标志位-默认向右
U8 snake_RefleshFg = 0;   //刷新标志位
U8 Game_Result = 0;       //游戏结果
U8 Game_Score = 0;        //记分
U8 Snake_Speed = 1;       //速度控制
U8 Sanke_Fool_Buf[2];     //食物数组

基本函数

以下有几个基本函数说明:
1.将当前吃到的食物更新到链表内:

// *****************************************************************************
// 函数名称:Convert_StructMap
// 功能描述:修改对应数据
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Convert_StructMap(SNAKE_BODY body_temp,U8 len)
{U8 i = 0;U8 *p_map;SNAKE_BODY struct_temp = body_temp;//处理食物-显示食物if(Sanke_Fool_Buf[0]!=0 && Sanke_Fool_Buf[1]!=0){p_map = &Game_Map[(Sanke_Fool_Buf[1]-1)][(Sanke_Fool_Buf[0]-1)*8];*p_map++=0x3f;*p_map++=0x33;*p_map++=0x21;*p_map++=0x21;*p_map++=0x33;*p_map=0x3f;}for(i = 0;i<len;i++){p_map = &Game_Map[(struct_temp.Snake_Y-1)][(struct_temp.Snake_X-1)*8];//链表数据处理*p_map++=0x3f;if(i==0){*p_map++=0x3f;*p_map++=0x33;*p_map++=0x33;*p_map++=0x3f;}else{*p_map++=0x3f;*p_map++=0x3f;*p_map++=0x3f;*p_map++=0x3f;       }*p_map=0x3f;//获取下个链表if(struct_temp.snake_next!=NULL){struct_temp = *struct_temp.snake_next;}}
}

2.刷新地图

// *****************************************************************************
// 函数名称:Update_Map
// 功能描述:更新地图-贪吃蛇
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Update_Map(void)
{U8 draw_i = 0;if(!Game_Result){for(draw_i = 0;draw_i<SNAKE_AXIS_Y;draw_i++){//将地图绘制到LCD屏幕里面的OLED_DrawBMP(0,draw_i+2,128,draw_i+3,Game_Map[draw_i]);}}
}

3.清理地图以及链表数据

// *****************************************************************************
// 函数名称:Clear_Map
// 功能描述:根据链表清空地图
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Clear_Map(void)
{U8 i = 0;U8 *p_map;SNAKE_BODY struct_temp = *Sanke_Body;for(i = 0;i<Sanke_Len;i++){p_map = &Game_Map[(struct_temp.Snake_Y-1)][(struct_temp.Snake_X-1)*8];//链表数据处理*p_map++=0x00;*p_map++=0x00;*p_map++=0x00;*p_map++=0x00;*p_map++=0x00;*p_map=0x00;//获取下个链表if(struct_temp.snake_next!=NULL){struct_temp = *struct_temp.snake_next;}}OLED_Clear_Row(2,6);
}

贪吃蛇游戏主体

话不多说了,直接上代码。

// *****************************************************************************
// 函数名称:Sanke_Init
// 功能描述:初始化-贪吃蛇
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Sanke_Init(void)
{   //释放空间free(Sanke_Body); //申请空间Sanke_Body = (SNAKE_BODY *)malloc(SNAKE_STRUCT_LEN);Sanke_Body->snake_next = NULL;Sanke_Body->Snake_X = 1; Sanke_Body->Snake_Y = 3;Sanke_Len = 1;     //初始化长度Direct_Flag = 4;   //初始化方向//初始化食物Sanke_Fool_Buf[0] = 8;Sanke_Fool_Buf[1] = 2;   //数据转换Convert_StructMap(*Sanke_Body,Sanke_Len);//画图Update_Map();snake_RefleshFg = 1;  //开始游戏Game_Result = 0;      //结果Game_Score = 0;       //分数
}

此函数主要是初始化一些长度以及方向,起始食物的规定等等。

当吃到食物后进行链表的添加,在链表的头部进行添加,如下:

// *****************************************************************************
// 函数名称:Snake_Add
// 功能描述:增加链表长度
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Snake_Add(U8 snake_x,U8 snake_y)
{   //申请内存SNAKE_BODY* snake_temp = (struct snake_body *)malloc(SNAKE_STRUCT_LEN);snake_temp->Snake_X = snake_x; snake_temp->Snake_Y = snake_y;snake_temp->snake_next = Sanke_Body;  //将当前的链表赋值到刚申请的链表地址内Sanke_Body = snake_temp;Sanke_Len++;
}

蛇身的移动-上下左右方向的移动,注意当前方向不能向反方向移动。

// *****************************************************************************
// 函数名称:Key_Down_Move
// 功能描述:方向选择
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Key_Down_Move(U8 key_type)
{switch(Direct_Flag){case 1://Upif(key_type!=2)Direct_Flag = key_type;break;case 2://Downif(key_type!=1)Direct_Flag = key_type;break;case 3://Leftif(key_type!=4)Direct_Flag = key_type;break;case 4://Rightif(key_type!=3)Direct_Flag = key_type;break;}
}

蛇身的偏移

// *****************************************************************************
// 函数名称:Snake_Offset
// 功能描述:蛇身偏移
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Snake_Offset(U8 direct)
{U8 snake_x = 0,snake_y = 0,i = 0;SNAKE_BODY *struct_temp = Sanke_Body;snake_x = Sanke_Body->Snake_X;snake_y = Sanke_Body->Snake_Y;switch(direct){case 1:snake_y--;if(snake_y<1)snake_y = SNAKE_AXIS_Y;         break;case 2:snake_y++;if(snake_y>SNAKE_AXIS_Y)snake_y = 1;   break;case 3:snake_x--;if(snake_x<1)snake_x = SNAKE_AXIS_X; break;case 4:snake_x++;if(snake_x>SNAKE_AXIS_X)snake_x = 1;break;}        //删除末端数据for(i = 0;i<Sanke_Len-1;i++){struct_temp = struct_temp->snake_next;}free(struct_temp->snake_next);struct_temp->snake_next = NULL;      Sanke_Len--; //增加一个数据Snake_Add(snake_x,snake_y);
}

检查随机数据是否在链表

// *****************************************************************************
// 函数名称:Check_Rand
// 功能描述:检查随机数据是否在链表
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
U8 Check_Rand(U8 rand_x,U8 rand_y,U8 *rand_buf)
{U8 i = 0,result = 0;SNAKE_BODY *struct_temp = Sanke_Body;if(rand_x==0)rand_x+=1;if(rand_y==0)rand_y+=1;for(i = 0;i<Sanke_Len;i++){    //链表数据处理if(struct_temp->Snake_X==rand_x && struct_temp->Snake_Y==rand_y){result = Check_Rand((rand()%SNAKE_RAND_X),(rand()%SNAKE_RAND_Y),rand_buf);}     //获取下个链表if(struct_temp->snake_next!=NULL){struct_temp = struct_temp->snake_next;}}result = 1;*rand_buf++=rand_x;*rand_buf = rand_y;return result;
}

检查蛇身是否碰撞

// *****************************************************************************
// 函数名称:Check_Snake
// 功能描述:检查蛇身是否出现碰撞
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
U8 Check_Snake(U8 sanke_x,U8 sanke_y)
{SNAKE_BODY *struct_temp = Sanke_Body->snake_next;U8 i = 0;for(i = 0;i<Sanke_Len-1;i++){if(sanke_x == struct_temp->Snake_X && sanke_y == struct_temp->Snake_Y)return 1;        if(struct_temp->snake_next!=NULL)struct_temp = struct_temp->snake_next;     }return 0;
}

吃到食物

// *****************************************************************************
// 函数名称:Snake_EatFool
// 功能描述:蛇身增加
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Snake_EatFool(U8 snake_x,U8 snake_y)
{switch(Direct_Flag){case 1:snake_y--;if(snake_y<1)snake_y = SNAKE_AXIS_Y;          break;case 2:snake_y++;if(snake_y>SNAKE_AXIS_Y)snake_y = 1;   break;case 3:snake_x--;if(snake_x<1)snake_x = SNAKE_AXIS_X; break;case 4:snake_x++;if(snake_x>SNAKE_AXIS_X)snake_x = 1;break;}Snake_Add(snake_x,snake_y);
}

关键部分-游戏执行

如下注释:

// *****************************************************************************
// 函数名称:Snake_RunStep
// 功能描述:贪吃蛇-蛇的移动
// 输入参数: /
// 输出参数: /
// 返回参量: /
// *****************************************************************************
void Snake_RunStep(void)
{static U8 time_count = 0;srand(time_count);        //初始化随机数据time_count++;if(SysParam.SysMode==MODE_GAME && time_count%Snake_Speed==0 && snake_RefleshFg == 1){        //清理屏幕    Clear_Map();      //判断蛇头是否吃到食物if(Sanke_Body->Snake_X==Sanke_Fool_Buf[0] && Sanke_Body->Snake_Y==Sanke_Fool_Buf[1]){//链表增加Snake_EatFool(Sanke_Fool_Buf[0],Sanke_Fool_Buf[1]);//产生随机数据Check_Rand((rand()%SNAKE_RAND_X),(rand()%SNAKE_RAND_Y),Sanke_Fool_Buf); //记分Game_Score++;     if(Game_Score>=29)//胜利-由于RAM有限(4K),只能申请到29个链表数据{Game_Stop("  GAME WINNER!!! ");}}else{//进行偏移Snake_Offset(Direct_Flag);//检查是否碰撞if(Check_Snake(Sanke_Body->Snake_X,Sanke_Body->Snake_Y)){Game_Stop("  GAME OVER !!!   ");}}      if(!Game_Result)Convert_StructMap(*Sanke_Body,Sanke_Len);       }
}

以上为贪吃蛇的主要代码,希望对大家有帮助。

C语言编写贪吃蛇-链表的使用相关推荐

  1. 用C语言编写贪吃蛇项目描述,刚学C语言,想写一个贪吃蛇的代码

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include #include typedef struct snake { int a; int b; stru ...

  2. c语言编写贪吃蛇代码无错,刚学C语言,想写一个贪吃蛇的代码

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include #include typedef struct snake { int a; int b; stru ...

  3. c语言编写贪吃蛇难点解析,刚学C语言,想写一个贪吃蛇的代码

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include #include typedef struct snake { int a; int b; stru ...

  4. 如何用c 语言编写贪吃蛇,刚学C语言,想写一个贪吃蛇的代码

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include #include typedef struct snake { int a; int b; stru ...

  5. 用C语言编写贪吃蛇代码(难度可选)

    /********************************************************* ********************贪吃蛇(难道可选)************ ...

  6. c语言安卓贪吃蛇代码下载,C语言贪吃蛇代码

    c语言编写贪吃蛇源代码,简单易懂,文件为VC源代码.如果你正在学习c语言,就来下载吧.很经典的 C语言贪吃蛇代码部分 #include #include #include#include #defin ...

  7. 【笔记】用vs2017 c语言写 贪吃蛇 小游戏

    目录 文章目录 前言 一.贪吃蛇游戏 设计逻辑 二.详细介绍 1.设置界面(界面大小,背景颜色) 2.设置贪吃蛇的身体并显示 3.使之能够移动并能够穿墙 4.添加食物并让蛇吃掉 5.设置背景音乐 完整 ...

  8. C语言与C++基础编写贪吃蛇项目1

    C语言与C++基础编写贪吃蛇项目1 第一阶段: 简单的移动的贪吃蛇编写. 小白编写,勿喷. 一.总体项目功能: 1.添加背景音乐或者动作音效 2.有欢迎界面,游戏选项等界面 3.地图范围内有障碍物,可 ...

  9. c语言mfc写贪吃蛇,手把手教你用MFC编写贪吃蛇.doc

    手把手教你用MFC编写贪吃蛇 贪吃蛇是一款经典的小游戏,它玩法非常简单,对于MFC的初学者来说,也是一个非常好的练手项目.这篇文章,将从项目创建开始来一步一步教你如何制作一个贪吃蛇小游戏.我用的是vi ...

  10. 安卓c语言自动补全软件吾爱,C语言实现贪吃蛇小游戏

    本文实例为大家分享了C语言实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下 一.程序实现的原理: 1.构造蛇身:定义一个坐标数组,存放的是蛇的每一节蛇身所在的坐标位置.这样就将移动蛇身的操作转换为 ...

最新文章

  1. pythonrandint函数左闭右开_Python容器类型公共方法总结
  2. 检测本地计算机是否正确安装网卡驱动,如何检测驱动是否存在问题?
  3. C#看书笔记_02 核心C#
  4. 智慧城市发展路径中 中国特色是主色调
  5. TZOJ 数据结构期末历年题目
  6. android gdb gdbserver
  7. 【面试记录1】爱立信5G基带开发工程师
  8. 图解等差数列和等比数列求和公式
  9. 怎么安装python的数据库5.7.28_Windows下mysql-5.7.28下载、安装、配置教程
  10. 统计小写英文字母的个数 c语言,输入一行字符,统计英文字母,空格,和其他字符的个数...
  11. 微信小程序的wx:for和vue的v-for
  12. WPS格式转换成Word的方法
  13. 抖音上免费涨粉的方法,制作出一个爆款视频!
  14. 样条曲线长度--数值积分
  15. 使用STM32C103C8T6的注意点
  16. 54-基于51单片机GSM模块的家庭防火防盗报警系统
  17. 各厂商接入交换机通过ACL限制端口应用的配置信息
  18. 地震反演近期文章阅读
  19. LeetCode第五题答案(time limite exceeded) C++ time limit exceeded
  20. 深交所、上交所、北交所、外汇交易中心、上期所官方接口说明及下载地址

热门文章

  1. center os 安装 mysql_MySQL数据库之center os 7 Mysql 安装
  2. 在excel中数字比对_Excel数据比对,多种方法总有一个适合你
  3. linux go语言运行环境,linux下怎么安装go语言环境
  4. win10下使用DuetDisplay有线/无线连接,推荐通过爱思助手(非iTunes)更新驱动
  5. MyApps接口引擎,打破跨系统间的壁垒
  6. Java集合面试题看这篇就够了
  7. 4种Dolby声场技术的区别
  8. Win10系统中蓝牙串口功能启动方法
  9. zedgraph怎么画曲线图_ZedGraph如何动态的加载曲线
  10. 使用PyTorch搭建ResNet101、ResNet152网络