c语言及数据结构实现简单贪吃蛇小游戏

这篇具有很好参考价值的文章主要介绍了c语言及数据结构实现简单贪吃蛇小游戏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一·贪吃蛇简单介绍:

二·贪吃蛇的实现的开始准备:

2.1:欢迎界面的实现:

2.2地图的绘制:

2.3.1初始化蛇:

2.3.2初始化食物: 

三·贪吃蛇的运行操作:

3.1辅助信息的打印:

3.2蛇的下一步移动操作:

3.2.1判断玩家按键情况:

3.2.2下一步遇到食物:

3.2.3下一步不是食物:

3.2.4蛇移动撞到自己死亡以及撞墙死亡:

四·贪吃蛇的结束操作:

五·源代码展示:

六·通过简单实现贪吃蛇游戏的总结与体会:


 文章来源地址https://www.toymoban.com/news/detail-859777.html

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

 

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

游戏效果演示:

上色后效果:


 

 

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

 

十进制颜色代码:void color(int c) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
}

普通效果:

 

 

一·贪吃蛇简单介绍:

 

 

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

想必大家都玩过贪吃蛇吧,这次我们来简单的实现一下它,由于受到知识盲区的限制,只好来粗略的实现一下以及介绍一下对它的具体操作等。

首先,我们设计的这个游戏只有一条蛇母体本身,然后就是在规定的地图里移动,然后在地图所在范围里面会随机的生成不同样式的食物,蛇可以通过吃它来增大分值,每当吃它一次,蛇自身长度就会增加一节,然后为了增加体验感,我们增添了f3与f4来分别作为加速键和减速键,比如我们按f3减速时候,我们难度会增加那么每个食物的分值也会对应增加,当我们按下f4减速时,难度降低,每个食物的分值也会减低。因此也不能无限减速,因此我们通过食物分值来限制了减速。

这便是我们对这个游戏简单思路介绍。

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

二·贪吃蛇的实现的开始准备:

1.在这里我们简单介绍一下这里用到的一些win32api规定的一些操作设置:首先要用到的就是,由于我们需要在界面打印一些游戏内容故需要得到光标位置:

我们可以这么理解弹出来的界面就是一个坐标系:

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

然而它的x轴是朝向右,但是y轴是朝向下的而且它的x的两个值所对应的距离差不多为一个y值所对应的距离,这些对下面我们布局有很大关系。

void setpos(short x, short y) {
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(houtput, pos);
}

接下来我们调用句柄的相关使用可以创建的这个函数可以直接确定光标所在的位置方便我们后续打印。下面我们在进行操作时候需要输入一定的特殊符号等,这时我们就需要把它改成适应本地

#include<locale.h>
setlocale(LC_ALL, "");

这里我们就可以后面用wprintf打印占两个位置的东西了。

下面我们还需要设置界面的名字以及弹窗的大小并且为了美观把光标位置隐藏于是就有了下面的操作:

system("mode con cols=100 lines=30");
system("title 贪吃蛇小游戏");
HANDLE houtput = NULL;
houtput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(houtput, &CursorInfo);
CursorInfo.bVisible = false;
SetConsoleCursorInfo(houtput, &CursorInfo);

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

下面我们步入操作的正题:

2.1:欢迎界面的实现:

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

我们为了实现这个界面操作:我们配合光标定位打印以及pause,cls使用来实现暂停以及清屏操作来完成:

void welcomegame() {
	setpos(40, 14);
	wprintf(L"欢迎来到贪吃蛇\n");
	Sleep(1000);
	setpos(40, 15);
	system("pause");
	system("cls");
	setpos(26, 5);
	wprintf(L"用箭头控制移动方向,F3加速,F4减速\n");
	setpos(32, 6);
	wprintf(L"加速可以获得更高的分数\n");
	setpos(44, 20);
	system("pause");
	system("cls");

}

这样就完成了此操作(我们在实现以及测试的时候可能会出现直接终止的情况,那么我们可以使用getchar()来防止它直接终止)。

2.2地图的绘制:

在地图绘制之前我们提前声明一下我们对它定义的操作以及对一些图案的define等:

#define pos_x 24
#define pos_y 5
#define wall L'※'
#define food0 L'▶'
#define food1 L'★'
#define food2 L'☆'
#define food3 L'◆'
#define food4 L'○'
#define food5 L'◇'
#define food6 L'▲'
#define food7 L'□'
#define food8 L'▼'
#define food9 L'◀'
#define body L'◎'
//这里我们定义了不同的食物以及蛇的身体的图案,以及我们蛇头出现的位置pos_x, pos_y等

