高级语言实训课程:简单的贪吃蛇项目实现(C语言)

人盡茶涼 提交于 2019-12-30 03:00:59

简单的贪吃蛇项目实现(C语言)源码


记录高级程序语言课的项目1:简单贪吃蛇小游戏(环境是Dev-C++)
第一次的小记录*~*加油

基本功能

本项目的主要功能为实现贪吃蛇小游戏,首先进行利用光标的定位来进行一系列的数据初始化,然后利用键盘上的按键来控制小蛇的移动,在此过程中,小蛇吃到食物后身体会变长,当它在移动的过程中撞到游戏边界或者咬到自己就结束游戏,并且得到一个食物就会积累相应得分。

具体模块

1、数据初始化模块
2、光标定位模块
3、移动模块
4、移动方向判定模块

具体实现代源码

/********************************************************************************
* @File name: main.c
* @Description: 此程序文件完成的是贪吃蛇小游戏,将设计出初始长度很短的小蛇,蛇头
                碰到随机生成的食物就会变长,并且在此过程中,小蛇碰到游戏界面或者
				碰到自己都标志着结束,吃到一个食物相应加10分,并统计最终总得分 
* @ Function List: void Pos();//设置光标位置
                   void creatInterface();//创建游戏界面 
                   void InitializeSnake();//初始化蛇的身体 
                   int bite_itself(); //判断是否咬到自己 
                   void createfood();//创建食物 
                   void cantcrosswall();//撞墙 
                   void snakemove();//蛇移动 
                   void pause();//暂停游戏 
                   void gamecircle();//游戏运行 
                   void welcometogame();//欢迎来到游戏的显示界面 
                   void endgame();//游戏结束 
                   void gamestart();//游戏开始 
* @Author:千阴 
* @Version: 1.1
* @Date: 2019-12-07
********************************************************************************/
#include<stdio.h>
#include<time.h>
#include<windows.h>
#include<stdlib.h>
#define U 1
#define D 2
#define L 3
#define R 4 //蛇的状态,U:上 ;D:下;L:左 R:右

/*  表示蛇身上的小点*  */
typedef struct SNAKE 
{
int x;/*横坐标*/ 
int y;/*纵坐标*/
struct SNAKE *next;/*下一个蛇身子的节点指针*/
}snake;

//全局变量//

int score=0,add=10;/* 总得分与每次吃食物得分 */ 
int status;/* 按键数字的存放  */
int sleeptime=200;/* 每次运行的时间间隔 */
snake *head, *food;/*蛇头指针,食物指针*/
snake *q;/* 蛇的结构体指针 */ 
int endgamestatus=0; /*游戏结束的情况,1:撞到墙;2:咬到自己;*/

//声明全部函数//
void Pos();//设置光标位置
void creatInterface();//创建游戏界面 
void InitializeSnake();//初始化蛇的身体 
int  bite_itself(); //判断是否咬到自己 
void createfood();//创建食物 
void cantcrosswall();//撞墙 
void snakemove();//蛇移动 
void pause();//暂停 
void gamecircle();//运行 
void welcometogame();//欢迎界面 
void endgame();//结束游戏 
void gamestart();//开始游戏 

void Pos(int x,int y)
{
COORD pos;//pos是结构体类型变量 
HANDLE hOutput;//新建的光标句柄 
pos.X=x;
pos.Y=y;
hOutput=GetStdHandle(STD_OUTPUT_HANDLE);//句柄的实例化 
SetConsoleCursorPosition(hOutput,pos);//SetConsoleCursorPosition是API中定位光标的函数 
}

void creatInterface()
{
	int i;
	for(i=0;i<58;i+=2)//打印上下边框
		{
			Pos(i,0);
			printf("-");//上边框 
			Pos(i,26);
			printf("-");//下边框 
		}
	for(i=1;i<26;i++)//打印左右边框
		{
			Pos(0,i);
			printf("-");//左边框 
			Pos(56,i);
			printf("-");//右边框 
		}
}

void InitializeSnake()
{
snake *tail;
int i;
tail=(snake*)malloc(sizeof(snake));//从蛇尾开始,头插法,用x,y设定开始的位置
tail->x=24;
tail->y=5;
tail->next=NULL;
for(i=1;i<=4;i++)
{
	head=(snake*)malloc(sizeof(snake));
	head->next=tail;
	head->x=24+2*i;
	head->y=5;
	tail=head;
}
while(tail!=NULL)//从头到尾,输出蛇身
{
	Pos(tail->x,tail->y);
	printf("*");
	tail=tail->next;
}
}

