LINUX下使用Ncurse来编写贪吃蛇小游戏

由于贪吃蛇小游戏需要对键盘快速响应的图形界面,所以选用Ncurses作为游戏的界面。其中使用到Ncurses,linux线程。
使用链表来显示贪吃蛇的身子和食物:
头文件和宏定义:

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

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

链表如下:

struct snake
{
	int hang;
	int lie;
	struct snake* next;

};

使用的全局变量:

struct snake food;    // 创建食物的节点

struct snake *head = NULL;     //贪吃蛇头结点和尾节点
struct snake *tail = NULL;
int dir;                  //贪吃蛇的转变方向
int key;                  //键盘响应变量

界面的初始化:

void initNcurses()
{
	initscr();            
	keypad(stdscr,1);         //Ncurses初始化的函数
	noecho();                 //为防止Ncurses出现乱码现象
}

食物初始化:

void initFood()
{                            //为了让食物能够随机出现采用rand函数,但是为防止食物位置超出规定界面采用取余的方式控制在界面内
	int x = rand()%20;
	int y = rand()%20;
	food.hang = x;
	food.lie = y;

}

蛇的身子初始化:

void initSnake()
{
	while(head != NULL){          //为防止蛇在行进过程中蛇尾节点开辟的空间出现内存泄漏
		struct snake *p = head;
		head = head->next;
		free(p);
	}

	initFood();          //初始化食物

	head = (struct snake *)malloc(sizeof(struct snake));
	head->hang = 2;           //规定蛇头结点位置
	head->lie = 2;
	head->next = NULL;
	tail = head;

	dir = RIGHT;           //给蛇初始行进方向
	addNode();             //增加结点使蛇更完整
	addNode();
	addNode();
}

增加蛇的节点

void addNode()
{
	struct snake *new = (struct snake*)malloc(sizeof(struct snake));

	switch(dir){                                 //由于蛇在行进的过程中会改变方向所以需要对其方向进行设定
		case UP:
			new->hang = tail->hang-1;  //蛇行进以蛇头结点增加,蛇尾节点删除的形式(注意:这里面head节点是蛇尾,tail是蛇头)
			new->lie = tail->lie;
			new->next = NULL;
			break;
		case DOWN:
			new->hang = tail->hang+1;
			new->lie = tail->lie;
			new->next = NULL;
			break;
		case LEFT:
			new->hang = tail->hang;
			new->lie = tail->lie-1;
			new->next = NULL;
			break;
		case RIGHT:
			new->hang = tail->hang;
			new->lie = tail->lie+1;
			new->next = NULL;
			break;
	}

	tail->next = new;
	tail = new;
}

删除蛇尾节点

void delNode()
{
	head = head->next;
}

蛇行进

void snakeMove()
{
	addNode();
	if(hasFood(tail->hang,tail->lie)){   //蛇每吃一个食物就会增加一个节点
		initFood();
	}else{
		delNode();
	}
       
       if(ifSnakeDie() == 1){          //蛇撞围墙或者自己会重新开始
                  initSnake();
         }
}

蛇撞墙和自己

int ifSnakeDie()
{
      struct snake *p = head;
      if(tail->hang < 0 || tail->hang == 20|| tail->lie ==0 || tail->lie == 20){ //撞上围墙
                return 1;
        }

       while(p->next !=NULL){       //通过遍历节点来判断是否撞到自己,注意tail节点需要从遍历里面删去,不然该函数一直return1
              if(p->hang == tail->hang && p->lie == tail->lie){
                     return 1;
              }
             p = p->next;
          }
        return 0;
}

图形中打印蛇身子的函数

int snakebody(int i,int j)
{
	struct snake *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;
	}else{
		return 0;
	}

}

打印图形界面

void gamePic()
{
	int hang;
	int lie;

	move(0,0);     //由于打印图形界面是光标会随着界面移动,所以使用move(0,0),使光标定位在开始位置

	for(hang=0;hang<=20;hang++){
		if(hang == 0 ){                   //打印第一行横线
			for(lie=0;lie<20;lie++){
				printw("--");        
			}
			printw("\n");
                       }
			for(lie=0;lie<=20;lie++){       //打印第一列和最后一列竖线
				if(lie==0 || lie==20){
					printw("|");
				}else if(snakebody(hang,lie) == 1){       //打印蛇身子
					printw("[]");    
				}else if(hasFood(hang,lie) == 1){        //打印食物
					printw("##");  
				}else{
					printw("  ");                        //打印空白
				}
			}
			printw("\n");                       
		
		if(hang ==20){                              //打印最后一排横线
			for(lie=0;lie<20;lie++){
				printw("--");
			}
		}
	}
	printw("\n");
	printw("by CaoHai\n  %d",key);          //打印作者和键盘信息调试
}

蛇转向函数

void turnDir(int direction)
{
	if(abs(dir) != abs(direction)){   //将上下作为一组,左右作为一组利用绝对值来防止蛇往相对的方向直接转向
		dir = direction;
	}

}