下面我们还定义了蛇身节点的结构体,以及贪吃蛇游戏里面总的需要的比如状态,分数等一些数据。如:

enum dirction {
	up=1,//这里我们为了后面蛇移动调用的Switch可以正确使用将up赋值为1.
	down,
	left,
	right,
};//这里我们定义了一个枚举类型来存放蛇移动的方向。
enum game_Status{
	ok,
	kill_by_wall,
	kill_by_self,
	end_normal,//这里是游戏的状态
};
typedef struct snakenode {
	int x;
	int y;
	struct snakenode* next;
}snakenode;//这里我们定义了一个蛇身节点的结构体并给它重命名为snakenode,存放坐标以及下一个节点的地址,这样我们用链表的知识完成了蛇的创建。

typedef struct snake {
	snakenode* psnake;//蛇头指针
	snakenode* pfood;//食物指针
	enum game_Status status;//游戏状态
	enum dirction dir;蛇移动的方向
		int foodscore;//每个食物的分数
		int all_score;//游戏的总分
		int sleep_time;//通过游戏的休眠时间来控制蛇移动的快慢

}snake;

下面我们就配合setpos函数定义光标的位置完成了地图打印:

 void print_map() {
	 int i = 0;
	 for (i = 0; i < 29; i++) {
		 wprintf(L"%lc", wall);
	 }
	 setpos(0, 26);
	 for (i = 0; i < 29; i++) {
		 wprintf(L"%lc", wall);
	 }
	 for (i = 1; i <= 25; i++) {
		 setpos(0, i);
		 wprintf(L"%lc", wall);

	 }
	 for (i = 1; i <=25; i++) {
		 setpos(56,i );
		 wprintf(L"%lc", wall);

	 }
	 
}

如:

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

2.3.1初始化蛇:

void initsnake(snake* ps) {
 int i = 0;
 snakenode* cur = NULL;
 for (i = 0; i < 5; i++) {
	 cur = (snakenode*)malloc(sizeof(snakenode));
	 if (cur == NULL) {
		 perror("malloc:snakenode");
		 return;
	 }
	 else {
		 cur->next = NULL;
		 cur->x = pos_x + 2 * i;
		 cur->y = pos_y;
		 if (ps->psnake==NULL) {
			 ps->psnake = cur;
		 }
		 else {
			 cur->next= ps->psnake;
			 ps->psnake = cur;
		 }
	 }
 }//这里我们完成蛇的创建是基于单链表,蛇初始长度为五个节点,因此我们开辟了五个snakenode的空间并把相关数据放进去再把它们连接起来。
 cur = ps->psnake;
 while (cur) {
	 setpos(cur->x, cur->y);
	 wprintf(L"%lc", body);
	 cur = cur->next;
 }//通过遍历整个链表完成蛇身的打印
 ps->dir = right;
 ps->status = ok;
 ps->foodscore = 10;
 ps->all_score = 0;
 ps->sleep_time = 200;
 //把蛇的初始化状态以及游戏相关初始化设置好
 }

这里我们对游戏以及蛇一些状态设置都要对游戏的一些相关数据操作故我们每次应给函数传递snake类型的自变量并用同类型ps指针接收。 

 

2.3.2初始化食物: 

初始化食物我们应注意:1.由于蛇能吃到食物故我们判断的就是蛇一节身子和食物的坐标能相同,故也就是食物的横坐标必须是2的倍数。2.其次就是食物出现的范围应该不仅在地图里面而且不能和蛇身子重合。

​
 void  set_food(snake* ps) {
	 int x = 0;
	 int y = 0;
 again:
	 do{ 
		 x = rand() % 53 + 2;
		 y = rand() % 25 + 1;
	} while (x % 2 != 0);//这里我们调用srand函数来随机生成坐标控制在x=0~54,y=1~25
	snakenode*cur= ps->psnake ;
	   while (cur) {
		if (x==cur->x  && y==cur->y ) {
			goto again;
		}
		cur = cur->next;//遍历蛇身节点防止食物与之重合
	}
	  snakenode* pd = NULL;
	 pd  = (snakenode*)malloc(sizeof(snakenode));
	 if (pd == NULL) {
		 perror("malloc:set_food");
		 return;
	 
	 }
	 else {
		 pd->next = NULL;
		 pd->x = x;
		 pd->y = y;
		 ps->pfood = pd;
		 setpos(x, y);

		 if (y % 10 == 0) {
			 wprintf(L"%lc", food0);
		 }
		 else if (y%10 == 1) {
			 wprintf(L"%lc", food1);
		 }
		 else if (y % 10== 2) {
			 wprintf(L"%lc", food2);
		 }
		 else if (y % 10 == 3) {
			 wprintf(L"%lc", food3);
		 }
		 else if (y % 10 == 4) {
			 wprintf(L"%lc", food4);
		 }
		 else if (y % 10 == 5) {
			 wprintf(L"%lc", food5);
		 }
		 else if (y % 10 == 6) {
			 wprintf(L"%lc", food6);
		 }
		 else if (y % 10 == 7) {
			 wprintf(L"%lc", food7);
		 }
		 else if (y % 10 == 8) {
			 wprintf(L"%lc", food8);
		 }
		 else if (y % 10 == 9) {
			 wprintf(L"%lc", food9);
		 }//根据生成的坐标y值不同来防止不同的食物
	 }
	
}

