Linux基于Ncurses的贪吃蛇小游戏

一、Ncurses库的引入

  1. Ncursers(new curses)是Linux/Uinx底下应用比较广泛的图像库,他提供了大量的API函数,可以让用户在终端里面绘制出简单的图形界面;

  1. 这里我们会调用几个API去不断刷新界面,获取键盘的上下左右键,打印出蛇、食物、以及边界;

二、Linux的线程的引入

  1. 这里我引入了Linux线程的机制,创建了两个线程;

  1. 线程1:不断地去刷新终端界面;

  1. 线程2:不断地去获取键盘值;

三、C语言链表的引入

  1. 这里我创建了一个单向链表去绘制出蛇身;

  1. 当蛇没碰到食物时,蛇的移动就是链表的节点的动态插入和删除;

  1. 当蛇碰到食物时,链表插入一个节点,而不进行节点删除,从而使链表的长度加一;

  1. 根据获取到的键盘方向键,确定链表头插入;

四、代码部分


//头文件
#include <curses.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

//函数声明
void initNcruse();    //189
void initSnake();    //165
void initFood();    //62
void gamePic();        //219
void moveSnake();        //153
void addNode();            //116
void deleNode();        //144
void turn(int direction);    //107
int hasSnakeNode(int i,int j);    //197
int hasFood(int i,int j);    //211
void* refreshJieMian();        //71
void* changeDir();        //84
void SnakeLen();

//蛇的节点结构体
typedef struct snake
{
    int hang;
    int lie;
    struct snake *next;
}snake;

//定义头蛇的头节点、尾节点,食物
snake *head = NULL;
snake *tail = NULL;
snake food;

//定义全局变量
int key;
int dir;
int len;

//宏定义
#define UP    1
#define DOWN  -1
#define LEFT  2
#define RIGHT -2

//主函数
int main()
{
    int con;
    pthread_t task_1;    //创建线程1
    pthread_t task_2;    //创建线程2

    initNcruse();    //初始化Ncurses界面
    initSnake();    //初始化蛇身
    gamePic();    //初始化地图

    pthread_create(&task_1,NULL,refreshJieMian,NULL);    //线程1,刷新界面
    pthread_create(&task_2,NULL,changeDir,NULL);        //线程2,改变方向键值

    while(1);    //主线程,防止退出
    return 0;
}

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

//线程1,刷新界面函数
void* refreshJieMian()
{
    while(1)
    {
        moveSnake();    
        gamePic();
        SnakeLen();
        refresh();
        usleep(200000);
    }

}

//线程2,改变方向键值函数
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;
        }
    }
}

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

//添加蛇的节点
void addNode()
{
    snake *new = (snake *)malloc(sizeof(snake));
    switch(dir)    //根据不同的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;
    }
    new->next = NULL;
    tail->next = new;
    tail = new;
}

//蛇节点的删除
void deleNode()
{
    snake *oldhead;
    oldhead = head;
    head = head->next;
    free(oldhead);
}

//获取蛇的长度
void SnakeLen()
{
    snake *plen;
    plen = head;
    while(plen->next != NULL)
    {
        len += 1;
        plen = plen->next;
    }
}

//判断蛇是否死亡
int ifSnakeDie()
{
    snake *p;
    p = head;

    if(tail->hang<0 || tail->lie==0 || tail->hang==20 || 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 moveSnake()
{
    addNode();
    if(hasFood(tail->hang,tail->lie))
        initFood();
    else
        deleNode();
    if(ifSnakeDie())
        initSnake();
}

//初始化蛇身
void initSnake()
{
    snake *p;
    dir = RIGHT;    //给dir一个初始值
    len = 5;
    while(head != NULL)
    {
        p = head;
               head = head->next;
        free(p);
    }
    initFood();
    head = (snake *)malloc(sizeof(snake));        //申请结构体内存
    head->hang = 1;
    head->lie = 1;
    head->next = NULL;
    tail = head;

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

//初始化Ncruses
void initNcruse()
{
    initscr();
    keypad(stdscr,1);
    noecho();
}

//获取蛇的节点
int hasSnakeNode(int i,int j)
{
    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 || hang ==20)
        {
            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(hasSnakeNode(hang,lie))
                    printw("[]");
                else if(hasFood(hang,lie))
                    printw("##");
                else
                    printw("  ");
            }
            printw("\n");
        }    
    }    
    printw("By erhuijiang\n");
    printw("%d\n",len);    
}

五、运行截图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二灰酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值