纯C语言实现贪吃蛇

//#include "tanchishe.h"
// #define _tanchishe_H_
 
#include <ctime> 
#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<time.h>
#include<conio.h>  //getch()函数   
#include<iostream>
using namespace std;

/*宏定义 */
#define UP 87
#define DOWN 83
#define LEFT 65
#define RIGHT 68 
#define PAUSE 32
#define SPEED_UP 74
#define SPEED_DOWN 75
#define ESC 27

unsigned int  KeyValue;// 记录键盘输入 

/*蛇身位置  snake链表数据*/
typedef struct Snakes{
	unsigned int x;
	unsigned int y;
	struct Snakes* next ;
}snake; 

snake* head = (snake*)malloc(sizeof(snake)); //创建蛇头节点 

/*食物位置  food 结构体数据*/
struct FOOD {
	unsigned int x;
	unsigned int y; 	
}food;  

struct Player{ //玩家属性——得分,按键值 等 
	unsigned int score;	
	unsigned int key_click; 
	unsigned int high_score; 
	unsigned int speed;
}player;   

void gotoxy(unsigned int x, unsigned int y){  /*设置光标位置 *///几列几行  
	
    HANDLE hOut;  //创建  句柄  
  
    COORD pos; 
    
    pos.X=x;
    pos.Y=y;
    
    hOut=GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOut,pos);  //传入 句柄   输出位置结构体变量 
    
    /*隐藏光标操作 */
    CONSOLE_CURSOR_INFO cursor;
	cursor.bVisible = FALSE;    
	cursor.dwSize = sizeof(cursor);
	SetConsoleCursorInfo(hOut, &cursor);
}
void gotodelete(unsigned int x, unsigned int y){ //删除时 填充空格 
    gotoxy(x, y);
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x06|0x09);
    printf("  ");
}
void gotoprintwall(unsigned int x, unsigned int y){ //围墙 
	 gotoxy(x, y);
	 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x09|0x09);
     printf("■");
}

void gotofood(unsigned int x, unsigned int y) { //食物打印 ★
	  //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03|0x02); // 设置由hOut光标 输出的文本颜色 ,可调用 

	 gotoxy(x, y);
     printf("★"); 
}

void gotoprinthead(unsigned int x, unsigned int y) { //蛇头打印  ⊙
	 //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03|0x02); // 设置由hOut光标 输出的文本颜色 ,可调用 

	 gotoxy(x, y);
     printf("⊙"); 
}

void gotoprintsnake(unsigned int x, unsigned int y) { //其他3打印  ◎ 
	  //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03|0x02); // 设置由hOut光标 输出的文本颜色 ,可调用 

	 gotoxy(x, y);
     printf("◎"); 
}

void goto_other1(unsigned int x, unsigned int y) { //其他1打印 ☆ 
	 //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03|0x02); // 设置由hOut光标 输出的文本颜色 ,可调用 

	 gotoxy(x, y);
     printf("☆"); 
}
void goto_other2(unsigned int x, unsigned int y) { //其他2打印  ¤
	 //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03|0x02); // 设置由hOut光标 输出的文本颜色 ,可调用 

	 gotoxy(x, y);
     printf("¤"); 
}

void goto_other4(unsigned int x, unsigned int y) { //其他4打印  □ 围墙    ★☆□⊙ 
	 gotoxy(x, y);
	 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x06|0x06);//橙色 
     printf("□"); 
}