​

 

三·贪吃蛇的运行操作:

我们要明白蛇要想动起来我们可以看成一个循环把玩家的每一步操作对蛇所产生的影响串起来,通过计算休眠时间来及时调整,因此我们对整个循环可以从第一步开始考虑,也就是它的移动情况以及下一个碰到食物该怎么坐或者不是食物又该怎么坐,在下面我们来深度剖析一下:

3.1辅助信息的打印:

为了游戏界面美观以及起到提示作用故我们进行了一下操作:

setpos(64, 10);
printf("总分数:%d",ps->all_score);
setpos(64, 11);
printf("每个食物分数:%3d", ps->foodscore);
void printhelpinfo() {

	setpos(64, 14);
	wprintf(L"蛇不能穿墙哦");
	setpos(64, 15);
	wprintf(L"可以使用箭头键盘来控制蛇移动的方向哦");
	setpos(64, 16);
	wprintf(L"按fn+F3加速,fn+F4减速哟");
	setpos(64, 17);
	wprintf(L"按ESC可以快速退出游戏,空格暂停哦");
	setpos(90,19);
	wprintf(L"@羑悻");
	
}

效果如下:

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

 

3.2蛇的下一步移动操作:

这里我们分情况列出蛇移动的第一步该怎么样,因此这里我们需要周到的想到众多情况才能防止游戏出现不必要的bug。这里蛇的每一步应该是状态为ok才能一直循环也就是蛇还活着。

	snakenode* smove = (snakenode*)malloc(sizeof(snakenode));
	if (smove == NULL) {
		perror("snakemove:malloc");
		return;
	}
	else {
		switch (ps->dir) {
		case up:
			smove->x = ps->psnake->x;
			smove->y= ps->psnake->y-1;
			break;

		case down:
			smove->x = ps->psnake->x;
			smove->y = ps->psnake->y +1;
			break;

		case right:
			smove->x = ps->psnake->x+2;
			smove->y = ps->psnake->y ;
			break;
		case left:
			smove->x = ps->psnake->x -2;
			smove->y = ps->psnake->y;
			break;
		}
//因为我们会判断出玩家按的键是什么来通过蛇头确定下一个坐标的位置
		if (nextisfood(smove,ps)) {
			eatfood(smove,ps);
		}
		else {
			noeatfood(smove,ps);
		}
		killbywall(ps);
		killbyself(ps);
		Sleep(ps->sleep_time);

		
		
	}
}

加减速的设置操作:

这里由于f3与f4来分别作为加速键和减速键,比如我们按f3减速时候,我们难度会增加那么每个食物的分值也会对应增加,当我们按下f4减速时,难度降低,每个食物的分值也会减低。因此也不能无限减速,因此我们通过食物分值来限制了减速,这样来适当增加游戏的乐趣。

​
else if (judgkeypush(VK_F3)) {
	if (ps->sleep_time > 80) {
		ps->sleep_time -= 30;
		ps->foodscore += 2;//这里我们每加速一次那么休眠时间就会减少,难度也会增大,那么我们设置的食物分数就让它增加两分。
	}
}
else if (judgkeypush(VK_F4)) {
	if (ps->foodscore > 2) {
		ps->sleep_time += 30;
		ps->foodscore -= 2;//这里我们每减速一次那么操作就会变得容易一些,因此我们让食物分值也减少2。
	}
}

​

 

3.2.1判断玩家按键情况:

为了能方便比较玩家按的哪个键因此我们创建了一个宏来专门判断:

#define judgkeypush(vk) ( (GetAsyncKeyState(vk)&1)?1:0)//我们这里又调用了系统自己的函数,作用:如果你按了某个键,他有规定的数值,当传给GetAsyncKeyState这个函数,按了就返回的值二进制末位是1,否则是0.

 

//这里我们在判断按键的时候比如按了↑就不能按↓类似操作完成对它的控制
if (judgkeypush(VK_UP) && ps->dir != down) {
	ps->dir=up;
}

