C语言 贪吃蛇

C 专栏收录该内容
19 篇文章 2 订阅

C语言 贪吃蛇

一、简述

       记--用C语言简单实现贪吃蛇小游戏。

二、效果

      使用上下左右方向键控制方向, 按ESC退出游戏。

       

       

三、代码结构

       

四、源代码

#include <stdio.h>  //标准输入输出函数库 
#include <stdlib.h> //包含system函数 
#include <windows.h>//包含Sleep函数,来控制速度
#include <time.h>   //设置食物时随机生成坐标用到time做种子
 
#define DOWN_WALL 20	 //下边框  (下面的墙)   //使用宏定义 ,是方便以后调整边框大小 
#define RIGHT_WALL 58 //右边框 (右面的墙)
 
//加上typedef 以后声明此类型的结构体不需要struct关键字,可以用这样声明 Snake s1;(原来:struct s_snake s1)
typedef struct s_snake //用来存储每一段蛇身的坐标位置 
{
	int x; //x坐标 
	int y; //y坐标 
	struct s_snake *next; //下一段蛇身 
}Snake;
 
/*函数声明*/
void SetPos(int x,int y);//移动光标函数
int IsHitWall();//判断撞墙函数
int IsBiteYouself();//判断咬到自己的函数
void DrawFrame();//画边框函数
void InitSnake();//初始化蛇函数
void CreateFood();//创建食物函数
void PlayGame();//游戏移动循环函数
int Move();//移动函数,方向控制 
void Welcome();//欢迎界面
void free_snake(Snake *head);//释放资源 
 
Snake *head,*end;//蛇头、蛇尾
Snake *p;//辅助指针
int speed=310;//休眠时间,用来控制移动速度 
int level = 0,score = 0;//分数
int foodx,foody;//食物的(x,y)坐标
char key;//方向,暂停/继续 控制状态 
 
int main()
{
    Welcome(); //欢迎界面 
	DrawFrame();//画边框 
	InitSnake();//初始化蛇身 
	CreateFood();//创建食物 
	
	//右侧提示信息 
	SetPos(60,7);
	printf("得分:%d",score);
	SetPos(60,8);
	printf("当前速度:%d毫秒",speed);
	SetPos(60,9);
	printf("每+30分速度变快");
	SetPos(60,10);
	printf("不能撞墙/咬到自己");
	SetPos(60,11);
	printf("按空格暂停/继续");
	
	PlayGame();//按方向键控制蛇身进行游戏 
	
	free_snake(head);
    return 0;
}
 
void SetPos(int x,int y)//设置光标位置(就是输出显示的开始位置)
{
	/*  COORD是Windows API中定义的一种结构体 
	 *	typedef struct _COORD 
	 *	{
	 *		SHORT X; 
	 *		SHORT Y;
	 *	} COORD; 
	 *
	 */
	COORD pos = {x,y};
	HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);//获得 标准输出的句柄
    SetConsoleCursorPosition(output,pos); //设置控制台光标位置 
}
 
int IsHitWall()//判断是否撞墙 
{
	if (head->x==0||head->x==RIGHT_WALL||head->y==0||head->y==DOWN_WALL)
	{  //因为蛇头最先动,并且蛇身后一段下一步会在前一段,所以只要蛇头不撞墙,那么整个蛇身就不会 撞墙 
		SetPos(DOWN_WALL,14);
		printf("游戏结束!撞到墙了\n");
		SetPos(DOWN_WALL,15);//令 ‘按任意键继续...’居中显示 
		//system("pause");//暂停
		return 1;
	}
	return 0;
}
 
int IsBiteYouself()//判断是否咬到自己 
{
	while(p->next!=NULL)
	{
		p=p->next;
		if (head->x==p->x&&head->y==p->y)//判断蛇头是否与其他蛇身重合 
		{
			SetPos(DOWN_WALL,14);
		    printf("游戏结束!你咬到自己了\n");
		    SetPos(DOWN_WALL,15);//令 “请按任意键继续”居中显示 
			//system("pause");//暂停 
		    return 1;
		}
	}
	return 0;
}
 