void gotoprintf(unsigned int x, unsigned int y,const char* ha ){  
	 gotoxy(x, y);
	 //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03|0x02); // 设置由hOut光标 输出的文本颜色 ,可调用 
      //0x09|0x06白  0x06|0x06 橙色  0x04|0x04红色   ......
	 while(*ha)
	 {
     	cout<<*ha;
     	++ha;
	 }
}
void Get_Time2 ()//时间显示 
{
   time_t rawtime;
   
   struct tm *info;
   
   char buffer[50];//最后拷贝存放容器 
 
   time( &rawtime );
 
   info = localtime( &rawtime );
 
   strftime(buffer, 50, " %Y-%m-%d %H:%M:%S  %A", info);
   //size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr) 
	//根据 format 中定义的格式化规则,格式化结构 timeptr 表示的时间,并把它存储在 str 中
   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0b|0x0b );//芥末色 
   gotoprintf(60,13, buffer);
}
/*开始界面*/
void Welcome(){
	unsigned int x;
	system("cls");  // 清屏 
	 
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0c|0x0a);//金色 
	gotoprintf(22,4,"=》请开启英文输入法操作《=") ;
	gotoxy(22,6);
	printf("哈哈哈,简单的贪吃蛇---");
	gotoxy(22,8);
	printf("请按空格键 开始 / 暂停");
	gotoxy(22,10);
	printf("操作:上下左右 wsad WSAD");
	gotoxy(22,12);
	printf("     加速:J    减速:K");
	gotoxy(22,14);
	printf("按N重新开始  ,  按 Esc 键 退出"); 
	while(1){
		x=getch();
		if(x==' ' )break;	
		else if(x==ESC) 
		{
			system("cls"); 
			gotoprintf(15,13,"=======已退出游戏,按任意键关闭窗口=======") ;
			exit(0);
		} 
	}; 
	/*清屏*/
	system("cls"); 	
} 
/*结束界面*/
void Finish(){//游戏结束 
 
 /*地图右侧显示元素*/
 	unsigned char i; 
 	
    for (i = 5; i <=19; i++)
	{
        goto_other4(56, i);
        goto_other4(94, i);
    }
    for (i = 56; i <= 94; i=i+2)
	{
        goto_other4(i, 5);
        goto_other4(i, 19);
    }
    
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0c|0x0a);//白色 
    
    gotoxy(60, 11);
    printf("得分 :%d    = ̄ω ̄= ", player.score/10);
    gotoprintf(34, 28,"游戏作者 : JH ");
  
    gotoxy(60, 8);
    printf("游戏结束    o(* ̄▽ ̄*)o");
    gotoxy(60, 14);
    printf("还不错哦 ,继续努力O( ∩_ ∩)O");
    gotoxy(60, 16);
    printf("=》按空格键继续,=》按ESC键退出");
    // 清除蛇头以外的蛇身数据 
    snake* p = head->next, * q;
    while (p != NULL) 
	{
        q = p->next;
        free(p);
        p = q;
    }
    head->next=NULL; 
    
    while(1){
    	
		unsigned int x=getch();
		
		if(x==' ' )  break;	
		
		else if(x==ESC) 
		{
			system("cls"); 
			gotoprintf(15,13,"=======已退出游戏,按任意键关闭窗口=======") ;
			exit(0);
		} 
	};
    KeyValue=0;
    player.key_click=0;
	system("cls");
}
void creat_food(){// 随机产生一个食物

    bool flag = false;
    
    srand((int)time(NULL));
    
    while (!flag)
    {
        flag = true;
        food.x = rand() % (51-4) + 4;
        food.y = rand() % (25-2) + 2;
        //打印 一格中文字符 宽度为2  保证偶数位置 
        if (food.x & 0x01 != 0)
        {
            food.x = food.x + 1;
        }
        snake* judge = head;
        while (1)  //遍历排除蛇身重复
        {
            if (judge->next == NULL) break;
            if (food.x == judge->x && food.y == judge->y)
            {
                flag = false;
            }
            judge = judge->next;
        }
    }//找到合适食物的位置 跳出循环
    
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x06|0x06 ); //橙色 食物 
    gotofood(food.x,food.y);
}
void Creat_snake(){ //创建初始蛇的位子 

	snake* p = (snake*)malloc(sizeof(snake));
    snake* q = (snake*)malloc(sizeof(snake));
    
   if(NULL!=p && NULL!=q) 
    {//   判断 p, q申请到内存空间了没
	 
		srand(time(NULL));//用于 随机方向 随机位置
		player.key_click=rand()%(5-1)+1; //初始方向
		head->x = rand()%(36-18)+18;//初始蛇身位置  x列 y行 2-52 1-26 | 18-36   9-18  
	    head->y = rand()%(19-9)+9;  //rand/(大-小)+小   所得区间 [小,大) 
	    
	     //打印 一格中文字符 宽度为2  保证偶数位置 
	    if(head->x & 0x01)
		{
	    	head->x +=1; 
		}
	    switch (player.key_click){
	    	
	    	case 1:  player.key_click=UP; 
					 p->x = head->x;
	   				 p->y = head->y+1;
	    			 q->x = p->x;
	    			 q->y = p->y+1; 
					 break;
					 
	    	case 2:  player.key_click=DOWN; 
					 p->x = head->x;
	   				 p->y = head->y-1;
	    			 q->x = p->x;
	    			 q->y = p->y-1; 
					 break;
					 
	    	case 3:  player.key_click=LEFT; 
					 p->x = head->x +2;
	   				 p->y = head->y;
	    			 q->x = p->x +2;
	    			 q->y = p->y; 
					 break;
					 
	    	case 4:  player.key_click=RIGHT; 
					 p->x = head->x-2;
	   				 p->y = head->y;
	    			 q->x = p->x-2;
	    			 q->y = p->y; 
					 break;
	 
		} 
	   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x09|0x09); //蓝色 
	   /*打印初始的蛇  长度三*/
	   gotoprintsnake(head->x,head->y);
	   gotoprintsnake(p->x,p->y);
	   gotoprintsnake(q->x,q->y);
	 
	    head->next = p;//最初蛇身 连接起来 
	    p->next = q;
	    q->next = NULL;
	    q=NULL;
   		p=NULL;
    	free(p);
    	free(q);
    }
    else
	{
    	gotoprintf(2,5, "创建失败");
    	q=NULL;
   		p=NULL;
    	free(p);
    	free(q);
    	exit(0);
	}
}  
void Creat_map(){//创建地图   	
    unsigned int i;
   //50*26
    for (i = 2; i <= 52; i += 2){/*注意这里横坐标是每次+2 因为控制台字符宽高比为 1:2 */
        gotoprintwall(i, 1);
        gotoprintwall(i, 26);
    }
    for (i = 1; i <= 26; i++){
        gotoprintwall(2, i);
        gotoprintwall(52, i);
    }
    /*地图右侧显示元素*/
    for (i = 5; i <=19; i++){
        goto_other4(56, i);
        goto_other4(94, i);
    }
    for (i = 56; i <= 94; i=i+2){
        goto_other4(i, 5);
        goto_other4(i, 19);
    }
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0a|0x0a);
    gotoprintf( 60, 8, "====  游戏进行中  ====");
  
    gotoxy(60, 11);
    printf("得分 :%d    = ̄ω ̄= ", player.score);
    gotoxy(34, 28);
    printf("游戏作者 : JH ");
    Creat_snake(); 
  	creat_food();
   	player.speed=180;
	player.score=0;
} 
unsigned char Judge(){ //判断 
	if (head->x == 2 || head->x == 52 || head->y == 1 || head->y == 26) {return 0; }//失败 
	
    snake* p = head->next;
    
    while (1){
        if (p == NULL) break;
        if (head->x == p->x && head->y == p->y)
		{
            return 0;//吃到自己 失败 
        }
        p = p->next;
    }
    return 1;  // 没有失败  继续移动 
}