else if(judgkeypush(VK_DOWN) && ps->dir != up) {
	ps->dir = down;
}
else if  (judgkeypush(VK_LEFT) && ps->dir != right) {
	ps->dir = left;
}
else if (judgkeypush(VK_RIGHT) && ps->dir != left) {
	ps->dir = right;
}
else if (judgkeypush(VK_的SPACE)) {
	snake_pause();//这里掉用的函数是通过死循环的休眠来满足暂停的,如果想暂停只需要判断空格是否被按过来break循环
//
//void snake_pause() {
//	while (1) {
//		Sleep(200);
//		if (judgkeypush(VK_SPACE)) {
//			break;
//		}
//	}
//}



}
else if (judgkeypush(VK_ESCAPE)) {
	ps->status = end_normal;
}
else if (judgkeypush(VK_F3)) {
	if (ps->sleep_time > 80) {
		ps->sleep_time -= 30;
		ps->foodscore += 2;
	}
}
else if (judgkeypush(VK_F4)) {
	if (ps->foodscore > 2) {
		ps->sleep_time += 30;
		ps->foodscore -= 2;
	}
}

 

 

3.2.2下一步遇到食物:

int nextisfood(snakenode*p, snake* ps) {
	if (ps->pfood->x == p->x && ps->pfood->y == p->y) {
		return 1;
	}
	else {
		return 0;
	}
 }//这里我们需要比较生成的食物坐标和蛇下一步移动的坐标来判断是否相同
void eatfood(snakenode* p, snake* ps) {
	ps->pfood->next = ps->psnake;
	ps->psnake = ps->pfood;
	free(p);
	p = NULL;
	snakenode* cur = ps->psnake;
	while (cur) {
		setpos(cur->x, cur->y);
		wprintf(L"%lc", body);
		cur = cur->next;
	}
	ps->all_score += ps->foodscore;
	set_food(ps);
}//如果是食物的话我们蛇就要把它吃掉并且延长蛇自身一个节点长度那么我们只需把食物这个地方的节点跟蛇头连接起来再把它当做新的蛇头再次打印蛇身即可,并且吃了它后我们分数也要做相应的改变,并重新生成新的食物

 

3.2.3下一步不是食物:

void noeatfood(snakenode* p, snake* ps) {
	p->next = ps->psnake;
	ps->psnake = p;
	snakenode* cur = ps->psnake;
	while (cur->next->next!=NULL) {
		setpos(cur->x, cur->y);
		wprintf(L"%lc", body);
		cur = cur->next;
	}
	setpos(cur->x, cur->y);
	wprintf(L"%lc", body);
	setpos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
//如果我们走的下一步不是食物的话我们蛇的自身长度就应该不变,因此我们还可以照样把食物节点指针指向蛇头,然后让其成为新的蛇头,完成连接再次打印,这时我们就要把蛇尾去掉一个节点就是把它释放掉让新的蛇尾节点指针为NULL,把我们之前在蛇尾打印的蛇身让其打印空格,完成地图的恢复。

}

3.2.4蛇移动撞到自己死亡以及撞墙死亡:

这里蛇在运行起来的死亡分为两种,一个是撞到墙再一个就是撞到自己那么我们根据这两种情况来实现对代码的编辑:

void killbywall(snake* ps) {
	if (ps->psnake->x == 0 || ps->psnake->x == 56 || ps->psnake->y == 0 || ps->psnake->y == 26) {
		ps->status = kill_by_wall;
	}
 }//蛇如果撞到墙也就是蛇头坐标不能和边界坐标重合
void killbyself(snake* ps) {
	snakenode* cur = ps->psnake->next;
	while (cur) {
		if (cur->x == ps->psnake->x && cur->y == ps->psnake->y) {
			ps->status = kill_by_self;
			break;
		}//同理这里也就是不能和自身除了蛇头之外节点坐标重合。
		cur = cur->next;
	}
 }

下面我们来看一下相关效果:

撞墙:

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

撞到自己:

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

四·贪吃蛇的结束操作:

由于我们设置了蛇每次运动的状态放在了枚举类型变量里面,因此我们可以根据蛇的情况来打印相关的信息提示等,然后游戏结束方便销毁创建的空间等。

void endgame(snake* ps) {
	setpos(24, 12);
	switch (ps->status) {
	case kill_by_wall:
		wprintf(L"你撞到墙死亡了!!!");
		break;
	case kill_by_self:
		wprintf(L"你撞到自己了!!!");
		break;
	case end_normal:
		wprintf(L"%ls",L"你主动退出游戏了!!!");
		break;
			
	}
	snakenode* cur = ps->psnake;
	snakenode* del = NULL;
	while (cur) {
		del = cur;
		cur = cur->next;
		free(del);//销毁malloc开辟空间
		
	}
}

