【无标题】基于ncurses库简单设计贪吃蛇游戏

1、全部代码(代码相应功能详见注释)

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

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

struct Snake
{
        int i;
        int j;
        struct Snake *next;
};

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

struct Snake food;

void initFood()
{
        int x;
        int y;
        x = rand()%20;  //rand()可随机取大于等于0的自然数,注意取余操作可使得x、y均满足(0<=x,y<=20)将食物“#”限制在游戏边界以内
        y = rand()%20;

        food.i = x;
        if (y != 0){  //当food的列等于0时,测试代码时发现界面没有打印“#”
                food.j = y;
        }
}

int eatFood(int i, int j)
{
        if (food.i == i && food.j == j){
                return 1;
        }

        return 0;
}

void addSnakeNode()
{
        struct Snake *new = (struct Snake *)malloc(sizeof(struct Snake));

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

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

void deleteSnakeNode()
{
        struct Snake *p = head;

        head = head->next;

        free(p);
}

void initSnakeNode()
{
        struct Snake *p = head;
        while(head != NULL){ //这里不能直接free(head)因为后面还会再此使用head结构体指针
                p = head;
                head = head->next;
                free(p);
        }

        dir = RIGHT;

        initFood();  
        head = (struct Snake *)malloc(sizeof(struct Snake));

        head->i = 2;
        head->j = 2;
        head->next = NULL;

        tail = head;

        addSnakeNode();
        addSnakeNode();
        addSnakeNode();
}

void initNcurse()
{
        initscr();  //ncurses界面初始化函数
        keypad(stdscr, 1);  //ncurses库自带的keypad函数,允许用户终端的键盘,允许getch()函数获取功能键
        noecho();  //不回显用户输入的内容
}

int printSnakeNode(int i, int j)
{
        struct Snake *p = head;
        while(p != NULL){
                if (p->i == i && p->j == j){
                        return 1;
                }

                p = p->next;
        }

        return 0;
}

void gamePic() //设计游戏边界
{
        int i;
        int j;

        move(0, 0); //move( int begin_x, int begin_y)//移动光标,基于标准屏幕stdscr(将移动后的界面覆盖掉先前的界面)

        for(i = 0; i < 20; i++){
                if (i == 0){
                        for(j = 0; j < 20; j++){
                                printw("--");
                        }
                        printw("\n");
                }

                if (i >= 0 && i <= 19){
                        for(j = 0; j <= 20; j++){
                                if (j == 0 || j == 20){
                                        printw("|");
                                }
                                else if (printSnakeNode(i, j) == 1){
                                        printw("[]");
                                }
                                else if (eatFood(i, j) == 1){
                                        printw("##");
                                }
                                else {
                                        printw("  ");
                                }
                        }
                        printw("\n");
                }
                if (i == 19){
                        for(j = 0; j < 20; j++){
                                printw("--");
                        }
                        printw("\n");
                }
        }
        printw("Designed by: kk    key value: %d\n", key);
        printw("food.hang = %d, food.lie = %d\n", food.i, food.j);
}

int snakeDie()//两种情况:1、撞向边界死亡;2、自己撞自己死亡
{
        struct Snake *p = head;

        if (tail->i < 0 || tail->j == 0 || tail->i == 20 || tail->j == 20){  //撞向游戏边界死亡
                return 1;
        }

        while(p->next != NULL){
      //当p走到🐍的尾巴tail时,以下条件语句恒成立则会出现一直初始化snake,故应该是p->next!=NULL,避免尾巴与尾巴自身比较
                if (p->i == tail->i && p->j == tail->j){
                        return 1;  //撞向自己死亡
                }

                p = p->next;
        }

        return 0;
}

void moveSnakeNode()
{
        addSnakeNode();

        if (eatFood(tail->i, tail->j) == 1){ 
                initFood();  //当吃到食物“#”初始化“#”,即蛇只增节点不删除节点
        }
        else {
                deleteSnakeNode();  //其余情况就是蛇增加尾巴节点删除头节点
        }

        if (snakeDie() == 1){
                initSnakeNode();
        }
}

void *refreshSnakeView()  //刷新界面线程
{
        while(1){
                moveSnakeNode();
                gamePic();
                refresh();  //每次在屏幕绘制之后,需要调用refresh()刷新屏幕
                usleep(100000);
        }

}

void turnByAbs(int direction)  //以绝对值改变来控制🐍是否转向
{
        if (abs(dir) != abs(direction)){
                dir = direction;
        }
}

void *changeDir()  //🐍转向线程
{
        while(1){
                key = getch();
                switch(key){
                        case KEY_UP:
                                turnByAbs(UP);
                                break;
                        case KEY_DOWN:
                                turnByAbs(DOWN);
                                break;
                        case KEY_LEFT:
                                turnByAbs(LEFT);
                                break;
                        case KEY_RIGHT:
                                turnByAbs(RIGHT);
                                break;
                }
        }
}


int main(int argc, char *argv[])
{
        pthread_t t1;
        pthread_t t2;

        initNcurse();
        initSnakeNode();
        gamePic();
		
		//创建两个线程同时运行
        pthread_create(&t1, NULL, refreshSnakeView, NULL); 
        pthread_create(&t2, NULL, changeDir, NULL);

        while(1);//等待输入,避免主程序提前结束
        getch();  //接收键盘上的输入一个字符, 相当于getchar()
        endwin(); //ncurses自带库函数,避免终端界面错乱,结束ncurse屏幕绘画

        return 0;
}

2、代码测试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这样就可以实现贪吃蛇小游戏了(当然在调试代码过程中会出现各式各样的问题,不要放弃,把基础打好,一定可以找到问题所在的地方并解决好它)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值