void AddBody(){//得分 添加长度 尾部 
    if (head->x == food.x && head->y == food.y)
    {
        creat_food();
        snake* _new = (snake*)malloc(sizeof(snake));
        snake* p;
        p = head;
        while (1)//遍历到 蛇身链表 尾部 
        {
            if (p->next == NULL) break;
            p = p->next;
        }
        p->next = _new;//在尾部 添加新的节点 
        _new->next = NULL;
        player.score += 1;
        gotoxy(60, 11);
    	printf("得分 :%d    = ̄ω ̄= ", player.score);
    }
}
void UpdateBody(unsigned int x, unsigned int y){//刷新蛇身坐标   
    /*删除尾部节点*/
	snake* p = head;
    while (p->next->next != NULL) {
        p = p->next;
    }
     
    /*通过先清空尾部 后打印开头   每个位置坐标点固定部不动  只进行 添删头尾 操作 */
    
    gotodelete(p->next->x, p->next->y); // 消除尾结点轨迹 
    
    free(p->next);//释放尾部节点 
    p->next = NULL;
    
     /*添加移动后的坐标*/  
    p = (snake*)malloc(sizeof(snake));
    p->x = x;
    p->y = y;
    
    /*添加 新的蛇头坐标 链表节点*/
    p->next = head;
    head = p;
    
	/*最后释放p 这个临时节点 */
	 p=NULL;
	 free(p);
	 
	 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03|0x02);//淡蓝色 蛇身 
	 gotoprintsnake(head->next->x ,head->next->y);
	  
	 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x09|0x06);//白色蛇头 
	 gotoprinthead(x,y); /*打印新蛇头轨迹*/
}
void RunBody(){//完整行走动作   

    unsigned int x = head->x;
	unsigned int y = head->y;
    
    switch (player.key_click)
    {
    case UP:
        y -= 1;
        break;
    case DOWN:
        y += 1;
        break;
    case LEFT:
        x -= 2;
        break;
    case RIGHT:
        x += 2;
        break;
    }
   if( !(x == 2 || x == 52 || y == 1 || y == 26))
   {
   
	    if (x != head->x || y != head->y) 
		{
	        UpdateBody(x, y);/* 删除尾结点 添加新的头结点  */
	    }
    }
    /*把下面的else删了,撞墙不死*/
    else
	{//如果已经撞墙了 
    	head->x=2;
	}
 
    // 蛇速度控制 
	Get_Time2 ();
    Sleep(player.speed);
}

