C语言贪吃蛇经典小游戏

 更新时间:2020年04月22日 16:24:37   作者:XHfight  
这篇文章主要为大家详细介绍了C语言贪吃蛇经典小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

一、贪吃蛇小游戏简介:

用上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,也不能咬到自己的身体,等到了一定的分数,就能过关。

二、函数框架

三、数据结构

typedef struct Snake 
{ 
 size_t x; //行 
 size_t y; //列 
 struct Snake* next; 
}Snake, *pSnake; 

定义蛇的结构体,利用单链表来表示蛇,每个结点为蛇身体的一部分。

四、代码实现(vs2010  c语言)

1.Snake.h

#ifndef __SNAKE_H__ 
#define __SNAKE_H__ 
 
#include <stdio.h> 
#include <stdlib.h> 
#include <Windows.h> 
#include <time.h> 
#include <malloc.h> 
#include <assert.h> 
//标识地图大小 
#define ROW_MAP 10 //地图的行 
#define COL_MAP 20 //地图的列 
#define SUCCESS_SCORE 10//通关分数 
enum Direction //蛇行走的方向 
{ 
 R, //右 
 L, //左 
 U, //上 
 D //下 
}Direction; 
 
enum State 
{ 
 ERROR_SELF, //咬到自己 
 ERROR_WALL, //撞到墙 
 NORMAL, //正常状态 
 SUCCESS //通关 
}State; 
 
typedef struct Snake 
{ 
 size_t x; //行 
 size_t y; //列 
 struct Snake* next; 
}Snake, *pSnake; 
 
 
void StartGame(); 
void RunGame(); 
void EndGame(); 
 
#endif 

2.Snake.c

#include "Snake.h" 
 
pSnake head = NULL; //定义蛇头指针 
pSnake Food = NULL; //定义食物指针 
 
int sleeptime = 500;//间隔时间,用来控制速度 
int Score = 0; //总分 
int everyScore = 1; //每步得分 
 
//定义游戏中用到的符号 
const char food = '#'; 
const char snake = '*'; 
 
void Pos(int x, int y) //控制输出光标 
{ 
 COORD pos; //pos为结构体 
 pos.X = x; //控制列 
 pos.Y = y; //控制行 
 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);//读取标准输出句柄来控制光标为pos 
} 
 
void Face() 
{ 
 system("color 0C"); 
 printf("*******************************************************\n"); 
 printf("* Welcome to Snake Game! *\n"); 
 printf("*    *\n"); 
 printf("* ->开始游戏请按 enter键  *\n"); 
 printf("* ->退出游戏请按 esc键  *\n"); 
 printf("* ->暂停游戏请按 space键  *\n"); 
 printf("* ->通过上下左右键来控制蛇的移动 *\n"); 
 printf("* ->通过F1键减速 F2键加速 *\n"); 
 printf("*******************************************************\n"); 
} 
void Map() //初始化地图 
{ 
 int i = 0; 
 for(i = 0; i<COL_MAP; i+=2) //打印上下边框(每个■占用两列) 
 { 
 Pos(i, 0); 
 printf("■"); 
 Pos(i, ROW_MAP-1); 
 printf("■"); 
 } 
 for(i = 0; i<ROW_MAP; i++) //打印左右边框 
 { 
 Pos(0, i); 
 printf("■"); 
 Pos(COL_MAP-2, i); 
 printf("■"); 
 } 
} 
void PrintSnake() //打印蛇 
{ 
 pSnake cur = head; 
 while(cur) 
 { 
 Pos(cur->y, cur->x); 
 printf("%c", snake); 
 cur = cur->next; 
 } 
} 
void InitSnake() //初始化蛇身 
{ 
 int initNum = 3; 
 int i = 0; 
 pSnake cur; 
 head = (pSnake)malloc(sizeof(Snake)); 
 head->x = 5; 
 head->y = 10; 
 head->next = NULL; 
 
 cur = head; 
 for(i = 1; i < initNum; i++) 
 { 
 pSnake newNode = (pSnake)malloc(sizeof(Snake)); 
 newNode->x = 5+i; 
 newNode->y = 10; 
 newNode->next = NULL; 
 cur->next = newNode; 
 cur = cur->next; 
 } 
 
 PrintSnake(); 
} 
 
void CreateFood() //在地图上随机产生一个食物 
{ 
 pSnake cur = head; 
 Food = (pSnake)malloc(sizeof(Snake)); 
 
 //产生x~y的随机数 k=rand()%(Y-X+1)+X; 
 srand((unsigned)time(NULL)); 
 Food->x = rand()%(ROW_MAP-2 - 1 + 1)+1; 
 Food->y = rand()%(COL_MAP-3 - 2 + 1)+2; 
 Food->next = NULL; 
 while(cur) //检查食物是否与蛇身重合 
 { 
 if(cur->x == Food->x && cur->y == Food->y) 
 { 
 free(Food); 
 Food = NULL; 
 CreateFood(); 
 return; 
 } 
 cur = cur->next; 
 } 
 Pos(Food->y, Food->x); 
 printf("%c", food); 
} 
 