然后为了游戏及结束后玩家还能接着玩这里我们调用了写游戏经常会用的do while来完成:

do {
	test();
	Sleep(1000);
	system("cls");
	setpos(20, 15);
	printf("是否需要再来一局???(y/n)");
	 ch = getchar();
	 while (getchar() != '\n');
} while (ch == 'y' || ch == 'Y');

测试函数:

​
void test() {
	snake bs = { 0 };
	game_start(&bs);
	game_run(&bs);
	endgame(&bs);

​}

游戏所用到的函数声明:

void game_start(snake*ps);//开始
void setpos(short x, short y);
void welcomegame();
 void print_map();
 void initsnake(snake* ps);
 void  set_food(snake* ps);
 void game_run(snake* ps);//运行
 void snake_pause();
 void printhelpinfo();
 int nextisfood(snakenode* p, snake* ps);
 void eatfood(snakenode* p, snake* ps);
 void noeatfood(snakenode* p, snake* ps);
 void killbywall(snake* ps);
 void killbyself(snake* ps);
 void endgame(snake* ps);//结束

这里我们的游戏相关介绍与操作就完成的差不多了。

 

 

效果图:

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

 

 

 

五·源代码展示:

snake.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<stdbool.h>
#include<time.h>
#define pos_x 24
#define pos_y 5
#define wall L'※'
#define food0 L'▶'
#define food1 L'★'
#define food2 L'☆'
#define food3 L'◆'
#define food4 L'○'
#define food5 L'◇'
#define food6 L'▲'
#define food7 L'□'
#define food8 L'▼'
#define food9 L'◀'
#define body L'◎'


enum dirction {
	up=1,
	down,
	left,
	right,
};
enum game_Status{
	ok,
	kill_by_wall,
	kill_by_self,
	end_normal,
};
typedef struct snakenode {
	int x;
	int y;
	struct snakenode* next;
}snakenode;

typedef struct snake {
	snakenode* psnake;
	snakenode* pfood;
	enum game_Status status;
	enum dirction dir;
		int foodscore;
		int all_score;
		int sleep_time;

}snake;
void game_start(snake*ps);//开始
void setpos(short x, short y);
void welcomegame();
 void print_map();
 void initsnake(snake* ps);
 void  set_food(snake* ps);
 void game_run(snake* ps);//运行
 void snake_pause();
 void printhelpinfo();
 int nextisfood(snakenode* p, snake* ps);
 void eatfood(snakenode* p, snake* ps);
 void noeatfood(snakenode* p, snake* ps);
 void killbywall(snake* ps);
 void killbyself(snake* ps);
 void endgame(snake* ps);//结束

snake.c

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"

