当前位置:网站首页>超简单的C语言贪吃蛇 不闪屏 双缓冲
超简单的C语言贪吃蛇 不闪屏 双缓冲
2022-06-22 10:14:00 【zh阿飞】
C语言贪吃蛇
今天把以前自己写的贪吃蛇总结了一下,发到博客上,怕放在电脑上哪天丢失了都不知道, 有不当之处还望指教 (*・ω< ) ヾ(◍°∇°◍)ノ゙
贪吃蛇中, 我们看到的蛇在不断的移动,其实就是在屏幕上不断的打印显示信息,又不断的擦除,就让蛇看起来在移动,在这里要用到语句: system("cls"), 但这个就造成了一个问题,打印不能一下打印完,所以造成了 闪屏, 解决闪屏的办法是 双缓冲, 双缓冲我在后边介绍
主要思想
大致准备
- 首先是用一个二维数组
arr来存放屏幕上的布局, 用0来表示空白的地方,蛇可以移动的区域, - 其他的食物、还有最外边的墙都用小于零的数来表示
- 我们的蛇身的话就用大于零的数表示,蛇尾用1表示,从蛇尾到蛇头依次增大,就可以根据蛇头值的大小来判断这个蛇吃了多少的食物
- 还有一些就是键盘上的方向键的, 总行、总列数,我们可以用宏定义, 这样方向键在用的时候就不用写 ASCII码了,直接用标识符又比较明显知道是哪个方向,不易错;
- 还要用一个1行2列的数组来存放蛇头的坐标位置,默认蛇是有长度的,所以要默认在数组中给蛇安排好它的位置,就是把数组中蛇身坐标的位置的值改为从蛇尾0到蛇头依次增大的值,

