博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简易贪吃蛇 C ~
阅读量:4216 次
发布时间:2019-05-26

本文共 8771 字,大约阅读时间需要 29 分钟。

C编写的控制台应用程序(黑框框~~~)

实现了贪吃蛇的一些基本功能如 : 积分、等级加速、暂停等简单功能

下面我们开始吧~

首先是准备工作:

其中的 COORD是 windows里面定义的一个结构体用于存储二维坐标

原型如下:

typedef struct _COORD{      //  用于存储二维坐标的结构体

    SHORT X;

    SHORT Y;

}COORD, *PCOORD;

#include
#include
#include
#include
#include
#include
#define W 26//边界宽度#define L 61//边界长度#define UP 72#define LEFT 75//依此是键盘上下左右对应的ASCII#define RIGHT 77#define DOWN 80#define SNAKE 1#define FOOD 2#define BAR 3#define MIDX L/2-4 //打印 Game Over 的位置#define MIDY W/2-2 typedef struct Node{ COORD cor; struct Node* next;}node;int score = 0; //记录分数int delay = 200; //控制蛇移动速度int len = 1; //蛇长度int grade = 1; //等级node* head;//蛇头COORD food;COORD mid = {MIDX, MIDY};COORD info_score = {L, W/3}; //打印分数 的位置COORD info_grade = {L, W/3+8};//打印等级的位置

还需要准备一个定位光标位置的函数:(能够把光标移动到pt 所指定的二维坐标处)