void DrawFrame()//画边框 
{
	int i = 0;
	for(i=0;i<60;i+=2)//打印上下边框 注意i 一段蛇身占用 x 2个单位, y 1个单位 
    {
        SetPos(i,0);   //上边框 
        printf("■");
        SetPos(i,DOWN_WALL);//下边框 
        printf("■");
    }
    for(i=1;i<DOWN_WALL;i++)//打印左右边框
    {
        SetPos(0,i); //左边框 
        printf("■"); 
        SetPos(RIGHT_WALL,i); //右边框 
        printf("■"); 
    }
}
 
void InitSnake()//初始化蛇身  头插法	初始化从(20,15)开始的四段蛇身 (横向排列) 
{
	int i = 0;
	
	//创建一个蛇身位置 蛇尾 
	end=(Snake*)malloc(sizeof(Snake));
	end->x=20;
	end->y=15;
	end->next=NULL;
	
	//创建三个蛇身位置 
	for (i=1;i<=3;i++)
	{
		head = (Snake*)malloc(sizeof(Snake));
		head->x = 20+2*i; //每个蛇身 x相差 2个单位 
		head->y = 15;
		
		head->next=end;  //头插法 
		end = head;
	}
	
	//从蛇头开始画贪吃蛇 
	while (end->next!=NULL)
	{
		SetPos(end->x,end->y);
		printf("■");
		end = end->next;
	}    
}
 
void CreateFood()//设置食物 
{
	srand(time(0));//设置随机数种子 
	flag:
	while(1)//由于food的x坐标必须为偶数,所以设置循环判断是否为偶数
	{
		//rand()%num产生 0~num-1
		//rand产生范围数公式rand()%(m+1-n)+n;有效范围在 [n,m]
		foody=rand()%(DOWN_WALL-1+1-1)+1;//foody的有效范围在 [1,DOWN_WALL-1 ]
		foodx=rand()%(RIGHT_WALL-2+1-3)+3;//foodx的有效范围在    [3,RIGHT_WALL-2] 注意x是以2为单位的 
		if (foodx%2==0)
	    {
		    break;
	    }
	}
	p=head;
	while(1) 
	{
		if(p->x==foodx&&p->y==foody)//若生成坐标和蛇重叠了,回到生成坐标循环
		{
			goto flag;
		}
 
		if(p->next==NULL) //与每一段蛇身比较完毕,跳出循环 
		{
			break;
		}
		p=p->next;
	}
	
	SetPos(foodx,foody);
	printf("■");  //显示食物 
}
 
void PlayGame()//贪吃蛇移动,暂停
{
	int mv_ret = 0;//移动后的返回值,如果撞墙、或就咬到自己设置为1 
	key = 'd';//刚开始,贪吃蛇默认向右移动 
	while (1)
	{	
		//GetAsyncKeyState(VK_UP) 判断VK_UP按键的状态,若是被按下,则位15设为1;如抬起,则为0 
		//所以要 与上0x8000 取出第15位 进行判断  
		if ((GetAsyncKeyState(VK_UP)&& 0x8000)&& key != 's')//与key!='s',因为不能后退 
		{
			key='w';//如果本来不是向下的,按下向上键,将key设置为w 
		}
		else if ((GetAsyncKeyState(VK_DOWN)&& 0x8000)&& key != 'w')
		{
			key='s';
		}
		else if ((GetAsyncKeyState(VK_RIGHT) && 0x8000)&& key != 'a')
		{
			key='d';
		}
		else if ((GetAsyncKeyState(VK_LEFT)&& 0x8000) && key != 'd')
		{
			key='a';
		}
		else if (GetAsyncKeyState(VK_SPACE)&& 0x8000) //暂停/继续函数 
		{
			//补上消隐的蛇尾(蛇尾还在)  原因未知   
			while(p->next!=NULL) p=p->next;
			SetPos(p->x,p->y);
			printf("■");
			
			while(1)//暂停语句
			{
				Sleep(100); //必要延时(消抖) Sleep(毫秒)
				if (GetAsyncKeyState(VK_SPACE)&& 0x8000)
				{
					break;
				}
			}
			
			//擦掉补上的 蛇尾 
			SetPos(p->x,p->y);
			printf(" ");
		}
		else if(GetAsyncKeyState(VK_ESCAPE)&& 0x8000)//按下ESC退出游戏,VK_ESCAPE == 27 
		{
			return ; 
		}
		 
		
		//实时刷新速度  得分每+30分 移动速度变快
		if (score==level && speed > 10)//判断得分
		{
			speed -=10; //睡眠时间,改变移动速度,越少越快 
			level +=30; //速度变快条件 变化 
			
			SetPos(60,8);
			printf("当前速度:%d毫秒",speed);
		}
		mv_ret = Move();//移动蛇身 
		if( mv_ret == 1)
		{
			break;
		} 
	}
}
 
