基于C语言链表+ncurses库 实现贪吃蛇小游戏

一、前言

学习c语言一段时间后,利用c语言链表和ncurses库实现贪吃蛇游戏项目。项目涉及到ncurses库的基本使用、c语言指针、链表的基本知识以及linux多线程的基本使用。

二、项目展示

  • a、贪吃蛇撞墙死亡,游戏重启
  • b、贪吃蛇撞到自己死亡,游戏重启
  • c、正常游戏,下方记录分数以及下一个food的位置坐标
    在这里插入图片描述

三、项目流程

在这里插入图片描述

四、代码结构

在这里插入图片描述
为了在更新游戏界面的同时能够让程序对键盘的输入能够进行反应,使用linux中的多线程实现两个任务的尽可能的同时进行:

int main()
{
        pthread_t th1;
        pthread_t th2;

        initScr();

        initSnake();

        gamPic();
        //多线程
        pthread_create(&th1,NULL,changeDirction,NULL);
        pthread_create(&th2,NULL,refreshjiemian,NULL);

       while(1);

        getch();
        endwin();

        return 0;
}

当然这里为了达到固定界面并且能够实时对键盘的操作做出回应,使用了ncurses库,创建窗口:

       initscr();
       keypad(stdscr,1);
       getch();
       endwin();

定义数据结构:

struct Snake //贪吃🐍结构体
{
        int hang;
        int lie;
        struct Snake *next;
};

//全局变量
struct Snake* head =NULL;//蛇头
struct Snake* tail =NULL;//蛇尾
struct Snake food;       //食物
int dir;                 //方向
int fen=0;               //分数

实物位置生成(rand()%19):

void initFood()//食物位置生成
{
        int x;
        int y;
 while(1){
        x=rand()%19;

        y=rand()%19;


        if (x!=0 && y !=0)
        {
         break;
        }
 }
        food.hang=x;
        food.lie =y;
        food.next=NULL;
        printw("Next Food is: x:%d y:%d\n",food.hang,food.lie);
}

根据键盘的方向输入对贪吃蛇链表节点进行修改:

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;
}

需要注意的是,之前写到的防止内存泄露问题 使用malloc 开辟地址之后要及时对废弃的地址进行释放:

void initSnake()//蛇身的初始化
{
        initFood();//初始化食物
        dir=RIGHT; //默认方向
        struct Snake *p;
        while(head!=NULL){
                p=head;
                head=head->next;
                free(p);//释放废弃地址
        }

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

        addNode();
        addNode();
        addNode();
        addNode();
        addNode();
}

蛇身的移动:

  • 没吃食物时,移动为尾增节点、头减节点;
  • 吃食物后不删除头部节点即可

碰撞检测:

  • 撞墙
  • 撞自己
int ifSnakedie()//判断蛇是否撞到自己
{
    struct Snake *p;
    p=head;
    
    while(p->next!=NULL)
    {
          if (p->hang == tail->hang && p->lie == tail->lie)
          {
                 return 1;
          }
          p=p->next;
    }
    return 0;
}

void movesnake()//蛇身移动,没吃食物移动为尾增节点、头减节点;吃食物后不删除头部节点即可!
{
        addNode();
        if(hasFood(tail->hang,tail->lie)){
             initFood();
             fen=fen+1;
        }else{

        head=head->next;//删除节点
        }
                if((tail->hang==0||tail->lie==0||tail->hang==20||tail->lie==20) ||(ifSnakedie()) )//撞墙、撞自己检测
                {
                        initSnake();
                        fen=0;
                }

}

五、源码

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


#define UP    1
#define DOWN  2
#define LEFT  3
#define RIGHT 4

struct Snake //贪吃🐍结构体
{
	int hang;
	int lie;
	struct Snake *next;
};

//全局变量
struct Snake* head =NULL;//蛇头
struct Snake* tail =NULL;//蛇尾
struct Snake food;	 //食物
int dir;                 //方向
int fen=0;               //分数

