C语言实现贪吃蛇小游戏

贪吃蛇

规则

  1. 初始蛇身长为4,向右移动,每吃到一次食物身长加1
  2. 键盘上下左右键控制移动方向
  3. 碰到墙壁、障碍物或者吃到自身时死亡,游戏结束

 

#include <curses.h>
#include <stdlib.h>

#define UP    1
#define DOWN  -1
#define LEFT  2
#define RIGHT -2

struct Snake { //蛇身一段的坐标信息
	int hang;
	int lie;
	struct Snake *next;
};

int key;          
int dir;
struct Snake *head = NULL;//蛇头
struct Snake *tail = NULL;//蛇尾

struct Snake food;  //食物

void initfood() {//初始化食物坐标
	int x = rand() % 20;
	int y = rand() % 20;//地图长宽为20

	food.hang = x;
	food.lie = y;
}

void initNcurse() {
	initscr();
	keypad(stdscr,1);
	noecho();
}

int hasNode(int i,int j) {
	struct Snake *p;
	p = head;
	while (p != NULL) {
		if (p->hang == i && p->lie == j)
			return 1;
		p = p->next;
	}
	return 0;
}//判断该坐标是否存在蛇身体

int hasfood(int i,int j) {
	if (food.hang == i && food.lie == j){
		return 1;
	}
	return 0;
}//判断该坐标是否存在食物

void gamePic() {//扫描全图,初始化并且判断地图,食物和蛇身体
	int hang;
	int lie;
	move(0,0);
	for (hang = 0 ; hang <= 20 ; hang++) {
		if (hang == 0) {
			for (lie = 0 ; lie < 20 ; lie++){
				printw("--");  
			}
			printw("\n");
		}
		if (hang >= 0 && hang <= 19) {
			for (lie = 0 ; lie <= 20 ; lie++) {
				if (lie == 0 || lie == 20) {
					printw("|");
				}
				else if (hasNode(hang,lie)) {
					printw("[]");         
				}
				else if(hasfood(hang,lie)) {
					printw("##");
				}
				else {
					printw("  ");
				}
			}
		 	printw("\n");
		}
		if (hang == 20) {
			for (lie = 0 ; lie < 20 ; lie++){
				printw("--");  
			}
			printw("\n");
		}
	}
	printw("By xiaozhang,food.hang=%d,food.lie=%d\n",food.hang,food.lie);
}

void addsnake() {
	struct Snake *new;
	new = (struct Snake*)malloc(sizeof(struct Snake));
	new->next = NULL;

	switch (dir) {//蛇的运动方向
		case UP:
			new->hang = tail->hang-1;	
			new->lie = tail->lie;
			break;	
		case DOWN:
			new->hang = tail->hang+1;
			new->lie = tail->lie;
			break;	
		case LEFT:		
			new->hang = tail->hang;
			new->lie = tail->lie-1;
			break;	
		case RIGHT:
			new->hang = tail->hang;
			new->lie = tail->lie+1;		
		break;
	}	

	tail->next = new;
	tail = new;//蛇尾部添加节点
}

void initsnake() {
	struct Snake *p;
	dir = RIGHT;//蛇的初始运动方向为向右
	while(head != NULL) {
		p = head;
		head = head->next;
		free(p);
	}	//清空内存中原有的蛇的信息
	
	initfood();//初始化食物
	head = (struct Snake*)malloc(sizeof(struct Snake)); 
	head->hang = 1;
	head->lie = 1;
	head->next = NULL;	//蛇头

	tail = head;//刚开始蛇头和蛇尾重合
	
	addsnake();
	addsnake();
	addsnake();//蛇尾添加新节点
}

void deleteNote() {//运动过程中,随着尾节点每运动一下,就删除一个原来的头节点
	struct Snake *p;
	p = head;
	head = head->next;
	free(p);
}

int ifsnakedie() {
	struct Snake *p;
	p = head;
	
	if(tail->lie==0 || tail->lie==20 || tail->hang < 0 || tail->hang ==20) {
		return 1;
	}//触碰边界返回1
	
	while (p->next != NULL) {
		if (tail->hang == p->hang && tail->lie == p->lie) {
			return 1;
		}//触碰身体返回1
		p = p->next;
	}
	return 0;
}

void movesnake() {
	addsnake();//移动时尾部添加新节点
	if (hasfood(tail->hang,tail->lie)) {
		initfood();//吃到食物添加新节点
	}else{
		deleteNote();//没吃到食物,移动一次删除一次头节点
	}
	
	if(ifsnakedie()) {
		initsnake();//无论碰到地图边界还是碰到自身,游戏重新开始
	}
}

void refreshjiemian() {
	while (1) {
		movesnake();
		gamePic();
		refresh();
		usleep(100000);			//每100ms刷新一次界面
	}	
}

void turn(int direction) {
	if (abs(dir) != abs(direction)) {
		dir = direction;
	}
}//在蛇的运动过程中,设置不会朝反方向运动

void changedir() {
	while (1) {
		key = getch();
		switch (key) {
			case KEY_UP:
				turn(UP);
				break;	
			case KEY_DOWN:
				turn(DOWN);
				break;	
			case KEY_LEFT:
				turn(LEFT);
				break;	
			case KEY_RIGHT:
				turn(RIGHT);
				break;	
		}	
	}
}

int main() {
	pthread_t t1;
	pthread_t t2;	

	initNcurse();
	
	initsnake();
		
	gamePic();

	pthread_create(&t1,NULL,refreshjiemian,NULL);
	pthread_create(&t2,NULL,changedir,NULL); //多线程操作,使得刷新界面和改变方向两个无限循环可以同时完成

	while (1);//防止游戏结束

	getch();	
	endwin();
	return 0;
}

运行方法

  1. 打开命令行窗口,输入 gcc snake.c -lcurses -lpthread 进行编译

  2. ./a.out运行
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值