C语言 基于Ncurse库的贪吃蛇游戏项目

为了敲键盘及时响应,需要用到ncurse

测试代码: ncurse1.c

/* ncurse1.c */
#include  //ncurse的头文件。

int main()
{
        char c;
        int i = 0;

		//ncurse界面的初始化函数。
        initscr(); 
        for(i=0;i<=2;i++)
        {
                c = getch();
                printw("\n");
                //ncurse下的打印函数。
                printw("Input: %c\n",c); 
        }
        //等待用户的输入,没有该函数程序会直接退出,看不到printw()的结果。
        getch(); 
        //调用程序退出函数,恢复shell终端的显示,没有该函数终端可能会乱码。 
        endwin(); 
        return 0;
}
//输入指令测试 gcc ncurse1.c -lcurses

C语言 基于Ncurse库的贪吃蛇游戏项目_第1张图片

 游戏的规划实现步骤

  1. Ncurse 函数初始化
  2. 边框图像设置 (for循环)
  3. 贪吃蛇身子节点    (结构体:行,列,下一个节点)
  4. 第一个节点  (静态设置)
  5. 设的整的身子  (静态设置)
  6. 改进 4,5蛇身子的问题, (采用结构体指针指向下一个,尾插法的方式)
  7. 蛇身子向右移动 move(0,0)光标界面不乱,通过按键key来向右行驶, 尾部加节点,注意必须要释放头节点来达到平衡。
  8. 贪吃蛇撞壁  
  9. 主动向右行驶,不需要按键key ,边框图像然后refresh()刷新界面。
  10. 方向键控制蛇变化 , key按键与dir配合,如果key向下,dir就变化,并switch选择增加往那个方向加节点。
  11. 主函数采用linux两个线程,(按键与自动)同时移动,并且都不退出。
  12. 贪吃蛇随机位置的设定。
  13. 咬死自己。

代码:

#include 
#include 
 
#define UP     1
#define DOWN  -1
#define LEFT   2
#define RIGHT -2
 
struct Snake
{
	int row;
	int line;
	struct Snake* next;
};
 
struct Snake* head = NULL;
struct Snake* tail = NULL;
int key;
int dir;
 
struct Snake food;
 
void initFood()//初始化食物节点
{
	int x = rand() % 20;//随机出现位置
	int y = rand() % 20;
	food.row = x;
	food.line = y;
}
 
void initNcurse()//初始化curses图形库
{
	initscr();
	keypad(stdscr,1);//使用keypad可以在stdscr中接受键盘的功能键
	noecho();//对于输出的功能键的值不做出回应,以免界面溢出
}
 
int hasSnakeNode(int i,int j)//传参:行号,列号
{
	struct Snake* p;
	p = head;
	while(p != NULL){
		if(p->row==i && p->line==j){
			return 1;//gamePic中打印一个节点"[]"
		}
		p=p->next;
	}
	return 0;
}
 
int hasFood(int i,int j)//打印食物
{
    if(food.row==i && food.line==j){
        return 1;
    }
    return 0;
}
 
void gamePic()//打印图形界面
{
	int row;
	int line;
	move(0,0);
	for(row=0;row<20;row++){
		//第0行为20个"--"
		if(row==0){
			for(line=0;line<20;line++){
				printw("--");
			}
			printw("\n");
		}
		//第0-19行为左右两边一个"|",中间21个"  "(空格)为了对齐第一行
		if(row>=0 && row<=19){//一共打印20行
			for(line=0;line<=20;line++){
				if(line==0 || line==20){
                    printw("|");//打印两边
                }else if(hasSnakeNode(row,line)){
					printw("[]");//打印蛇的身体
				}else if(hasFood(row,line)){
					printw("##");//打印食物
				}
				else{
                    printw("  ");//打印中间
                }
            }
            printw("\n");
		}
		//打印第19行,与第一行一样
		if(row==19){
            for(line=0;line<20;line++){
                printw("--");
            }
            printw("\n");
			printw("by Andy,key = %d\n",key);//打印作者名字以及方向键的值
        }
	}
}
 
void addNode()//加节点
{
	struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新节点空间
	new->next = NULL;
	switch(dir){//根据用户按的功能键的方向来决定如何添加一个节点
		case UP://列不变,行减一的位置添加
			new->row = tail->row - 1;
		    new->line = tail->line;
			break;
		case DOWN:
            new->row = tail->row + 1;
            new->line = tail->line;
            break;
		case LEFT:
            new->row = tail->row;
            new->line = tail->line - 1;
            break;
		case RIGHT:
            new->row = tail->row;
            new->line = tail->line + 1;
            break;
	}
	tail->next = new;
	tail = new;//新节点变成尾部
}
 
void deleteNode()//删除节点
{
	struct Snake* p;
	p = head;
	head = head->next;
	free(p);
}
 
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->row = 1;//第一行
	head->line = 1;//第一列
	head->next = NULL;//防止野指针
	tail = head;//头插法
	addNode();//加4个节点
	addNode();
	addNode();
	addNode();
}
 
int ifSnakeDie()//蛇死亡的条件
{
	struct Snake* p;
	p = head;
	if(tail->row < 0 || tail->line == 0 || tail->row == 20 || tail->line == 20){//四个边界
        return 1;
    }
	while(p->next != NULL){
		if(p->row == tail->row && p->line == tail->line){//头咬到尾巴
			return 1;
		}
		p = p->next;
	}
	return 0;
}
 
void moveSnake()//蛇的移动
{
	addNode();
	if(hasFood(tail->row,tail->line)){
		initFood();
	}
	else{
		deleteNode();
	}
	if(ifSnakeDie()){
		initSnake();
	}
}
 
void* refreshBox()//刷新界面
{
	while(1){
        moveSnake();//蛇移动
        gamePic();//重新打印界面
        refresh();//刷新覆盖原界面
        usleep(100000);//0.1s
    }
}
 
void turn(int direction)//绝对值解决方向问题
{
	if(abs(dir) != abs(direction)){
		dir = direction;
	}
}
 
void* changeDir()//根据用户按的功能键走位
{
	while(1){
        key = getch();
        switch(key){
            case KEY_DOWN:
                turn(DOWN);//转向
                break;
            case KEY_UP:
                turn(UP);
                break;
            case KEY_LEFT:
                turn(LEFT);
                break;
            case KEY_RIGHT:
                turn(RIGHT);
                break;
        }
    }
}
 
int main()
{
	initNcurse();//第一步:搭建curses环境
	initSnake();//第三步:打印蛇的身体
	gamePic();//第二步:打印图形界面
	pthread_t th1;//线程1
	pthread_t th2;//线程2
	pthread_create(&th1,NULL,refreshBox,NULL);//运行线程1:不断刷新界面
	pthread_create(&th2,NULL,changeDir,NULL);//运行线程2:不断改变方向
	while(1);//让线程一直进行
	getch();//让程序一直重复输入功能键还能执行
	endwin();//curses函数
	return 0;
}

还需要不断改进。。。。。。

你可能感兴趣的:(linux,c语言)