c语言综合练习——贪吃蛇小游戏

前提环境准备

  1. Linux开发环境(虚拟机)
  2. 安装NCurses库 

对C语言学习的阶段性总结 

使用:C语言的基本语法,链表,Linux基础,NCurses库等 

为什么要用到NCurses 

     NCurses是一个程序库,它提供了 API,可以允许程序员编写独立于终端的基于文本的用户界面。它是一个虚拟终端中的“类 GUI”应用软件工具箱。它还优化了屏幕刷新方法,以减少使用远程 shell 时遇到的延迟。(转载)

简单来说:这个贪吃蛇的项目要用到方向键的移动,要对操作的灵敏度和画面的刷新有一定的要求,如果用传统的scanf()来获取用户的输入,用户输入后还要回车才能完成,不利于游戏的运行,而且贪吃蛇的游戏页面时刻在扫描刷新,对页面刷新要求高,对键盘的输入反应要求也高

NCurses的安装就不介绍了,可以去自行搜索安装

NCurses的简单使用

#include <curses.h>

int main()
{
        int key;
        initscr(); //初始化Ncurses (必须有)
        keypad(stdscr,1);//Reject from stdscr ,1 (allow Reject) //允许接收特殊按键(如上下左右)
        while(1)//循环扫描按键按下情况
        {
           key=getch();
           switch(key)
        {
           case KEY_DOWN:
           printw("Down\n");//相当于<stdio.h>库中的printf()
           break;

           case KEY_UP:
           printw("Up\n");
           break;

           case KEY_LEFT:
           printw("Left\n");
           break;

           case KEY_RIGHT:
           printw("Right\n");
           break;
        }
          // printw("your input: %d\n",key);
        }

        endwin(); //一定要写,不写页面退出时可能会崩溃乱码

        return 0;
}
~        

 很多人会发现case 的参数是什么,可以打开curses头文件查看说明

 

里面用数字标识了键盘按下的结果,当然数字对我们使用很不友好,所以用宏定义创建好了,供我们使用

当然我们也要知道Ncurses怎么运行

 

运行结果 

 

前序准备 

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

#define Up    1
#define Down  -1
#define Left  2
#define Right -2
int cmd;
int dir;
void initNncurse()
{
        initscr();
        keypad(stdscr,1);
        noecho();
}

struct Snake{
        int hang;
        int lie;
        struct Snake *next;
};

struct Snake *head=NULL;
struct Snake *tail=NULL;
struct Snake food;

 

简单的知道怎么使用,我们可以开始贪吃蛇游戏的制作

贪吃蛇游戏界面

//检查是否有界面
int hasSnakeNode(int i,int j)
{
        struct Snake *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 initPic() //初始化地图 20*20
{
        int Row;
        int Column;
        move(0,0);
        for(Row=0;Row<20;Row++)
        {
                if(Row==0)
                {
                    for(Column=0;Column<20;Column++)
                        {
                          printw("--");
                        }
                        printw("\n");
                }//0 Row  
                if(Row>=0 &&Row<=19)
                {
                   for(Column=0;Column<=20;Column++)
                      {
                        if(Column==0 ||Column==20)
                          {
                            printw("|");
                          }
                        else if(hasSnakeNode(Row,Column))
                                {
                                  printw("[]");
                                }
                        else if(hasFood(Row,Column))
                                {
                                  printw("$$");
                                }
                        else
                          {
                            printw("  ");
                          }
                      }
                    printw("\n");
                     }
                if(Row==19)
                {
                   for(Column=0;Column<20;Column++)
                      {
                        printw("--");
                      }
                        printw("\nAuthor: Xwd\n");
                }
        }
}

 贪吃蛇身体创建、食物创建

void initSnake()
{
        initFood();
        struct Snake *p;
        dir=Right;
        while(head!=NULL)
        {
            p=head;
            head=head->next;
            free(p);
        }
        head=(struct Snake *)malloc(sizeof(struct Snake));
        head->hang=1;
        head->lie=1;
        head->next=NULL;

        tail=head;
        addNode();
        addNode();
        addNode();
}

void initFood()
{
   int x=rand()%20; //在20*20格子中随机生成
   int y=rand()%20;
  food.hang=x;
   food.lie=y;
}

 贪吃蛇身体增加

void addNode()
{
        struct Snake *new=(struct Snake *)malloc(sizeof(struct Snake));
        new->next=NULL;
        switch(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;
        }
        tail->next=new;
        tail=new;
}

在蛇的移动中,如果没吃到食物相当于原来节点的不断删除创建

节点删除 

void deleteNode()
{
     struct Snake *p=head;
     head=head->next;
     free(p);
}

蛇的移动 

 

void moveSnake()
{
      addNode();
      if(hasFood(tail->hang,tail->lie))
        {
        initFood();
        }
        else
        {
      deleteNode();
        }
      if(isDie())
        {
            initSnake();
        }
}

蛇是否死亡(撞墙、吃自己)

int isDie()
{
    struct Snake *p=head;
    if(tail->lie==0 || tail->hang<0 ||tail->lie==20 ||tail->hang==20)
        {
                return 1;
        }
     while(p->next!=NULL)
        {
            if((p->hang==tail->hang) && (p->lie==tail->lie))
                {
                        return 1;
                }
            p=p->next;

        }
        return 0;
}

蛇的方向的改变 

void turn(int direction)//turn snake if Up and Down(Left and Right) putin no turn
{
        if(abs(direction)!=abs(dir))//绝对值判断蛇是否有方向上的变化
                            //例如在右移的时候按方向左是无效的
        {
                dir=direction;
        }
}

void *changeDir()
{
         while(1)
        {
           cmd=getch();
           switch(cmd)
        {
           case KEY_DOWN:
           turn(Down);
           break;

           case KEY_UP:
           turn(Up);
           break;

           case KEY_LEFT:
           turn(Left);
           break;

           case KEY_RIGHT:
           turn(Right);
           break;
        }
          // printw("your input: %d\n",key);
        }

}

时刻刷新页面 

void *refresheFace()
{
        while(1){
        moveSnake();
        initPic();
        refresh();
        usleep(100000);
         }
}

 

当然我们想要在贪吃蛇运行的同时,时刻扫描键盘方向有没有改变,还有程序要保持时刻运行,这里我们不得不用到线程的创建

int main()
{
        initNncurse();
        initSnake();
        initFood();
        initPic();
        pthread_t th1,th2;
        pthread_create(&th1,NULL,refresheFace,NULL);//线程1创建 刷新界面
        pthread_create(&th2,NULL,changeDir,NULL);//线程2创建 扫描方向键
        while(1);

        getch();
        endwin();
        return 0;
}
                                                                           

 

效果展示

 

 

                                                                                                                write date:202212172310

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值