int Move()//移动函数,w前 s后 a左 d右,实现移动:头部增加一个,尾部减掉一个 
{
	int ret;
	
	//不是按下控制方向的 a,s,d,w 就 
	if( (key != 'a') && (key != 's') && (key != 'd') && (key != 'w') ) 
	{
		return 0;
	}
	
	ret = IsHitWall(); //是否撞墙 
	ret += IsBiteYouself(); //是否咬到自己 
	if(ret == 1)
	{
		return 1;
	}
	
	p = (Snake*)malloc(sizeof(Snake));//头部增加的那个 
	p->next=head;//添加到头部 
	
	switch(key)
	{
		case 'd'://向右 
		    p->x = head->x+2;//右边 
		    p->y = head->y;
	        break;
	
		case 'w'://向上 
			p->x=head->x;
			p->y=head->y-1;//向上 
			break;
			
		case 's'://向下 
			p->x=head->x;
			p->y=head->y+1;//向下 
			break;
			
		case 'a'://向左 
			p->x=head->x-2;//向左 
			p->y=head->y;
			break; 
			
	}
	
	//画出新的头部 
	SetPos(p->x,p->y);
    printf("■");
    
    head = p;//在贪吃蛇的头部添加一个称为新的头 ,相当于是贪吃蛇移动一格 
    		//如果 移动的一格刚好是食物的位置,新增的称为蛇头,不用去掉蛇尾
			//如果 移动的一格不是食物的位置,新增的称为蛇头,去掉蛇尾,就是贪吃蛇移动一格的效果 
    
    Sleep(speed);//移动速度的控制 
	if (p->x==foodx && p->y==foody)//移动的一格刚好是食物的位置 
	{
		CreateFood();
		score +=10;
		SetPos(60,7);
		printf("得分:%d",score);
		
	}
	else   //吃不到食物,头部添加一个,尾部去掉一个 
	{
		//移动的一格刚好是食物的位置,新增的称为蛇头,不用去掉蛇尾 
		while (p->next->next != NULL) p = p->next;//指向蛇尾前一格,然后释放蛇尾,并将原来的尾二置空。

		SetPos(p->x, p->y);//为什么不是setPos(p->next->x,p->next->y)? 
		printf(" ");//擦掉蛇尾(蛇头加一,蛇尾减一,实现移动效果) 

		free(p->next);//释放蛇尾
		p->next = NULL;//必须置空,不然原来的尾二还是指向原来的尾巴(但是原来的为尾巴已经释放了)
		p = head;//将p指向head 
	}
	
	return 0;
}
 