void setpos(short x, short y) {
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(houtput, pos);
}
void welcomegame() {
	setpos(40, 14);
	wprintf(L"欢迎来到贪吃蛇\n");
	Sleep(1000);
	setpos(40, 15);
	system("pause");
	system("cls");
	setpos(26, 5);
	wprintf(L"用箭头控制移动方向,F3加速,F4减速\n");
	setpos(32, 6);
	wprintf(L"加速可以获得更高的分数\n");
	setpos(44, 20);
	system("pause");
	system("cls");

}
 void print_map() {
	 int i = 0;
	 for (i = 0; i < 29; i++) {
		 wprintf(L"%lc", wall);
	 }
	 setpos(0, 26);
	 for (i = 0; i < 29; i++) {
		 wprintf(L"%lc", wall);
	 }
	 for (i = 1; i <= 25; i++) {
		 setpos(0, i);
		 wprintf(L"%lc", wall);

	 }
	 for (i = 1; i <=25; i++) {
		 setpos(56,i );
		 wprintf(L"%lc", wall);

	 }
	 
}
 void initsnake(snake* ps) {
	 int i = 0;
	 snakenode* cur = NULL;
	 for (i = 0; i < 5; i++) {
		 cur = (snakenode*)malloc(sizeof(snakenode));
		 if (cur == NULL) {
			 perror("malloc:snakenode");
			 return;
		 }
		 else {
			 cur->next = NULL;
			 cur->x = pos_x + 2 * i;
			 cur->y = pos_y;
			 if (ps->psnake==NULL) {
				 ps->psnake = cur;
			 }
			 else {
				 cur->next= ps->psnake;
				 ps->psnake = cur;
			 }
		 }
	 }
	 cur = ps->psnake;
	 while (cur) {
		 setpos(cur->x, cur->y);
		 wprintf(L"%lc", body);
		 cur = cur->next;
	 }
	 ps->dir = right;
	 ps->status = ok;
	 ps->foodscore = 10;
	 ps->all_score = 0;
	 ps->sleep_time = 200;
	 
  }

 void  set_food(snake* ps) {
	 int x = 0;
	 int y = 0;
 again:
	 do{ 
		 x = rand() % 53 + 2;
		 y = rand() % 25 + 1;
	} while (x % 2 != 0);
	snakenode*cur= ps->psnake ;
	   while (cur) {
		if (x==cur->x  && y==cur->y ) {
			goto again;
		}
		cur = cur->next;
	}
	  snakenode* pd = NULL;
	 pd  = (snakenode*)malloc(sizeof(snakenode));
	 if (pd == NULL) {
		 perror("malloc:set_food");
		 return;
	 
	 }
	 else {
		 pd->next = NULL;
		 pd->x = x;
		 pd->y = y;
		 ps->pfood = pd;
		 setpos(x, y);

		 if (y % 10 == 0) {
			 wprintf(L"%lc", food0);
		 }
		 else if (y%10 == 1) {
			 wprintf(L"%lc", food1);
		 }
		 else if (y % 10== 2) {
			 wprintf(L"%lc", food2);
		 }
		 else if (y % 10 == 3) {
			 wprintf(L"%lc", food3);
		 }
		 else if (y % 10 == 4) {
			 wprintf(L"%lc", food4);
		 }
		 else if (y % 10 == 5) {
			 wprintf(L"%lc", food5);
		 }
		 else if (y % 10 == 6) {
			 wprintf(L"%lc", food6);
		 }
		 else if (y % 10 == 7) {
			 wprintf(L"%lc", food7);
		 }
		 else if (y % 10 == 8) {
			 wprintf(L"%lc", food8);
		 }
		 else if (y % 10 == 9) {
			 wprintf(L"%lc", food9);
		 }
	 }
	
}


void game_start(snake*ps) {
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇小游戏");
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(houtput, &CursorInfo);
	CursorInfo.bVisible = false;
	SetConsoleCursorInfo(houtput, &CursorInfo);
	welcomegame();
	print_map();
	initsnake(ps);
	set_food(ps);
}
void printhelpinfo() {

	setpos(64, 14);
	wprintf(L"蛇不能穿墙哦");
	setpos(64, 15);
	wprintf(L"可以使用箭头键盘来控制蛇移动的方向哦");
	setpos(64, 16);
	wprintf(L"按fn+F3加速,fn+F4减速哟");
	setpos(64, 17);
	wprintf(L"按ESC可以快速退出游戏,空格暂停哦");
	setpos(90,19);
	wprintf(L"@羑悻");
	
}
#define judgkeypush(vk) ( (GetAsyncKeyState(vk)&1)?1:0)
void snake_pause() {
	while (1) {
		Sleep(200);
		if (judgkeypush(VK_SPACE)) {
			break;
		}
	}
}
int nextisfood(snakenode*p, snake* ps) {
	if (ps->pfood->x == p->x && ps->pfood->y == p->y) {
		return 1;
	}
	else {
		return 0;
	}
 }
void eatfood(snakenode* p, snake* ps) {
	ps->pfood->next = ps->psnake;
	ps->psnake = ps->pfood;
	free(p);
	p = NULL;
	snakenode* cur = ps->psnake;
	while (cur) {
		setpos(cur->x, cur->y);
		wprintf(L"%lc", body);
		cur = cur->next;
	}
	ps->all_score += ps->foodscore;
	set_food(ps);
}
void noeatfood(snakenode* p, snake* ps) {
	p->next = ps->psnake;
	ps->psnake = p;
	snakenode* cur = ps->psnake;
	while (cur->next->next!=NULL) {
		setpos(cur->x, cur->y);
		wprintf(L"%lc", body);
		cur = cur->next;
	}
	setpos(cur->x, cur->y);
	wprintf(L"%lc", body);
	setpos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;


}
void killbywall(snake* ps) {
	if (ps->psnake->x == 0 || ps->psnake->x == 56 || ps->psnake->y == 0 || ps->psnake->y == 26) {
		ps->status = kill_by_wall;
	}
 }
void killbyself(snake* ps) {
	snakenode* cur = ps->psnake->next;
	while (cur) {
		if (cur->x == ps->psnake->x && cur->y == ps->psnake->y) {
			ps->status = kill_by_self;
			break;
		}
		cur = cur->next;
	}
 }