需要使用线程让其同时进行的函数:

void* changeDir()                     //转向
{
	while(1){
		key  = getch();              //等待键盘输入
		switch(key){
			case KEY_UP:
				turnDir(UP);
				break;
			case KEY_DOWN:
				turnDir(DOWN);
				break;
			case KEY_LEFT:
				turnDir(LEFT);
				break;
			case KEY_RIGHT:
				turnDir(RIGHT);
				break;

		}
	}
}

void* reFreshJieMian()               //保持界面刷新(只有不断刷新界面才能看到图形变化)
{
	while(1){
		snakeMove();                
		gamePic();
		refresh();                //刷新界面
		usleep(100000);           //速度设定
	}
}

主函数

int main()
{ 
	pthread_t t1;               //创建两个线程
	pthread_t t2;

	initNcurses();             //初始化Ncurses界面

	initSnake();               

	gamePic();

	pthread_create(&t1,NULL,reFreshJieMian,NULL);
	pthread_create(&t2,NULL,changeDir,NULL);

	while(1);

	getch();                     //防止程序退出
	endwin();                    //ncurses必要的程序末尾函数
	return 0;
}

完整代码:

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

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

struct snake
{
	int hang;
	int lie;
	struct snake* next;

};

struct snake food;

struct snake *head = NULL;
struct snake *tail = NULL;
int dir;
int key;

void initFood()
{
	int x = rand()%20;
	int y = rand()%20;
	food.hang = x;
	food.lie = y;

}

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



void addNode()
{
	struct snake *new = (struct snake*)malloc(sizeof(struct snake));

	switch(dir){
		case UP:
			new->hang = tail->hang-1;
			new->lie = tail->lie;
			new->next = NULL;
			break;
		case DOWN:
			new->hang = tail->hang+1;
			new->lie = tail->lie;
			new->next = NULL;
			break;
		case LEFT:
			new->hang = tail->hang;
			new->lie = tail->lie-1;
			new->next = NULL;
			break;
		case RIGHT:
			new->hang = tail->hang;
			new->lie = tail->lie+1;
			new->next = NULL;
			break;
	}

	tail->next = new;
	tail = new;
}

void delNode()
{
	head = head->next;
}

void initSnake()
{
	while(head != NULL){
		struct snake *p = head;
		head = head->next;
		free(p);
	}

	initFood();     

	head = (struct snake *)malloc(sizeof(struct snake));
	head->hang = 2;
	head->lie = 2;
	head->next = NULL;
	tail = head;

	dir = RIGHT;
	addNode();
	addNode();
	addNode();
}

int ifSnakeDie()
{
      struct snake *p = head;
      if(tail->hang < 0 || tail->hang == 20|| tail->lie ==0 || tail->lie == 20){
                return 1;
        }

       while(p->next !=NULL){
              if(p->hang == tail->hang && p->lie == tail->lie){
                     return 1;
              }
             p = p->next;
          }
        return 0;
}

void snakeMove()
{
	addNode();
	if(hasFood(tail->hang,tail->lie)){
		initFood();
	}else{
		delNode();
	}
       
       if(ifSnakeDie() == 1){
                  initSnake();
         }
}

int snakebody(int i,int j)
{
	struct snake *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;
	}else{
		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");
                       }
			for(lie=0;lie<=20;lie++){
				if(lie==0 || lie==20){
					printw("|");
				}else if(snakebody(hang,lie) == 1){
					printw("[]");
				}else if(hasFood(hang,lie) == 1){
					printw("##");  
				}else{
					printw("  ");
				}
			}
			printw("\n");                       
		
		if(hang ==20){
			for(lie=0;lie<20;lie++){
				printw("--");
			}
		}
	}
	printw("\n");
	printw("by CaoHai\n  %d",key);
}

void turnDir(int direction)
{
	if(abs(dir) != abs(direction)){
		dir = direction;
	}

}

void* changeDir()
{
	while(1){
		key  = getch();
		switch(key){
			case KEY_UP:
				turnDir(UP);
				break;
			case KEY_DOWN:
				turnDir(DOWN);
				break;
			case KEY_LEFT:
				turnDir(LEFT);
				break;
			case KEY_RIGHT:
				turnDir(RIGHT);
				break;

		}
	}
}

void* reFreshJieMian()
{
	while(1){
		snakeMove();
		gamePic();
		refresh();
		usleep(100000);
	}
}


int main()
{ 
	pthread_t t1;
	pthread_t t2;

	initNcurses();

	initSnake();

	gamePic();

	pthread_create(&t1,NULL,reFreshJieMian,NULL);
	pthread_create(&t2,NULL,changeDir,NULL);

	while(1);

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

注意:程序在linux下进行编译的时候需要加上ncurses 和pthread库:
gcc snake.c -lcurses -lpthread -o snake

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值