int bite_itself()
{
snake *self;
self=head->next;
while(self!=NULL)
{
if(self->x==head->x && self->y==head->y)//头的坐标和其他身子的坐标重合 
{
return 1;//咬到 
}
self=self->next;
}
return 0;//没有咬到 
}

void createfood()//随机出现食物
{
snake *food_1;
srand((unsigned)time(NULL));
food_1=(snake*)malloc(sizeof(snake));
do //保证其为偶数,使得食物能与蛇头对齐
{
food_1->x=rand()%52+2;//随机生成食物的横坐标 
}while((food_1->x%2)!=0);
food_1->y=rand()%24+1;//随机生成食物的纵坐标 
q=head;
while(q->next != NULL)
{
if(q->x==food_1->x && q->y==food_1->y) //判断蛇身是否与食物重合
{
free(food_1);
food_1 = NULL;
createfood();
break;
}
q=q->next;
}
if (food_1 != NULL)//食物要是不存在,就随机生成食物 
{
Pos(food_1->x,food_1->y);
food=food_1;
printf("¥");
}
}

void cantcrosswall()
{
if(head->x==0 || head->x==56 ||head->y==0 || head->y==26)//蛇头的横坐标纵坐标撞到了边界,就把endgamestatus设置为情况1 
{
endgamestatus=1;//1,表示穿墙 
endgame();
}
}

void snakemove()//蛇前进,上 U,下 D,左 L,右 R
{
snake  *nexthead;
cantcrosswall();//首先蛇不可以撞墙 
nexthead=(snake*)malloc(sizeof(snake));//动态分配内存空间 
if(status==U)//向上方向键 
{
nexthead->x=head->x;//横坐标不变,纵坐标减一 
nexthead->y=head->y-1;
	if(nexthead->x==food->x && nexthead->y==food->y)//如果下一个有食物//
	{
		nexthead->next=head;
		head=nexthead;
		q=head;
		while(q!=NULL)
		{ 
			Pos(q->x,q->y);
			printf("*");
			q=q->next;
		}
		score=score+add;//计算新得分 
		createfood();//吃完食物后生成食物 
}

else //如果下一个位置没有食物
{
nexthead->next=head;
head=nexthead;
q=head;
while(q->next->next!=NULL)
	{
		Pos(q->x,q->y);
		printf("*");
		q=q->next;
	}
	Pos(q->next->x,q->next->y);
	printf(" ");
	free(q->next);
	q->next=NULL;
	}
}
if(status==D)//向下移动 
{
	nexthead->x=head->x;//横坐标不变,纵坐标加一 
	nexthead->y=head->y+1;
	if(nexthead->x==food->x && nexthead->y==food->y) //下一个节点有食物
	{
 		nexthead->next=head;
		head=nexthead;
		q=head;
		while(q!=NULL)
		{
			Pos(q->x,q->y);
			printf("*");
			q=q->next;
		}
score=score+add;
createfood();
}
else //下一节点没有食物
{
	nexthead->next=head;
	head=nexthead;
	q=head;
	while(q->next->next!=NULL)
	{
		Pos(q->x,q->y);
		printf("*");
		q=q->next;
	}
	Pos(q->next->x,q->next->y);
	printf(" ");
	free(q->next);
	q->next=NULL;
	}
}
if(status==L)//向左移动 
{
nexthead->x=head->x-2;//横坐标减2,纵坐标不变 
nexthead->y=head->y;
if(nexthead->x==food->x && nexthead->y==food->y)//下一节点有食物
{
nexthead->next=head;
head=nexthead;
q=head;
while(q!=NULL)
{
Pos(q->x,q->y);
printf("*");
q=q->next;
}
score=score+add;
createfood();
}
else //下一节点没有食物
{
nexthead->next=head;
head=nexthead;
q=head;
while(q->next->next!=NULL)
{
Pos(q->x,q->y);
printf("*");
q=q->next;
}
Pos(q->next->x,q->next->y);
printf(" ");
free(q->next);
q->next=NULL;
}
}
if(status==R)//向右移动 
{
nexthead->x=head->x+2;//横坐标加2,纵坐标不变 
nexthead->y=head->y;
if(nexthead->x==food->x && nexthead->y==food->y)//下一节点有食物
{
nexthead->next=head;
head=nexthead;
q=head;
while(q!=NULL)
{
Pos(q->x,q->y);
printf("*");
q=q->next;
}
score=score+add;
createfood();
}
else //下一个节点没有食物
{
nexthead->next=head;
head=nexthead;
q=head;
while(q->next->next!=NULL)
{
Pos(q->x,q->y);
printf("*");
q=q->next;
}
Pos(q->next->x,q->next->y);
printf(" ");
free(q->next);
q->next=NULL;
} 
}
if(bite_itself()==1) //判断是否会咬到自己
{
endgamestatus=2;
endgame();//咬到自己就会结束游戏 
}
}