void StartGame() //游戏开始的所有设置 
{ 
 Face(); 
 system("pause"); 
 
 if(GetAsyncKeyState(VK_RETURN)) 
 { 
 system("cls"); 
 Pos(COL_MAP+5, 1); 
 printf("当前分数/通关分数:"); 
 Pos(COL_MAP+20, 1); 
 printf("%d/%d", Score, SUCCESS_SCORE); 
 Pos(COL_MAP+5, 2); 
 printf("当前分每步得分:"); 
 Pos(COL_MAP+20, 2); 
 printf("%d", everyScore); 
 Pos(COL_MAP+5, 3); 
 printf("\n"); 
 Pos(COL_MAP+5, 4); 
 printf("速度越快 得分越高哦!!\n"); 
 
 Map(); 
 InitSnake(); 
 CreateFood(); 
 } 
 else if(GetAsyncKeyState(VK_ESCAPE)) 
 { 
 exit(0); 
 } 
} 
 
int IsCrossWall() //判断是否碰到墙 
{ 
 if(head->x <= 0 || head->x >= ROW_MAP-1 
 ||head->y <= 1 || head->y >= COL_MAP-2) 
 { 
 State = ERROR_WALL; 
 return 0; 
 } 
 return 1; 
} 
 
int IsEatSelf(pSnake newHead) //判断是否咬到自己 
{ 
 pSnake cur = head; 
 assert(newHead); 
 while(cur) 
 { 
 if(cur->x == newHead->x && cur->y == newHead->y) 
 { 
 State = ERROR_SELF; 
 return 0; 
 } 
 cur = cur->next; 
 } 
 return 1; 
} 
 
int IsFood(pSnake pos) //判断该位置是不是食物 
{ 
 assert(pos); 
 if(pos->x == Food->x && pos->y == Food->y) 
 { 
 return 1; 
 } 
 return 0; 
} 
 
void SnakeMove() //蛇移动一次 
{ 
 pSnake newHead = NULL; 
 newHead = (pSnake)malloc(sizeof(Snake)); 
 
 if(Direction == R) 
 { 
 newHead->x = head->x; 
 newHead->y = head->y+1; 
 newHead->next = head; 
 } 
 else if(Direction == L) 
 { 
 newHead->x = head->x; 
 newHead->y = head->y-1; 
 newHead->next = head; 
 } 
 else if(Direction == U) 
 { 
 newHead->x = head->x-1; 
 newHead->y = head->y; 
 newHead->next = head; 
 
 } 
 else if(Direction == D) 
 { 
 newHead->x = head->x+1; 
 newHead->y = head->y; 
 newHead->next = head; 
 } 
 
 if(IsFood(newHead)) 
 { 
 head = newHead; 
 PrintSnake(); 
 CreateFood(); 
 Score += everyScore; 
 Pos(COL_MAP+20, 1); 
 printf("%d/%d", Score, SUCCESS_SCORE); 
 if(Score >= SUCCESS_SCORE) 
 { 
 State = SUCCESS; 
 } 
 } 
 else 
 { 
 if(IsCrossWall() && IsEatSelf(newHead)) 
 { 
 pSnake cur = NULL; 
 head = newHead; 
 cur = head; 
 //删除蛇尾并打印 
 while(cur->next->next != NULL) 
 { 
  Pos(cur->y, cur->x); 
  printf("%c", snake); 
  cur = cur->next; 
 } 
  
 Pos(cur->y, cur->x); 
 printf("%c", snake); 
 Pos(cur->next->y, cur->next->x); 
 printf(" "); //打印空格来覆盖频幕上的蛇尾 
 free(cur->next); 
 cur->next = NULL; 
 } 
 else 
 { 
 free(newHead); 
 newHead = NULL; 
 } 
 } 
} 
 
void Pause() 
{ 
 while(1) 
 { 
 Sleep(sleeptime); 
 if(GetAsyncKeyState(VK_SPACE)) 
 { 
 break; 
 } 
 } 
} 
 
void ControlSnake() //用键盘控制游戏 
{ 
 if(GetAsyncKeyState(VK_UP) && Direction!=D) 
 { 
 Direction = U; 
 } 
 else if(GetAsyncKeyState(VK_DOWN) && Direction!=U) 
 { 
 Direction = D; 
 } 
 else if(GetAsyncKeyState(VK_LEFT) && Direction!=R) 
 { 
 Direction = L; 
 } 
 else if(GetAsyncKeyState(VK_RIGHT) && Direction!=L) 
 { 
 Direction = R; 
 } 
 else if(GetAsyncKeyState(VK_F1)) 
 { 
 if(sleeptime != 500) 
 { 
 sleeptime = 500; 
 everyScore = 1; 
 Pos(COL_MAP+20, 2); 
 printf("%d", everyScore); 
 } 
 } 
 else if(GetAsyncKeyState(VK_F2)) 
 { 
 if(sleeptime != 300) 
 { 
 sleeptime = 300; 
 everyScore = 2; 
 Pos(COL_MAP+20, 2); 
 printf("%d", everyScore); 
 } 
 } 
 else if(GetAsyncKeyState(VK_SPACE)) 
 { 
 Pause(); 
 } 
 else if(GetAsyncKeyState(VK_ESCAPE)) 
 { 
 exit(0); 
 } 
} 
 