void snakemove(snake* ps) {
	snakenode* smove = (snakenode*)malloc(sizeof(snakenode));
	if (smove == NULL) {
		perror("snakemove:malloc");
		return;
	}
	else {
		switch (ps->dir) {
		case up:
			smove->x = ps->psnake->x;
			smove->y= ps->psnake->y-1;
			break;

		case down:
			smove->x = ps->psnake->x;
			smove->y = ps->psnake->y +1;
			break;

		case right:
			smove->x = ps->psnake->x+2;
			smove->y = ps->psnake->y ;
			break;
		case left:
			smove->x = ps->psnake->x -2;
			smove->y = ps->psnake->y;
			break;
		}
		if (nextisfood(smove,ps)) {
			eatfood(smove,ps);
		}
		else {
			noeatfood(smove,ps);
		}
		killbywall(ps);
		killbyself(ps);
		Sleep(ps->sleep_time);

		
		
	}
}
void game_run(snake* ps) {
	printhelpinfo();
	do {
		setpos(64, 10);
		printf("总分数:%d",ps->all_score);
		setpos(64, 11);
		printf("每个食物分数:%3d", ps->foodscore);
		if (judgkeypush(VK_UP) && ps->dir != down) {
			ps->dir=up;
		}

		else if(judgkeypush(VK_DOWN) && ps->dir != up) {
			ps->dir = down;
		}
		else if  (judgkeypush(VK_LEFT) && ps->dir != right) {
			ps->dir = left;
		}
		else if (judgkeypush(VK_RIGHT) && ps->dir != left) {
			ps->dir = right;
		}
		else if (judgkeypush(VK_SPACE)) {
			snake_pause();
		}
		else if (judgkeypush(VK_ESCAPE)) {
			ps->status = end_normal;
		}
		else if (judgkeypush(VK_F3)) {
			if (ps->sleep_time > 80) {
				ps->sleep_time -= 30;
				ps->foodscore += 2;
			}
		}
		else if (judgkeypush(VK_F4)) {
			if (ps->foodscore > 2) {
				ps->sleep_time += 30;
				ps->foodscore -= 2;
			}
		}
		snakemove(ps);


	} while (ps->status==ok);
}
void endgame(snake* ps) {
	setpos(24, 12);
	switch (ps->status) {
	case kill_by_wall:
		wprintf(L"你撞到墙死亡了!!!");
		break;
	case kill_by_self:
		wprintf(L"你撞到自己了!!!");
		break;
	case end_normal:
		wprintf(L"%ls",L"你主动退出游戏了!!!");
		break;
			
	}
	snakenode* cur = ps->psnake;
	snakenode* del = NULL;
	while (cur) {
		del = cur;
		cur = cur->next;
		free(del);
		
	}
}

test.c

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"
#include<locale.h>
void test() {
	snake bs = { 0 };
	game_start(&bs);
	game_run(&bs);
	endgame(&bs);
}
int main() {

	setlocale(LC_ALL, "");
	srand((unsigned int)time(NULL));
	/*test();
	setpos(20, 15);
	printf("是否需要再来一局??(y/n)");*/
	char ch = 0;
	do {
		test();
		Sleep(1000);
		system("cls");
		setpos(20, 15);
		printf("是否需要再来一局???(y/n)");
		 ch = getchar();
		 while (getchar() != '\n');
	} while (ch == 'y' || ch == 'Y');

	/*getchar();*/

	/*wprintf(L"%ls\n", L"我");
	printf("%d%d", 4,5);*/
	return 0;
}

 

 

六·通过简单实现贪吃蛇游戏的总结与体会:

通过此次对这个的构造以及代码的编写,让我感受到了一个看似很简单的一个小游戏却有很复杂的逻辑以及实现操作,当完成它时候首先我们要构思,想想自己就是玩家每一步对应会遇到什么情况该如何用代码去把它实现,不放过每一处细节的设置以防止出现bug,当然在写这个游戏时候避免不了bug的出现,出现不可怕,可怕的是你写了好几百行代码突然运行调试的时候出现bug而且要从这几百行代码里面去一一安排断点去调试,监视这就是一件很麻烦的事情,当然我也是遇到了找出的错误回事函数名字的一个字母写错了,然而却浪费了很长时间,因此我们在以后写的时候一定要仔细然后每写一点就测试一下,养成好习惯以免不必要的麻烦发生。然而,当我看到最后效果的时候,让我想我了那些断断续续的调试,思考,改调没有白费,为的就是将它呈现除了,回想起从hello world 到现在确实看到了进步,每一次挑战都是成长的阶梯,每一次失败都是成长的垫脚石,无论前路多么曲折,我都会保持对知识的那份渴望,对技术的那份钻研。不断超越前一次的自我,攀登最高的山峰,翻山越岭,只为遇见更加优秀的自己。

 