void Welcome()//欢迎界面 
{
	SetPos(25,8);
	printf("【贪吃蛇】   作者:Genven_Liang");
	SetPos(25,11);
	printf("【游戏规则】");
	SetPos(25,12);
	printf("1、不能撞墙、咬到自己");
	SetPos(25,13);
	printf("2、按空格暂停/继续游戏");
	
	printf("\n");
	SetPos(30,15);
	system("pause");//暂停 
	system("cls");//清屏 
}
 
void free_snake(Snake *head)//释放资源,释放链表空间 
{
	if(head == NULL || head->next == NULL)
	{
		return ;
	}
 
    //从头部开始逐个节点释放
	while( (p=head) != NULL)
	{
		head = head->next;
		free(p);						
	}	
}
 

五、关于看不见“游戏结束”

           例子使用的是C-Free,这个IDE在程序结束后会暂停的;如果使用的是Visual Studio,程序结束后不会暂停;需要在IsHitWall()函数和IsBiteYouself()函数里面加上一句system(pause);暂停一下(或者是加上一句getchar()),这样就能看见"游戏结束"了。

六、问题记录

   6.1 残留问题

         目前在Win10-64bit家庭中文版 发现残留问题,现象如下:       

         ps:在Win7-32bit 系统,Win7-64bit系统,Win10专业版未发现该问题。

         产生原因:空格的宽度与■的宽度不一致,导致用空格不能完全擦除一段完整的蛇身--■

         解决办法:使用两个空格来擦除一段蛇身         

 

===========================以下回复 qq_45936030 这位老铁===================

使用Dev-C++ IDE 

使用VC6.0 IDE     (需要暂停一下才能看到最后的"游戏结束")

 

====================================以下回复  钢钢钢不爽 这位老铁 ======================

在字符映射表charmap中可以搜索 实心 就可以找到实心方形--就是黑色的那个正方形

可以使用快捷键Win键+R唤出运行窗口  (Win键就是这个按键

ps:还可以使用系统自带的造字程序进行自定义,搜索:专用字符编辑程序 或在运行窗口直接输入 eudcedit.exe 然后回车。

 

======================以下回复  xmx666 这位老铁 ===============

1 p->next->next是对的,p->next是不对的。以下是p->next->next和p->next的对比:

原因:在没有吃到食物情况,我们需要在前面增加一个方块,并将最后的方块A去掉,以实现移动效果。

         去掉最后一个方块有2个操作:1)将最后的方块A释放内存,擦除方块A;2)断开联系,方块A的前面的方块B不要再指向方块A。

         (如果不断开的话,B还是指向A,但是A已经被释放了,程序已经没有合法权限去的操作A的内存空间了。)

         其中while (p->next->next != NULL) p = p->next;是找到倒数第二个方块,

         释放方块A的空间不管是找到A还是A的前一个都是可以的,但是单项链表不能操作A的前一个。

         将A的前面一个的next置空,如果是使用p->next找到A并释放A,那么是不能直接操作A的前面一个的(但是可以增加一个变量用来指向A的前面一个)