void pause()//游戏暂停
{
while(1)
{
Sleep(300);//延迟300ms 
}
}

void gamecircle()//控制游戏
{

Pos(64,15);
printf("不能穿墙,不能咬到自己");
Pos(64,16);
printf("用上下左右键控制蛇的移动");
Pos(64,17);
printf("ESC:退出游戏。");
while(1)
{
	Pos(64,10);
	printf("得分:%d",score);
	Pos(64,11);
    printf("每个食物的得分:%d",add);
	if(GetAsyncKeyState(VK_UP)&& status!=D)
	{	
		status=U;//对应下一个按键状态 
	}
	else if(GetAsyncKeyState(VK_DOWN)&&status!=U)
	{
		status=D;
	}
		else if(GetAsyncKeyState(VK_LEFT)&&status!=R)
	{
		status=L;
	}
			else if(GetAsyncKeyState(VK_RIGHT)&&status!=L)
	{
		status=R;
	}	
Sleep(sleeptime);//休息一段时间 
snakemove();
}
}

void welcometogame()
{
	Pos(20,12);
	printf("欢迎来到贪吃蛇小游戏\n");
	system("pause");//利用系统函数冻结屏幕 
	system("cls");//利用系统函数清屏,实现动态刷新 
}

void endgame()//结束游戏
{
	system("cls");
	Pos(24,12);
	if(endgamestatus==1)
	{	

    printf("你撞到墙壁了,游戏结束!\n");

	}
	else if(endgamestatus==2)
	{
		printf("你咬到自己了,游戏结束!");
	}
	
    Pos(24,13);
	printf("您的分数是%d\n",score);
//	exit(0);
}

void gamestart()
{	
	system("mode con cols=100 lines=30");  //将界面的大小设置为100列和30行 ,要是默认的话会有溢出 
	welcometogame();
	creatInterface();
	InitializeSnake();
	createfood();
}
int main()
{
 gamestart();//开始 
 gamecircle();//运转 
 endgame();//结束 
 return 0;
}

总结及改进

(一)项目中存在的不足之处:
1、界面简单,不美观,观赏度低;
2、可操作性低,如果要改变蛇移动的速度,还需要调整相应的代码来修改,比较麻烦;
3、使用系统中的API函数来刷新界面,在Dev-C++中有时候会出现卡顿的现象,但是已经做出了相应的调整和改进,基本没有问题出现;
4、游戏的功能设计的比较少,体验感不强。
(二)进一步的改进方向:
1、为界面增添颜色,使界面更加美观。(VC++6.0中)
这里可以使用System函数(System(“color 4A”);)来实现,4是背景色,A代表前景色
其他补充的颜色代码使用:
0=黑色; 1=蓝色;2=绿色;3=湖蓝色; 4=红色; 5=紫色; 6=黄色; 7=白色;8=灰色;
9=淡蓝色;
A=浅绿色;B=淡浅绿色;C=淡红色;D=淡紫色;E=淡黄色;F=亮白色;
同时也可以在控制台设置局部的字体和颜色:SetConsoleTextAttribute(句柄,颜色)
wAttribute是用来设置颜色的参数
setbkcolor()//设置背景的颜色
setcolor()//设置前景颜色
moveto()//移动到指定坐标
PS:这里可以到EasyX的官网上下载图形库,就可以在VC++6.0的环境下绘制图形,修改颜色,这个小模块我比较感兴趣,所以可以寒假有时间再总结一下。
2、增加游戏的其他功能,例如设置其他按键功能可以使蛇的速度加快或者减慢,还可以设计按键使游戏暂停,还可以赋予小蛇生命值,来增强游戏的体验感。
(三)开发心得:
在制作这个项目中接触到了特殊的数据类型——结构体数据类型,并且在此过程中大量使用了指针,我觉得这很具有灵活性,利用指针的不同指向来增加蛇的节点,使蛇可以在设计的界面上移动,并且涉及到了动态分配内存空间的问题,以及很多的系统API的函数的使用,比如光标的定位,还有System函数的常用指令,利用它可以实现清屏操作和刷新屏幕界面,在此过程中学习到了很多以前没有接触的东西,也改变了原有的思维模式,使我受益匪浅。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!