随机产生食物
- 那我们现在开始随机产生食物,用一个函数
produceFood专用来随机产生食物 - 随机产生一个坐标垂直
vertical的水平的levelv = rand() % ROW; l = rand() % COL判断arr[v][l]是否是空白区域,如果不是再重新产生,直到产生的是空白区域
方向选择
- 根据按键,判断出是哪个方向,就把相应的方向存好,注意: 如果按的是和蛇移动的方向相反,我们应该不处理,让蛇继续往这个方向移动,不然就会出现蛇吃自己,那就应该死亡了,这样体验要好一些些, 因为有好多时候就这样死亡了体验不好
蛇移动
- 那我们怎么来让蛇移动呢,首先我们要默认给蛇一个移动的方向,还要用一个1行2列的数组来存放蛇头的坐标位置,知道了蛇头的移动方向,还有坐标位置,那我们就知道了蛇头要移动到下一个坐标点的位置,那我们根据我们的数组就知道下一个坐标点位置是什么东西(食物,墙,空白地方,蛇身),我们就可以判断了
- 如果是 空白地方: 首先,我们让整个数组中大于零的值都 减1, 那原先的蛇尾的值为 1 变为了 0 , 就变为空白区域了,蛇尾就移动了, 之后我们让下一个坐标点位置的值改为蛇头的值 加1 ,蛇头就自然移动到下一个位置了
- 如果是 食物:把下一个坐标点位置的值改为蛇头的值 加1,这样蛇移动了,且变长了,吃了一个食物,之后调用 产生食物的函数,继续运行
- 如果是 墙或蛇身:死亡了, 根据蛇头的值,判断出吃了多少食物,得了多少分, 显示分数,退出游戏
双缓冲
写这个贪吃蛇已经快有一年了, 我也忘了双缓冲了(>ω・* )ノφ(>ω<*) ,只能模糊的记得些,让我说我也不知道怎样说, 我太菜了┗( ▔, ▔ )┛,但我代码里面有双缓冲,具体的双缓冲可以看
http://m.bubuko.com/infodetail-582228.html
https://blog.csdn.net/weixinhum/article/details/72179593
可以去网上了解了解 , 好了, 看看代码吧,不足之处欢迎指教 ─=≡Σ(((つ•̀ω•́)つ
代码如下:
/********************************************* *贪吃蛇 *用0表示空白的地方,用大于0的数做蛇,从蛇尾到蛇头的数依次增大,其它(墙,食物)的用负数表示, *碰到食物就把食物那个点的值变成蛇头值+1,食物的点变成蛇头,退出 *没有碰到食物,下一个点为空,就把下一个点的值变成蛇头值+1, *在将整个数组大于0的值都减一,蛇尾为一的自然变为0,就消失了,其它情况直接退出 *@author zhoufei *@date 2018-06-03 *********************************************/
#include<stdio.h>
#include<windows.h>
#define FOOD -4 //食物
#define WALL -9 //墙
#define COL 35
#define ROW 20
#define VK_UP 72 //方向键上下左右的第二个值,方向键有两个值,第一个是224,分别是72,...
#define VK_DOWN 80
#define VK_LEFT 75
#define VK_RIGHT 77
#define int short //把所有的int类型数据换成short类型节约空间
/*心得,常量大写,变量有多个单词加下划线,函数多个单词首字母小写,其余首字母大写*/
//用word打特殊符号,再复制
void fangXiangChoice(int arr[][COL]); //输入的方向的
void start(int p[][COL]); //开始之前的初始化操作
void print(int* a); //输出函数,输出到屏幕
void produceFood(int a[][COL]); //产生食物
void moveSnake(int (*arr)[COL],int * fx); //蛇的移动
int head_v = 4,head_h = 5;
//蛇头的纵向坐标和横向坐标,用大于0的数做蛇,从蛇尾到蛇头的数依次增大,
int arr[ROW][COL];
int speed_snake = 5; //蛇移动的速度,几次循环执行一次来控制
int fang_xiang = VK_RIGHT;//蛇移动的方向,默认向右
int exitgame = 0;
HANDLE hOutput,hOutBuf; //控制台屏幕缓冲区句柄
HANDLE *houtpoint;
COORD coord = {
1,0};
DWORD bytes = 0;
char data[ROW][COL];
int zhixiang_hOutput = 0; //通过指针轮流指向两个缓冲区,实现双缓冲
void main()
{
int k;
start(arr);
produceFood(arr);
puts("嗨~欢迎你来到贪吃蛇的世界!请君坐好了,要开车了~");
Sleep(2000); //休眠2秒
system("cls");
hOutBuf = CreateConsoleScreenBuffer(
GENERIC_WRITE, //定义进程可以往缓冲区写数据
FILE_SHARE_WRITE, //定义缓冲区可共享写权限
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
hOutput = CreateConsoleScreenBuffer(
GENERIC_WRITE, //定义进程可以往缓冲区写数据
FILE_SHARE_WRITE, //定义缓冲区可共享写权限
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
SetConsoleTitle(TEXT("贪吃蛇"));
SMALL_RECT rc = {
0,0,COL+10,ROW+4}; //设置窗口大小,宽度和高度
SetConsoleWindowInfo(hOutput,1,&rc);
SetConsoleWindowInfo(hOutBuf,1,&rc);
//隐藏两个缓冲区的光标
CONSOLE_CURSOR_INFO cci;
cci.bVisible = 0;
cci.dwSize =1;
SetConsoleCursorInfo(hOutput, &cci);
SetConsoleCursorInfo(hOutBuf, &cci);
while(1)
{
if(kbhit())
{
fangXiangChoice(arr);
moveSnake(arr,&fang_xiang);
print(arr[0]);
}
if(k++ % speed_snake == 0)
{
moveSnake(arr,&fang_xiang);
print(arr[0]);
}Sleep(40);
}
}
void fangXiangChoice(int arr[][COL])
{
int key1,key2;
key1 = getch();
if(key1 == 27)//ESC建退出
exitgame = 1;
if(key1 == 224)
{
key2 = getch();
switch(key2)
{
case VK_UP: if(fang_xiang != VK_DOWN) fang_xiang = VK_UP; //如果在向下移动,那蛇就不能向上移动,下面的相同
break;
case VK_DOWN: if(fang_xiang != VK_UP) fang_xiang = VK_DOWN;
break;
case VK_LEFT: if(fang_xiang != VK_RIGHT) fang_xiang = VK_LEFT;
break;
case VK_RIGHT: if(fang_xiang != VK_LEFT) fang_xiang = VK_RIGHT;
}
}
}
void start(int p[][COL])
{
int i,j;
p[head_v][head_h] = 2; //初始化蛇头,蛇身
p[head_v][head_h-1] = 1;
for(i = 0; i < ROW; i++)
{
for(j = 0; j < COL; j++)
{
if(i == 0 || i == ROW-1 || j == 0 || j == COL-1)
p[i][j] = WALL; //初始化墙
}
}
}
void produceFood(int a[][COL])
{
int food_v,food_h;
srand(time(NULL));
food_v = rand() % ROW;
food_h = rand() % COL;
while(a[food_v][food_h] != 0)
{
food_v = rand() % ROW;
food_h = rand() % COL;
}
a[food_v][food_h] = FOOD;
}
/** //蛇头的纵向坐标和横向坐标,用大于0的数做蛇,从蛇尾到蛇头的数依次增大, //碰到食物就把食物那个点的值变成蛇头值+1,食物的点变成蛇头,退出 //没有碰到食物,下一个点为空,就把下一个点的值变成蛇头值+1, //在将整个数组大于0的值都减一,蛇尾为一的自然变为0,就消失了,其它情况直接退出 */
void moveSnake(int (*arr)[COL],int * fx) //根据传入的方向移动蛇
{
int i,j,eat_food = 0; //为0表示没有吃到食物
int temp = arr[head_v][head_h]; //记录现在蛇头的值
if(*fx == VK_UP)
{
if(arr[head_v - 1][head_h] == 0) head_v--;
else if(arr[head_v - 1][head_h] == FOOD)
head_v--,eat_food = 1; //吃到食物了,蛇身不用减一
else exitgame = 1; //其它情况只有撞墙和吃蛇身
}if(*fx == VK_DOWN)
{
if(arr[head_v + 1][head_h] == 0) head_v++;
else if(arr[head_v + 1][head_h] == FOOD)
head_v++,eat_food =1;
else exitgame = 1;
}if(*fx == VK_LEFT)
{
if(arr[head_v][head_h -1] == 0) head_h--;
else if(arr[head_v][head_h -1] == FOOD)
head_h--,eat_food = 1;
else exitgame = 1;
}if(*fx == VK_RIGHT)
{
if(arr[head_v][head_h + 1] == 0) head_h++;
else if(arr[head_v][head_h + 1] == FOOD)
head_h++,eat_food = 1;
else exitgame = 1;
}
/**没有吃的食物大于零的数都要减一*/
arr[head_v][head_h] = temp+1;
if(!eat_food)
{
for(i = 0; i < ROW; i++)
{
for(j = 0; j < COL; j++)
{
if(arr[i][j] > 0) arr[i][j] = arr[i][j] - 1;
}
}
}
else
produceFood(arr); //吃到食物了,产生一个食物
}
void print(int* p)
{
int i,j;
char shuo_ming1[] = "请按方向键 ↑ ↓ ← → 的控制上下左右";
char shuo_ming2[] = "连续按方向键会加速,退出按ESC键";
for(i = 0; i < ROW; i++)
{
for(j = 0; j < COL; j++,p++)
{
if(*p == WALL)
data[i][j] = '*'; //printf("■"); //墙墙
if(*p == 0)
data[i][j] = ' '; //printf(" ");
if(*p > 0) //蛇
{
if(i == head_v && j == head_h) data[i][j] = '0';//printf("⊙");
else data[i][j] = '@'; //printf("●");
}
if(*p == FOOD)
data[i][j] = '@'; //printf("●");
}//printf("\n");
}
//以下是缓冲代码
zhixiang_hOutput = !zhixiang_hOutput ;
if(!zhixiang_hOutput)
{
houtpoint = &hOutput;
}
else
{
houtpoint = &hOutBuf;
}
coord.Y = 1;
WriteConsoleOutputCharacterA(*houtpoint,shuo_ming1,strlen(shuo_ming1), coord,&bytes);
coord.Y++; WriteConsoleOutputCharacterA(*houtpoint,shuo_ming2,strlen(shuo_ming2), coord,&bytes);
for(i = 0; i < ROW; i++)
{
coord.Y++ ;
WriteConsoleOutputCharacterA(*houtpoint,(char *)data[i],COL, coord,&bytes);
}
if(exitgame)
{
char score[20];//得分为蛇吃的食物乘以3
sprintf(score,"你的得分为:%d",(arr[head_v][head_h]-2)*3);
coord.Y++;
WriteConsoleOutputCharacterA(*houtpoint,score,strlen(score), coord,&bytes);
SetConsoleActiveScreenBuffer(*houtpoint);
getch();exit(0);
}
SetConsoleActiveScreenBuffer(*houtpoint);
}
边栏推荐
- 如何进行高效简洁的电子文档管理
- How to manage electronic documents efficiently and concisely
- Web Configuration of Visual Studio Code
- 7-1 group minimum
- TikTok 宣布将数据存储于 Oracle 服务器!
- Opencv人脸识别之发送QQ邮箱
- [backtrader source code analysis 51] simple interpretation of the source code of seven files in observers (boring, for reference only)
- AttributeError: module ‘skimage.draw‘ has no attribute ‘circle‘
- Quel est le risque de divulgation d'un certificat de signature de code?
- 抖音实战~手机号一键注册登录流程(验证码)
猜你喜欢

Should the theme of the IDE be bright or dark? Here comes the ultimate answer!

Three months to successfully "turn over" the software project!

扎克伯格最新VR原型机来了,要让人混淆虚拟与现实的那种

Former amd chip architect roast said that the cancellation of K12 processor project was because amd counseled!

Signal integrity (SI) power integrity (PI) learning notes (XXIV) differential pair and differential impedance (IV)

AttributeError: module ‘skimage.draw‘ has no attribute ‘circle‘

Don't be silly enough to distinguish hash, chunkhash and contenthash

Who says PostgreSQL has no reliable high availability (2)

社区文章|MOSN 构建 Subset 优化思路分享

Summary of neural network training trick
随机推荐
缓存穿透利器之「布隆过滤器」
[backtrader source code analysis 51] simple interpretation of the source code of seven files in observers (boring, for reference only)
使用pytorch mask-rcnn进行目标检测/分割训练
力扣 1108. IP 地址无效化
LeetCode Algorithm 剑指 Offer 22. 链表中倒数第k个节点
传iPhone 14将全系涨价;TikTok美国用户数据转移到甲骨文,字节无法访问;SeaTunnel 2.1.2发布|极客头条...
The data intelligence infrastructure upgrade window is approaching? See Chapter 9 how Yunji dingodb breaks through data pain points
7-1 group minimum
【无标题】#修复日志#
搭建OpenPGP Key server
Summary of neural network training trick
iNFTnews | 观点:市场降温或是让NFT应用走向台前的机会
名词解析:ETL
不要再傻傻分不清 hash、 chunkhash 和 contenthash 啦
Some penetration test terms I collected
从MVC原理开始手敲一个MVC框架,带你体会当大神的乐趣
使用 Matplotlib 这么久,竟不知道数据可以动起来
Pareto's law at work: focus on results, not outputs
【深度学习】不得了!新型Attention让模型提速2-4倍!
IPO配置指南