void gotoxy(COORD pt)	{		HANDLE hout;// 句柄		hout = GetStdHandle(STD_OUTPUT_HANDLE);//定位到标准输出		SetConsoleCursorPosition(hout, pt);			}
下面由于要
比较坐标是否相等的方较多,可用函数表示:

int cor_cmp(COORD pt1, COORD pt2)	{		return (pt1.X == pt2.X && pt1.Y == pt2.Y);	}int cor_cmp(COORD pt1, COORD pt2)	{		return (pt1.X == pt2.X && pt1.Y == pt2.Y);	}

判断坐标是否在边界上:

int in_border(COORD pt)	{		return (pt.X == L-1 || pt.X == 0 || pt.Y == 0 || pt.Y == W-1);		}

贪吃蛇的代码实现 主要分为五个部分:

1、初始化地图  2、获取移动方向  3、产生食物  4、移动和 局部更新(此方法没有选择完全更新整个地图) 5、判断游戏是否结束

一、初始化地图

void init_pos()//随机生成初始食物坐标和 蛇坐标	{		srand((unsigned int)time(NULL));		do{			food.X = rand() % (L-20) + 10;			food.Y = rand() % (W-5) + 5;			head->cor.X = rand() % 60;			head->cor.Y = rand() % 25; 		}while(cor_cmp(head->cor, food) || in_border(head->cor) || in_border(food));	}void init_game()	{		int i, j;		head = (node *)malloc(sizeof(node));//先创建蛇头 然后初始化		head->next = NULL;//别忘记 置为NULL		init_pos();//生成初始食物和蛇		for(i = 0; i < W; i++ ){			for(j = 0; j <= L; j++ ){				if(i == info_score.Y && j == info_score.X){//打印分数栏					printf("\t\tscore: %d",score);				}				if(i == info_grade.Y && j == info_grade.X){//打印等级栏					printf("\t\tgrade: %d",grade);				}				else if((i == 0 && j != L) || (i == W-1 && (j != L)) || j == 0 || j == L-1)					putchar('#');//边界符号				else if(i == food.Y && j ==  food.X)					putchar('@');//食物符号				else if(i == head->cor.Y && j == head->cor.X)					putchar('$');	//蛇头符号					else 					putchar(' ');					}			putchar('\n');		}	}

二、获取移动方向

注: kbhit()函数判断有无输入 , getch()读取输入但不回显(显示)

int get_dir(int old_dir)	{		int new_dir = old_dir;		if(kbhit() != 0){//这里保证了 如果没有输入 蛇头的方向将保持不变				getch();//第一次返回只是扩展字符 第二次返回真正的方向				new_dir = getch();			if(len > 1 && (abs(new_dir-old_dir) == 2 || abs(new_dir-old_dir) == 8))	//根据键值差 保证蛇不能回头 (回头就死了)				new_dir = old_dir;			}				return new_dir;	//返回蛇头方向	}

三、产生食物(返回的是食物位置的结构体)

COORD generate_food()	{		srand((unsigned int)time(NULL));//随机数产生食物(放在循环外面 ,  因为这是伪随机数)		int in_snake = 0;// 标记  食物是否 和 蛇身坐标重合		node *p;		COORD new_food;		do{			new_food.X = rand() % 60;			new_food.Y = rand() % 20;			p = head;			while(p != NULL){				if(cor_cmp(new_food, p->cor))					in_snake = 1;				p = p->next;			}		}while(new_food.X == 0 || new_food.X == L-1 || new_food.Y == 0 || new_food.Y == W-1 || in_snake);//满足不在边界 不重合 才停止				return new_food;		}

四、移动和 局部更新

void move_snake(int dir)	{		COORD last, current;		last = head->cor;//记录当前蛇头的坐标		switch(dir){			case UP :				head->cor.Y--;				break;			case DOWN :				head->cor.Y++;				break;			case LEFT :				head->cor.X--;				break;			case RIGHT :				head->cor.X++;				break;						}		node *p;		int grow = 0;		if(cor_cmp(food, head->cor)){			grow = 1;			food = generate_food();		}		p = head->next;		while(p != NULL){//更新蛇身体 蛇头给第二节、 第二节 给第三节  依此进行 知道蛇尾 其中 结束时候last保存的是上一过程蛇尾的坐标			current = p->cor;			p->cor = last;			last = current;			gotoxy(p->cor);			putchar('*');  //蛇身体 用 * 表示			p = p->next;		}		gotoxy(head->cor);//光标定位到新的蛇头处 打印蛇头		putchar('$');		if(grow){			for(p = head; p->next != NULL; p = p->next); //找到 蛇尾			p->next = (node *)malloc(sizeof(node));			p->next->cor = last;			p->next->next = NULL;//  不要忘记 置为NULL  否则 可能 找不到尾巴 			gotoxy(food);//定位到新的食物的位置 打印食物			putchar('@');			len++; //蛇长度增加			score += 10;//累加分数		}		else{//如果 没有吃到食物 把上一循环的 蛇尾 也就是last 位置 清空 (打印为空白)			gotoxy(last);			putchar(' ');		}		gotoxy(info_score);//定位到分数和等级 处 更新分数和等级		printf("\t\tscore: %d",score);		if(len >= 5){			grade++;			len -= 5;			delay -= 30;			gotoxy(info_grade);			printf("\t\tgrade: %d",grade);		}		Sleep(delay);// 这个 包含在windows.h  控制蛇的速度					}
五、判断游戏是否结束

int is_alive()	{		int eat_self = 0; //标记 是否自食		node *p;		p = head;		while(p->next != NULL){;//判断蛇头是否撞到自己			if(cor_cmp(head->cor, p->next->cor))				eat_self = 1;			p = p->next;		}				return (head->cor.X == L-1 || head->cor.X == 0|| head->cor.Y == W-1 ||				head->cor.Y == 0 || eat_self == 1) ? 0 : 1; 	}

六、其他(控制暂停的)

int is_key(int k)//判断是否是方向键 用于 判断是否是暂停	{		return (k == UP || k == DOWN || k == RIGHT || k == LEFT);	}			void free(node* head)// 释放 空间	{		node* p = head;		node* q;		while(p != NULL){			q = p->next;			free(p);			p = q;		}		}

完整实现 :

#include
#include
#include
#include
#include
#include
#define W 26#define L 61#define UP 72#define LEFT 75#define RIGHT 77#define DOWN 80#define SNAKE 1#define FOOD 2#define BAR 3#define MIDX L/2-4#define MIDY W/2-2 typedef struct Node{ COORD cor; struct Node* next;}node;int score = 0;int delay = 200;int len = 1;int grade = 1;node* head;COORD food;COORD mid = {MIDX, MIDY};COORD info_score = {L, W/3};COORD info_grade = {L, W/3+8};void gotoxy(COORD pt) { HANDLE hout; hout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hout, pt); } int cor_cmp(COORD pt1, COORD pt2) { return (pt1.X == pt2.X && pt1.Y == pt2.Y); } int in_border(COORD pt) { return (pt.X == L-1 || pt.X == 0 || pt.Y == 0 || pt.Y == W-1); } void init_pos() { srand((unsigned int)time(NULL)); do{ food.X = rand() % (L-20) + 10; food.Y = rand() % (W-5) + 5; head->cor.X = rand() % 60; head->cor.Y = rand() % 25; }while(cor_cmp(head->cor, food) || in_border(head->cor) || in_border(food)); }void init_game() { int i, j; head = (node *)malloc(sizeof(node)); head->next = NULL; init_pos(); for(i = 0; i < W; i++ ){ for(j = 0; j <= L; j++ ){ if(i == info_score.Y && j == info_score.X){ printf("\t\tscore: %d",score); } if(i == info_grade.Y && j == info_grade.X){ printf("\t\tgrade: %d",grade); } else if((i == 0 && j != L) || (i == W-1 && (j != L)) || j == 0 || j == L-1) putchar('#'); else if(i == food.Y && j == food.X) putchar('@'); else if(i == head->cor.Y && j == head->cor.X) putchar('$'); else putchar(' '); } putchar('\n'); } } int get_dir(int old_dir) { int new_dir = old_dir; if(kbhit() != 0){ getch(); new_dir = getch(); if(len > 1 && (abs(new_dir-old_dir) == 2 || abs(new_dir-old_dir) == 8)) new_dir = old_dir; } return new_dir; } COORD generate_food() { srand((unsigned int)time(NULL)); int in_snake = 0; node *p; COORD new_food; do{ new_food.X = rand() % 60; new_food.Y = rand() % 20; p = head; while(p != NULL){ if(cor_cmp(new_food, p->cor)) in_snake = 1; p = p->next; } }while(new_food.X == 0 || new_food.X == L-1 || new_food.Y == 0 || new_food.Y == W-1 || in_snake); return new_food; } void move_snake(int dir) { COORD last, current; last = head->cor; switch(dir){ case UP : head->cor.Y--; break; case DOWN : head->cor.Y++; break; case LEFT : head->cor.X--; break; case RIGHT : head->cor.X++; break; } node *p; int grow = 0; if(cor_cmp(food, head->cor)){ grow = 1; food = generate_food(); } p = head->next; while(p != NULL){ current = p->cor; p->cor = last; last = current; gotoxy(p->cor); putchar('*'); p = p->next; } gotoxy(head->cor); putchar('$'); if(grow){ for(p = head; p->next != NULL; p = p->next); p->next = (node *)malloc(sizeof(node)); p->next->cor = last; p->next->next = NULL;// 不要忘记 置为NULL 否则 可能 找不到尾巴 gotoxy(food); putchar('@'); len++; score += 10; } else{ gotoxy(last); putchar(' '); } gotoxy(info_score); printf("\t\tscore: %d",score); if(len >= 5){ grade++; len -= 5; delay -= 30; gotoxy(info_grade); printf("\t\tgrade: %d",grade); } Sleep(delay); } int is_alive() { int eat_self = 0; node *p; p = head; while(p->next != NULL){ if(cor_cmp(head->cor, p->next->cor)) eat_self = 1; p = p->next; } return (head->cor.X == L-1 || head->cor.X == 0|| head->cor.Y == W-1 || head->cor.Y == 0 || eat_self == 1) ? 0 : 1; } int is_key(int k) { return (k == UP || k == DOWN || k == RIGHT || k == LEFT); } void free(node* head) { node* p = head; node* q; while(p != NULL){ q = p->next; free(p); p = q; } } int main() { int dir = UP; int old_dir =UP; init_game(); while(1){ if(is_key(dir)) old_dir = dir; dir = get_dir(dir); while(!is_key(dir)){ dir = get_dir(old_dir); } move_snake(dir); if(!is_alive()){ break; } } gotoxy(mid); printf("Game Over!"); getchar(); free(head); return 0; }

总之 、这是 一个 非常简易的 贪吃蛇 游戏 ,主要是练习指针 和 结构体的使用。 

你可能感兴趣的文章
usb-otg-调试心得
查看>>
USB规范浏览--设备和主机规范
查看>>
男人的品位--我们自己的最求
查看>>
Android (Linux) Suspend流程
查看>>
LINUX时间管理
查看>>
定时器的使用
查看>>
为Android加入busybox工具
查看>>
使用技巧busybox
查看>>
如何查看与/dev/input目录下的event对应的设备
查看>>
bootloader-bootable解析
查看>>
bootloader (LK)&&android lk bootloader中相关修改指南
查看>>
SD卡驱动分析--基于高通平台
查看>>
SD Card 驱动流程分析
查看>>
Linux之debugfs介绍
查看>>
关于sd卡中一些概念的理解
查看>>
sd卡驱动分析之相关硬件操作和总结
查看>>
好的播文
查看>>
linux dd命令解析
查看>>
linux find命令详解
查看>>
S3C2440上touchscreen触摸屏驱动
查看>>