void initFood()//食物位置生成
{
	int x;
	int y;
    while(1){	
        x=rand()%19;

        y=rand()%19;	
               

	if (x!=0 && y !=0)
	{
         break;	        
	}
      } //防止x=0或y=0            

	food.hang=x;
	food.lie =y;
	food.next=NULL;
	printw("Next Food is: x:%d y:%d\n",food.hang,food.lie);

}


void initScr()//初始化curse界面
{
	initscr();
	keypad(stdscr,1);
}


int hasSnakeNode(int i,int j)//检测链表节点
{
	struct Snake * point=head;
	while(point!=NULL)
	{
		if(point->hang==i && point->lie==j)
		{
			return 1;
		}
	  point=point->next;
	}//历遍链表判断当前位置是否为蛇身节点
	return 0;
}

int hasFood(int i,int j)//判断当前位置是否为食物位置
{
	if(food.hang==i && food.lie==j)
	{
		return 1;
	}

	return 0;
}

void gamPic()//初始化地图
{      
	int hang=0;
	int lie;
        move(0,0);
	while(hang<21){

		if(hang==0)
		{
			for(lie=0;lie<20;lie++)
			{
			 printw("--");
			}
		}else
		 {

			if(hang==20)
			{
				for(lie=0;lie<20;lie++)
				{
				 printw("--");
				}
			}else
			{
			
			for(lie=0;lie<21;lie++){
				if (lie==0||lie==20)
				{
                                   printw("|");
			        }else
			         {
			             if(hasSnakeNode(hang,lie))
					 {
						 printw("[]");
					 }else if(hasFood(hang,lie))
					 {
						 printw("##");
					 }
				     
				     else{
			         		  printw("  ");
					}
				 }	 

			 }
		        }
		}
			printw("\n");
                        hang++;
	        
	}
	
}



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 initSnake()//蛇身的初始化
{
        initFood();
        dir=RIGHT;
	struct Snake *p;
	while(head!=NULL){
	        p=head;
		head=head->next;
		free(p);
	}

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

	addNode();
	addNode();
	addNode();
	addNode();
	addNode();
}	

int ifSnakedie()//判断蛇是否撞到自己
{
    struct Snake *p;
    p=head;



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

	  p=p->next;
    }

    return 0;
}



void movesnake()//蛇身移动,没吃食物移动为尾增节点、头减节点;吃食物后不删除头部节点即可!
{
	addNode();
	if(hasFood(tail->hang,tail->lie)){
	     initFood();
	     fen=fen+1;
	}else{
	
	head=head->next;//删除节点
	}
		if((tail->hang==0||tail->lie==0||tail->hang==20||tail->lie==20) ||(ifSnakedie()) )//撞墙、撞自己检测
		{
			initSnake();
			fen=0;
		}

}


void* refreshjiemian()//刷新界面
{
	        while(1)
             {
                        movesnake();
                        gamPic();
                        refresh();
	        	printw("Game score is:%d \n",fen*10);
                        usleep(100000);

            }

}


void* changeDirction() //检测键入的方向
{

	int c;
	
	        while(1)
             {   c=getch();
                switch(c){

                case 0402:
			if (dir!=UP)
	         	{
			 dir=DOWN;
			}
                       // printw("DOWN\n");
                        break;

                case 0403:
	         	if(dir!=DOWN)
			{
			dir=UP;
			}
                       // printw("UP\n");
                        break;

                case 0404:
		       if(dir!=RIGHT)
		       {
			dir=LEFT;
			}
                       // printw("LEFT\n");
                        break;

                case 0405:
			if (dir!=LEFT)
			{
			dir=RIGHT;
			}
                       // printw("RIGTH\n");
                        break;
            }
	     }
}


int main()
{     
	pthread_t th1;
	pthread_t th2;

	initScr();

        initSnake();

	gamPic();
	//多线程
	pthread_create(&th1,NULL,changeDirction,NULL);
	pthread_create(&th2,NULL,refreshjiemian,NULL);
   
       while(1);
  
        getch();
	endwin();
   
	return 0;
}

git:https://github.com/Ryj233/My_Program

编译和运行:
ren@ren-virtual-machine:~$ gcc cures7.c -lcurses -lpthread
ren@ren-virtual-machine:~$ ./a.out

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值