用windows api 做的贪吃蛇 #include #include"resource.h" #include"Node.h" #include #include TCHAR szAppname[] = TEXT("Snack_eat"); #define SIDE (x_Client/80) #define x_Client 800 #define y_Client 800 #define X_MAX 800-20-SIDE //点x的范围 #define Y_MAX 800-60-SIDE //点y的范围 #define TIME_ID 1 #define SECOND 100 #define NUM_POINT 10 //点的总个数 #define ADD_SCORE 10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; //窗口句柄 MSG msg; //消息 WNDCLASS wndclass; //窗口类 HACCEL hAccel;//加速键句柄 wndclass.style = CS_HREDRAW | CS_VREDRAW; //窗口的水平和垂直尺寸被改变时,窗口被重绘 wndclass.lpfnWndProc = WndProc; //窗口过程为WndProc函数 wndclass.cbClsExtra = 0; //预留额外空间 wndclass.cbWndExtra = 0; //预留额外空间 wndclass.hInstance = hInstance; //应用程序的实例句柄,WinMain的第一个参数 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //设置图标 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //载入预定义的鼠标指针 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置画刷 wndclass.lpszMenuName = szAppname; //设置菜单 wndclass.lpszClassName = szAppname; //设置窗口类的名字 if (!RegisterClass(&wndclass))//注册窗口类 { MessageBox(NULL, TEXT("这个程序需要windows NT!"), szAppname, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppname, TEXT("Snack_eat"),//CreateWindow函数调用时,WndProc将受到WM_CREATE WS_OVERLAPPEDWINDOW&~WS_THICKFRAME& ~WS_MAXIMIZEBOX,//普通的层叠窗口&禁止改变大小&禁止最大化 CW_USEDEFAULT, //初始x坐标(默认) CW_USEDEFAULT, //初始y坐标 x_Client, //初始x方向尺寸 770 y_Client, //初始y方向尺寸 750 NULL, //父窗口句柄 NULL, //窗口菜单句柄 hInstance, //程序实例句柄 WinMain函数中第二个参数 NULL); //创建参数 ShowWindow(hwnd, iCmdShow);//显示窗口,iCmdShow是WinMain的第四个参数,决定窗口在屏幕中的初始化显示形式,例:SW_SHOWNORMAL表示正常显示 UpdateWindow(hwnd);//使窗口客户区重绘,通过向WndProc发送一条WM_PAINT消息而完成的 hAccel = LoadAccelerators(hInstance, szAppname);//加载加速键 while (GetMessage(&msg
#include <stdio.h> #include <windows.h> #include <conio.h> #include <time.h> //游戏窗口 #define FrameX 4 //游戏窗口左上角的X轴坐标 #define FrameY 4 //游戏窗口左上角的Y轴坐标 #define Frame_height 20 //游戏窗口的高度 #define Frame_width 20 //游戏窗口的宽度 //定义全局变量 int i,j; int a[2]; //用于记住蛇尾坐标,其中a[0]、a[1]分别表示横、竖坐标 //声明蛇的结构体 struct Snake { int x[100]; //蛇的横坐标,其中x[0]表示蛇尾的横坐标,x[N-1]表示蛇头的横坐标 int y[100]; //蛇的竖坐标,其中y[0]表示蛇尾的竖坐标,y[N-1]表示蛇头的竖坐标 int count; //蛇吃食物的个数 int length; //蛇的长度 int speed; //蛇的速度 }; //声明食物的结构体 struct Food { int x; //食物的横坐标 int y; //食物的竖坐标 }; /******光标移到指定位置**************************************************************/ void gotoxy(HANDLE hOut, int x, int y) //UNKNOW { COORD pos; pos.X = x; //横坐标 pos.Y = y; //纵坐标 SetConsoleCursorPosition(hOut, pos); } /******设置文本为绿色*****************************************************************/ void Set_TextColor_Green (void) { HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE); //UNKNOW SetConsoleTextAttribute(Handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN); //UNKNOW } /******制作游戏窗口******************************************************************/ void make_frame() { HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+13); //打印选择菜单 printf("Esc 退出游戏"); gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+15); printf("长按方向键:加速"); gotoxy(hOut,FrameX,FrameY); //打印框角 printf("╔"); gotoxy(hOut,FrameX+2*Frame_width-2,FrameY); printf("╗"); gotoxy(hOut,FrameX,FrameY+Frame_height); printf("╚"); gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+Frame_height); printf("╝"); for(i=2;i<2*Frame_width-2;i+=2) { gotoxy(hOut,FrameX+i,FrameY); printf("═"); //打印上横框 } for(i=2;i<2*Frame_width-2;i+=2) { gotoxy(hOut,FrameX+i,FrameY+Frame_height); printf("═"); //打印下横框 } for(i=1;i<Frame_height;i++) { gotoxy(hOut,FrameX,FrameY+i); printf("║"); //打印左竖框 } for(i=1;i<Frame_height;i++) { gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+i); printf("║"); //打印右竖框 } gotoxy(hOut,FrameX+Frame_width-5,FrameY-2); //打印游戏名称 Set_TextColor_Green (); //设置蛇为绿色 printf("贪吃蛇游戏"); } /******结束菜单*******************************************************************/ void over_game() { system("cls"); printf("\n\n\n\n\n\n\n\n\t\t\t\t游戏结束\n\n\n"); Sleep(2000); getch(); } /******菜单信息***************************************************************/ void print_information(HANDLE hOut,struct Snake *snake,struct Food *food) { gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+1); printf("level : %d",snake->count/5+1); //打印游戏等级 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+3); printf("score : %d",10*snake->count); //打印游戏得分 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+5); printf("eat food : %d",snake->count); //打印产生食物个数 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+7); printf("speed : %dms",snake->speed); //打印游戏速度 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+9); printf("foodX : %d",food->x); //打印食物的横坐标 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+11); printf("foodY : %d",food->y); //打印食物的竖坐标 } /******初始化蛇**********************************************************************/ void init_snake(struct Snake *snake) { snake->x[0]=FrameX+2; //初始化蛇的横坐标 snake->y[0]=FrameY+Frame_height/2; //初始化蛇的竖坐标 snake->speed=300; //初始化蛇的速度为300ms snake->length=3; //初始化蛇的长度为3节 snake->count=0; //初始化蛇吃的个数为0 for(i=1;i<snake->length;i++) {/* 依次得到蛇身、蛇头的坐标 */ snake->x[i]=snake->x[i-1]+2; snake->y[i]=snake->y[i-1]; } } /******移动蛇*************************************************************************/ void move_snake(HANDLE hOut,struct Snake *snake) { gotoxy(hOut,snake->x[0],snake->y[0]); printf(" "); /* 清除蛇尾*/ for(i=1;i<snake->length;i++) {/* 后一节的坐标依次取代前一节的坐标 */ snake->x[i-1]=snake->x[i]; snake->y[i-1]=snake->y[i]; } } /******打印蛇*************************************************************************/ void print_snake(HANDLE hOut,struct Snake *snake) { for(i=0;i<snake->length;i++) { gotoxy(hOut,snake->x[i],snake->y[i]); if(i==0) { printf("○"); //打印蛇尾 } else if(i==snake->length-1) { printf("¤"); //打印蛇头 } else { printf("⊙"); //打印蛇身 } } } /******随机产生食物*******************************************************************/ void get_food(HANDLE hOut,struct Snake *snake,struct Food *food) { srand((unsigned)time(NULL)); //初始化随机数 while(1) {/* 产生食物的条件:1.在游戏窗口内 2.不在蛇的身上 */ food->x = rand() % (Frame_width-1); food->y = rand() % Frame_height; if( food->x==0 || food->y==0 ) { continue; } food->x = 2*food->x + FrameX; //得到食物的横坐标 food->y+=FrameY; //得到食物的竖坐标 for(i=0;i<snake->length;i++) {/* 判断食物是否在蛇的身上,如果在蛇身上,则重新产生;否则,打印蛇身 */ if( food->x==snake->x[i] && food->y==snake->y[i] ) { break; } } if(i==snake->length) { gotoxy(hOut,food->x,food->y); printf("⊙"); break; } } } /******吃食物***************************************************************************/ void eat_food(HANDLE hOut,struct Snake *snake,struct Food *food) { if( snake->x[snake->length-1]==food->x && snake->y[snake->length-1]==food->y ) {/* 如果蛇头位置与食物位置相同,吃食物 */ snake->length++; //吃一个食物,蛇身增长一节 for(i=snake->length-1;i>=1;i--) {/* 蛇后节坐标依次赋值给蛇前一节的坐标,依次得到蛇身及蛇头的坐标 */ snake->x[i]=snake->x[i-1]; snake->y[i]=snake->y[i-1]; } snake->x[0]=a[0]; //得到蛇尾移动前的横坐标 snake->y[0]=a[1]; //得到蛇尾移动前的竖坐标 get_food(hOut,snake,food); //重新产生食物 snake->count++; //食物的个数增1 if( snake->count%5==0 ) {/* 当蛇吃Up_level个食物时,速度加快Up_speed毫秒并且升一级 */ snake->speed-=50; } } } /******穿墙**********************************************************************************/ void through_wall(HANDLE hOut,struct Snake *snake,char ch) { if( ch==72 && snake->y[snake->length-1]==FrameY) { snake->y[snake->length-1] = FrameY+Frame_height-1; //如果蛇在上框且向上移动,穿墙 } if( ch==80 && snake->y[snake->length-1]==FrameY+Frame_height ) { snake->y[snake->length-1] = FrameY+1; //如果蛇在下框且向下移动,穿墙 } if( ch==75 && snake->x[snake->length-1]==FrameX ) { snake->x[snake->length-1] = FrameX+2*Frame_width-4; //如果蛇在左框且向左移动,穿墙 } if( ch==77 && snake->x[snake->length-1]==FrameX+2*Frame_width-2 ) { snake->x[snake->length-1] = FrameX+2; //如果蛇在右框且向右移动,穿墙 } } /******判断蛇是否死**************************************************************************/ int if_die(struct Snake *snake) {/* 当蛇头碰到自身时,蛇死 ,返回值为0 */ for(i=0;i<snake->length-1;i++) { if( snake->x[snake->length-1]==snake->x[i] && snake->y[snake->length-1]==snake->y[i] ) { return 0; } } return 1; } /******开始游戏*******************************************************************************/ void start_game() { unsigned char ch=77; //定义用于接收键盘输入的字符变量 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量 struct Snake s,*snake=&s; //定义蛇的结构体指针并指向蛇的结构体 struct Food f,*food=&f; //定义食物的结构体指针并指向食物的结构体 make_frame(); //制作游戏窗口 init_snake(snake); //初始化蛇 get_food(hOut,snake,food); //随机产生食物 while(1) { print_information(hOut,snake,food); //打印菜单信息 a[0]=snake->x[0]; //记住蛇尾的横坐标 a[1]=snake->y[0]; //记住蛇尾的竖坐标 j=0; if(kbhit()) //unknow {/* 判断是否按下键盘,如果按下,ch接收键盘输入 */ ch=getch(); if(kbhit()) {/* 如果长按键盘,则加速 */ Sleep(20); //unknow j=1; } } switch(ch) { case 72: {/* 向上移动 */ move_snake(hOut,snake); //移动蛇 snake->y[snake->length-1]-=1; //蛇头的竖坐标向上移,即减1 break; } case 80: {/* 向下移动 */ move_snake(hOut,snake); //移动蛇 snake->y[snake->length-1]+=1; //蛇头的竖坐标向下移,即加1 break; } case 75: {/* 向左移动 */ move_snake(hOut,snake); //移动蛇 snake->x[snake->length-1]-=2; //蛇头的横坐标向左移,即减2 break; } case 77: {/* 向右移动 */ move_snake(hOut,snake); //移动蛇 snake->x[snake->length-1]+=2; //蛇头的横坐标向右移,即加2 break; } } through_wall(hOut,snake,ch); //穿墙 eat_food(hOut,snake,food); //吃食物 print_snake(hOut,snake); //打印蛇 if( if_die(snake)==0 || ch==27 || snake->speed==50 ) {/* 游戏结束条件:1.蛇碰到自身 2.按Esc键 3.速度为50ms */ gotoxy(hOut,FrameX+Frame_width-2,FrameY+Frame_height/2-1); printf("Game Over"); Sleep(2000); break; } if(j==0) { Sleep(snake->speed); //延迟时间 } else { Sleep(10); } } } int main() { system("color 0D"); //设置文本为粉红色 start_game(); //开始游戏 over_game(); //结束游戏 }
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值