Linux编程 --- 贪吃蛇小游戏

如何使用ncurse

#include <curses.h>

int main()
{
        initscr();//ncurse 界面的初始化函数
        printw("This is curses window\n");//在ncurse模式下的printf
        getch();//等待用户输入,如果没有这句话,程序就退出了,看不到运行的结果,也就是看不到上面那句话
        endwin();//程序退出,调用改函数来恢复shell终端的显示,如果没有这句话,shell终端字乱码,坏掉
        return 0;
}

编译curses文件

gcc xxx.c -lcurses

ncurse的上下左右键
vi /usr/include/curses.h 可查看ncurse的宏定义

#define KEY_DOWN	0402
#define KEY_UP		0403
#define KEY_LEFT	0404
#define KEY_RIGHT	0405

验证代码

#include <curses.h>

int main()
{
        int key;

        initscr();
        keypad(stdscr,1);//设置了可以在stdscr中接受键盘的功能键(快捷键),1代表“是”
        while(1){
                key = getch();
                switch(key){
                        case KEY_DOWN:
                                printw("DOWN\n");
                                break;
                        case KEY_UP:
                                printw("UP\n");
                                break;
                        case KEY_LEFT:
                                printw("LEFT\n");
                                break;
                        case KEY_RIGHT:
                                printw("RIGHT\n");
                                break;

                }
        }

        endwin();
        return 0;
}

贪吃蛇小游戏参考代码

此贪吃蛇小游戏的链表插入方式采用的是尾插法,*head 是贪吃蛇的头节点,也是贪吃蛇的尾巴。

#include <ncurses.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 hang;
        int lie;
        struct Snake *next;
};

struct Snake *head = NULL;//贪吃蛇的尾巴
struct Snake *tail = NULL;//贪吃蛇的头
struct Snake food;//贪吃蛇的食物
int key;
int dir;

void initNurses()
{
        initscr();//ncurse 界面的初始化函数
        keypad(stdscr,1);//设置了可以在stdscr中接受键盘的功能键(快捷键),1代表“是”
}

void initfood()
{
        int x = rand()%19+1;//产生1~20的随机数
        int y = rand()%20+1;//产生1~21的随机数

        food.hang = x;
        food.lie = y;
}

int hasfood(int i, int j)
{
        if(food.hang == i && food.lie == j){
                return 1;
        }
        return 0;
}

int hasSnakeNode(int hang,int lie)
{
        struct Snake *p;
        p = head;
        while(p != NULL){
                if(p->hang==hang && p->lie == lie){
                        return 1;
                }
                p = p->next;//遍历贪吃蛇链表
        }
                return 0;
}

void gamePic()
{
        int hang;//定义地图位置行
        int lie;//定义地图位置列
        move(0,0);//当按下方向键时,让贪吃蛇往所按的方向键一直行走
        for(hang=0; hang<=21; hang++){
                for(lie=0; lie<=22; lie++){
                        if(hang==0 || hang==21){//地图第一行和最后一行为“--”墙
                                if(lie==0){
                                        printw(" -");
                                }else if(lie==22){
                                        printw("- ");
                                }else{
                                        printw("--");
                                }
                        }else if(lie==0){//地图第一列和最后一列为“|”墙
                                printw(" |");
                        }else if(lie==22){
                                printw("| ");
                        }else if(hasSnakeNode(hang,lie)){//打印贪吃蛇初始位置
                                printw("[]");
                        }else if(hasfood(hang,lie)){//打印贪吃蛇食物初始位置
                                printw("##");
                        }else{
                                printw("  ");
                        }
                }
                printw("\n");
        }
}

void addNode()//通过尾插法增加链表节点
{
        struct Snake *new = (struct Snake*)malloc(sizeof(struct Snake));

        new->lie = tail->lie+1;
        new->next = NULL;
        switch(dir){
                case UP: //向上移动
                        new->hang = tail->hang-1;
                        new->lie = tail->lie;
                        break;

                case RIGHT: //向右移动
                        new->hang = tail->hang;
                        new->lie = tail->lie+1;
                        break;
                case LEFT: //向左移动
                        new->hang = tail->hang;
                        new->lie = tail->lie-1;
                        break;
                case DOWN: //向下移动
                        new->hang = tail->hang+1;
                        new->lie = tail->lie;
                        break;
        }

        tail->next = new;
        tail = new;//让新的节点成为链表尾节点
}

void deleNode()
{
        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->hang = 1;
        head->lie = 1;//贪吃蛇尾巴的初始位置
        head->next = NULL;

        tail = head;
        addNode();
        addNode();
        addNode();//初始化后的贪吃蛇有4个节点
}
int ifSnakeDie()//贪吃蛇撞死
{
        struct Snake *p;
        p = head;

        if(tail->hang == 0 || tail->lie == 0 || tail->hang == 21 || tail->lie == 22){
                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* refreshJieMian()
{

        while(1){
                        usleep(150000);//时延要放在while的首行,不然游戏地图容易出现乱码,可调节贪吃蛇行走速度
                        moveSnake();//贪吃蛇行走函数定义
                        gamePic();//地图界面不断刷新
                        refresh();//刷新的界面在同一个位置出现
        }
}

void turn(int diretion)
{//贪吃蛇在往一个方向移动时,无法通过一次按键让它反向移动。例如贪吃蛇在往左方向移动时,无法通过一次按键向右移动。
        if(abs(diretion) != abs(dir)){
                dir = diretion;
        }
}

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()
{
        pthread_t t1;
        pthread_t t2;
        initNurses();//Nurses初始化

        initSnake();//贪吃蛇初始化
        gamePic();//贪吃蛇地图初始化
        pthread_create(&t1, NULL, refreshJieMian, NULL);//创建线程1,让界面不断刷新
        pthread_create(&t2, NULL, changeDir, NULL);//创建线程线程2,让贪吃蛇接受按键可以转向

        while(1);//让进程不退出
        endwin();
        return 0;
}

演示视频

7.46 Vlc:/ 终于把程序写完了,玩贪吃蛇吗? https://v.douyin.com/NkWJmoD/ 复制此链接,打开Dou音搜索,直接观看视频!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

从入门到捕蛇者说

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

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

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

打赏作者

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

抵扣说明:

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

余额充值