void StateGame() //判断游戏失败或成功 
{ 
 if(State == ERROR_SELF) 
 { 
 system("cls"); 
 printf("很遗憾,蛇咬到自己,游戏失败!\n"); 
 } 
 else if(State == ERROR_WALL) 
 { 
 system("cls"); 
 printf("很遗憾,蛇碰到墙壁,游戏失败!\n"); 
 } 
 else if(State == SUCCESS) 
 { 
 system("cls"); 
 printf("恭喜您,已通关!!!\n"); 
 } 
 
} 
void RunGame() 
{ 
 Direction = R; //蛇初始行走方向为右 
 State = NORMAL;//游戏初始为正常状态 
 while(1) 
 { 
 ControlSnake(); 
 SnakeMove(); 
 if(State != NORMAL) 
 { 
 StateGame(); 
 break; 
 } 
 Sleep(sleeptime); 
 } 
} 
 
void EndGame() //释放链表并恢复默认值 
{ 
 pSnake cur = head; 
 while(cur) 
 { 
 pSnake del = cur; 
 cur = cur->next; 
 free(del); 
 del = NULL; 
 } 
 head = NULL; 
 if(Food != NULL) 
 { 
 free(Food); 
 Food = NULL; 
 } 
 Score = 0; 
 everyScore = 1; 
 sleeptime = 500; 
} 

3.Test.c

#include "Snake.h" 
 
int main() 
{ 
 while(1) 
 { 
 StartGame(); 
 RunGame(); 
 EndGame(); 
 } 
 system("pause"); 
 return 0; 
} 

五、运行界面展示

1.欢迎界面

 

2.游戏界面

小小的c语言项目,用来练手,仅供参考哦!!

谢谢阅读,如有问题,欢迎提出。

更多有趣的经典小游戏实现专题,分享给大家:

C++经典小游戏汇总

python经典小游戏汇总

python俄罗斯方块游戏集合

JavaScript经典游戏 玩不停

java经典小游戏汇总

javascript经典小游戏汇总

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • FFmpeg进阶教程之给视频添加文字水印

    FFmpeg进阶教程之给视频添加文字水印

    FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序,下面这篇文章主要给大家介绍了关于FFmpeg进阶教程之给视频添加文字水印的相关资料,需要的朋友可以参考下
    2022-11-11
  • C语言实现运筹学中的马氏决策算法实例

    C语言实现运筹学中的马氏决策算法实例

    这篇文章主要介绍了C语言实现运筹学中的马氏决策算法,简单介绍了马氏决策的概念,并结合实例形式分析了C语言实现马氏决策算法的具体实现技巧,需要的朋友可以参考下
    2017-09-09
  • 详解C++中的四种类型转换运算符

    详解C++中的四种类型转换运算符

    隐式类型转换是安全的,显式类型转换是有风险的,C语言之所以增加强制类型转换的语法,就是为了强调风险,让程序员意识到自己在做什么,本文将给大家详细介绍一下C++中的四种类型转换运算符,需要的朋友可以参考下
    2023-09-09
  • 二分图匹配实例代码及整理

    二分图匹配实例代码及整理

    这篇文章主要介绍了二分图匹配实例代码及整理的相关资料,这里提供了三种方法包括匈牙利算法,KM算法,多重匹配,需要的朋友可以参考下
    2017-07-07
  • 纯C语言:递归二进制转十进制源码分享

    纯C语言:递归二进制转十进制源码分享

    这篇文章主要介绍了纯C语言:递归二进制转十进制源码,有需要的朋友可以参考一下
    2014-01-01
  • C语言的分支和循环语句你真的了解吗

    C语言的分支和循环语句你真的了解吗

    这篇文章主要为大家详细介绍了C语言的分支和循环语句,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • C++ 程序员为什么看不起php程序员

    C++ 程序员为什么看不起php程序员

    由于当今市场状况,各种培训班飞起,PHPer越来越多,学习成本很低。导致了很多人对PHP的误解。其实PHP学到深入的时候,所需知识很多,并不是表面看到的那样。另外,PHP确实严谨性不高,这个跟C++,java确实都没法比。但是,PHP在web开发中的效率,是其他语言所不能比的
    2017-02-02
  • C语言中的内存泄露 怎样避免与检测

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

    堆经常会出现两种类型的问题:1.释放或改写仍在使用的内存(称为:“内存损坏”)。2.未释放不再使用的内存(称为:“内存泄露”)。这是最难被调试发现的问题之一
    2013-09-09
  • 基于C语言中野指针的深入解析

    基于C语言中野指针的深入解析

    “野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用
    2013-07-07
  • C++实现中缀表达式转后缀表达式

    C++实现中缀表达式转后缀表达式

    这篇文章主要为大家详细介绍了C++实现中缀表达式转后缀表达式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04

最新评论