c语言及数据结构实现简单贪吃蛇小游戏,c语言,开发语言,数据结构,链表,青少年编程

 

 

 

 

 

到了这里,关于c语言及数据结构实现简单贪吃蛇小游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用Java实现一个简单的贪吃蛇小游戏

    基于java实现贪吃蛇小游戏,主要通过绘制不同的图片并以一定速度一帧一帧地在窗体上进行展示。 开发工具:eclipse java工具包:jdk1.8 代码地址:https://gitee.com/jay_musu/games-and-tools.git 创建一个新的项目,并命名。创建一个名为images的文件夹用来存放游戏相关图片。然后再在项

    2024年02月11日
    浏览(17)
  • 数据结构-顺序表的基本实现(C语言,简单易懂,含全部代码)

    今天起开始编写数据结构中的各种数据结构及算法的实现,说到顺序表,我们首先得了解下线性表。 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻

    2023年04月08日
    浏览(12)
  • C语言-------实现贪吃蛇小游戏

    Windows 这个多作业系统除了协调应用程序的执行、分配内存、管理资源之外, 它同时也是一个很大的服务中心,调用这个服务中心的各种服务(每一种服务就是一个函数),可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的,由于这些函数服务的对象是应用程序

    2024年04月29日
    浏览(13)
  • C语言从零实现贪吃蛇小游戏

    制作不易,点赞关注一下呗!!! 文章目录 前言 一.  技术要点 二、 WIN32API介绍 三、 贪吃蛇游戏设计与分析         1.游戏开始前的初始化         2.游戏运行的逻辑  总结 当我们掌握链表这样的数据结构之后,我们就可以用它来做一些小项目,比如童年小游戏贪吃蛇

    2024年02月20日
    浏览(17)
  • C语言之实现贪吃蛇小游戏篇(2)

    目录 🎇测试游戏test.c 🎇游戏头文件包含函数声明snake.h 🎇游戏实现snake.c 屏幕录制 2023-12-02 204515   ✔✔✔✔✔最后感谢大家的阅读,若有错误和不足,欢迎指正!乖乖敲代码哦!  代码---------→【唐棣棣 (TSQXG) - Gitee.com】 联系---------→【邮箱:2784139418@qq.com】

    2024年02月05日
    浏览(21)
  • 小游戏贪吃蛇的实现之C语言版

    找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏:C语言 目录 游戏前期准备: 设置控制台相关的信息  GetStdHandle GetConsoleCursorInfo  SetConsoleCursorInfo SetConsoleCursorPosition GetAsyncKeyState 贪吃蛇游戏设计与分析  本地化 地图,食物

    2024年04月23日
    浏览(19)
  • C语言小项目——小游戏贪吃蛇的实现

    我们可以使用 mode命令来设置控制台的大小,使用title命令来设置控制台标题。 在C语言中调用库函数 system来使用这些作用于控制台的命令 。使用代码如下: 采用该命令后控制台界面大概如下:   控制台坐标系以控制台左上角为原点从上往下y轴坐标增大,从左往右x轴坐标增

    2024年04月27日
    浏览(17)
  • 【C语言\数据结构】图dijkstra最短路径 邻接矩阵(无项、有权)代码简单实现深度解析

    这个代码是在图的邻接矩阵(无项、有权)的代码的基础上,添加了dijkstra最短路径函数,并且修改测试用例和主函数代码,图的邻接矩阵(无项、有权)的代码具体请查看 【C语言数据结构】图之邻接矩阵(无向、有权)代码简单实现,这里就不过多赘述。 我们用一个案例

    2024年02月03日
    浏览(25)
  • 【C语言&&数据结构】简单题目

    ✨作者:@平凡的人1 ✨专栏:《小菜鸟爱刷题》 ✨一句话:凡是过往,皆为序章 ✨说明: 过去无可挽回, 未来可以改变 为了方便自己的学习以及基于好久没更新博客的原因。特地写了这一篇博客 。💖 本篇博客是一篇记录学习篇,我将之归纳于刷题专栏。方便自己的复习以

    2023年04月08日
    浏览(22)
  • 数据结构 C语言 树形结构 简单目录管理系统

    在图书、操作系统文件夹、学生等管理系统中,目录管理是必要环节,如何高效搜寻与低复杂度存储是实现这一环节的关键性问题。本课程设计需完成一种基于多叉树结构简单目录管理系统,该系统能以交互式界面进行创建目录、删除目录、查找目录、修改目录、层次遍历目

    2024年02月04日
    浏览(17)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包