unsigned char ClickControl(){//按键控制 	
    while (1)
    {
        if (Judge() == 0) 
		{ 	
			Finish();
			return 0; //游戏失败 返回 0 
 		}     
 		
        if (_kbhit()) // _kbhit() 检测按键函数 请百度 
        { 
        	KeyValue=getch();  
			 	
        	if(KeyValue==ESC) 
			{//退出 
	        	KeyValue=0;
	        	return 1; //退出返回 1  
			 }
			if(KeyValue=='N'||KeyValue=='n')
			{//新游戏 
				KeyValue=0;
				return 2;
			 }
        	switch (KeyValue)
			{	
				case PAUSE : while(1)
							{	
								if(_kbhit()) {	KeyValue=getch(); break; }  
							} break;
				
				case 106:
				case SPEED_UP	:	if(player.speed>=60 ) { player.speed-=10; }	KeyValue=0;	break;
				
				case 107:
			    case SPEED_DOWN :	if(player.speed<=270) { player.speed+=10; } KeyValue=0;	break;
		    	
				case 119:	
				case UP   :	if(player.key_click!=DOWN)  player.key_click=UP; 	break;
				
				case 115:
				case DOWN :	if(player.key_click!=UP)    player.key_click=DOWN;	break;
				
				case 97:
				case LEFT :	if(player.key_click!=RIGHT) player.key_click=LEFT;	break;
				
				case 100:
				case RIGHT: if(player.key_click!=LEFT)  player.key_click=RIGHT;	break;
				
				default : break;
			}   	
        }
		 RunBody();
         AddBody();
	}	     
    return 1;  
}

void game(){ //贪吃蛇游戏  封装一下 

	while(1)
	{ 	
		Welcome();
		Creat_map();
		if(1==ClickControl())
		{ 
			break;
		} 
    }	
    system("cls");
    gotoprintf(20,20,"已经退出游戏,按任意键关闭窗口"); 
} 
 
 /*主函数 精简一些*/ 
 
int main()
{
	game(); 
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值