基于C+ncurses 实现的贪吃蛇

C语言中的图形用户界面开发:使用库如GTK+或ncurses创建GUI应用程序(一) C语言开发者可以充分利用GTK+的强大功能,开发出界面美观、功能丰富、具有良好用户体验的跨平台GUI应用程序。 阅读详情

游戏说明:


linux 环境下的,基于Ncursse 图形图的C语言小游戏

基础要求:


C语言基础
Linux 基本操作:  
如何编写代码 如何编译代码  如何运行程序  如何创建文件夹


为什么需要应用ncurse 库:


C语言的键盘输入 函数  没法满足实时性 -- scanf gets getchar -- 都需要 回车确认

curse 输入和输出:


键盘响应快 
#include<curses.h>
initscr();
printw("This is a curse window.\n");  // ncurse 模式的printf
getch();  //等待用户输入 ,if 没这句话程序会自动退出,看不到运行结果
endwin(); //程序退出-- 调用函数来恢复shell终端的显示,没有这句话,shell终端就会乱码

nurse 的上下左右 键:
#define  KEY_DOWN 0402
#define KEY_UP  0403
#define KEY_LEFT 0404
#define KEY_RIGHT 0405

上面四个键是功能键 -- 使用的时候需要我们 引入 keypad函数

keypad(stdscr,1);


#include <curses.h>

int main()
{
    int key;
    initscr();
    keypad(stdscr, 1);
    while (1)
    {
      key = getch();
      switch (key)
      {
     // case 0402:
      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;
}


======================================

贪吃蛇地图:


20 * 20 的格子 :
地图上界"--"
地图左界"|"
苹果(食物)"##"
蛇身 "[][][[]"

void myPrintMap()
{
  int line, row;

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

    if (line >= 0 && line < 20)
    {
      for (row = 0; row <= 20; row++)
      {
        if (row == 0)
          printw("|");
        else if (row == 20)
          printw("|\n");
        else
          printw("  ");
      }
      if (line == 19)
      {
        for (row = 0; row < 20; row++)
        {
          if (row == 19)
            printw("--\nby mxjun");
          else
            printw("--");
        }
      }
    }
  }
}

=========================================


贪吃蛇身子 节点 -- 结构体--使用链表实现

//扫描匹配到贪吃蛇的身体节点 --行列都匹配 
不打空格 ,打出蛇身子
-- printw("[]") --显示出来

//判断是否需要显示蛇的身子 
int haveSnack(int line,int row)
{
struct snack * p=&s1;

 while(p!=NULL)
 {
  if(p->line==line && p->row==row)
   return 1;
  p=p->next;
 }
return 0;

}

=======================================


链表添加蛇的节点:


void addSnack()
{
 //尾插法实现
 struct Snack *new = (struct Snack*)malloc(sizeof(struct Snack));
 new->line=tail->line; 
 new->row=tail->row+1;
 new->next=NULL; //作为新的尾巴
 tail->next=new;
 tail=new;
}

void initSnack()
{
head = (struct Snack*)malloc(sizeof(struct Snack));
head->line=2;
head->row=2;
head->next=NULL;
tail=head;

addSnack();
addSnack();
addSnack();

}

=========================================


实现贪吃蛇的向右移动:

1.右移:
原理 删除第一个, 在最右边一个节点就没添加一个

void delSnack()
{
 struct Snack* new;
 new=head;
 head=head->next;
 free(new);
}

void moveRight()
{
 addSnack();
 delSnack();

}

===============================


贪吃蛇撞墙 ;

void initSnack()
{
struct Snack*new=NULL;
while(head!=NULL)
 {
  new=head;
 head=head->next;
free(new);

 }


head = (struct Snack*)malloc(sizeof(struct Snack));
head->line=2;
head->row=2;
head->next=NULL;
tail=head;

addSnack();
addSnack();
addSnack();

}


void moveRight()
{
 addSnack();
 delSnack();
  //判断是否撞到墙
 if(tail->row==0 || tail->row==20)
   {
   initSnack();

   }

}

usleep () -- 休眠
refresh()  -- 刷新

========================


贪吃蛇的自行游走

 -- while -- 一直执行, move函数 usleep() -- 控制时间

 warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]
  156 |        usleep(100000);
// 这种警报 可以直接man usleep 查看他的头文件

===============================

方向变化 -- 多线程


引入 -- .界面一边在刷新,我们也要求一边能接收我们的按键  -- 多线程 --让两个while 同时进行


怎么实现多线程:


Linux 线程:

创建线程的代码:
#include<pthread.h>
ret = pthread_create(&th,NULL,thread,&arg ); // thread --可以是函数 -- 我们要执行的


#include<stdio.h>
#include<pthread.h>

void* func1()
{
 while(1)
  {
  puts("func1 is running");
  sleep(1);
  }

}

void* func2()
{
 while(1)
  {
  puts("func2 is running");
  sleep(1);
  }

}

int main()
{
 pthread_t th1;
 pthread_t th2;


 pthread_create(&th1,NULL,func1,NULL);
 pthread_create(&th2,NULL,func2,NULL);


 while(1);

}


===================================


蛇的转弯


定义全局 的方向变量dir 
在键入 方向键的时候进行修改 -- 然后在moveSncak()的addSnack() 的时候 方向 被改变


===================================

绝对值优化蛇的不合理走位;

abs 函数 -- 去绝对值

initNcurses() -- noecho -- 不要把无关信息显示在界面上

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

oid turn(int newDir)
{
 if(abs(newDir)!=abs(dir))
   dir=newDir;

}

void *inputKey()
{

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

=====================================


苹果 -- 食物

食物可以使用之前的snack 结构体里面的坐标表示

static -- 静态变量 -- 函数被再次调用打的时候他的值不会发生变化

rand()  --实现食物随机生成: % 20 -- 限制范围

==================================


蛇能吃自己 -- 链表尾巴 和 身体的重合

//这里我们再明确一点 ,由于我们使用的是尾插法,so我们得到的链表尾巴就是蛇头

代码整体实现

#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 Snack //定义蛇类
{
  int line;
  int row;

  struct Snack *next; //链表实现贪吃蛇变长
};
// 定义蛇头,蛇尾
struct Snack *head = NULL;
struct Snack *tail = NULL;
struct Snack food; //定义食物类
int key;
int dir; //记录方向

void initNcurse() //对Ncurse初始化
{

  initscr();
  keypad(stdscr, 1);
  noecho(); //避免键入方向键的时候屏幕错乱,返回值
}

void initFood() //初始化食物
{
int x=rand()%20; //随机生成0-19的位置
int y=rand()%20;

food.line=x;
food.row=y;



}
int haveFood(int line, int row) //判断这个格子上是否存在食物
{
  if(food.line==line && food.row==row)
   return 1;

  return 0;
}


int haveSnack(int line, int row)//判断这个格子上是否存在蛇
{
  struct Snack *p = head;

  while (p != NULL)
  {
    if (p->line == line && p->row == row)
      return 1;
    p = p->next;
  }
  return 0;
}

void addSnack() //增加蛇的长度
{
  // 尾插法实现
  struct Snack *new = (struct Snack *)malloc(sizeof(struct Snack));

 
  switch (dir) //依据当前的方向判断
  {
  case UP:
  new->line = tail->line-1;
  new->row = tail->row;
  new->next = NULL; // 作为新的尾巴
    break;
  
   case DOWN:
  new->line = tail->line+1;
  new->row = tail->row;
  new->next = NULL; // 作为新的尾巴
    break;
    
     case LEFT:
  new->line = tail->line;
  new->row = tail->row-1;
  new->next = NULL; // 作为新的尾巴
    break;

     case RIGHT:
  new->line = tail->line;
  new->row = tail->row+1;
  new->next = NULL; // 作为新的尾巴
    break;

  }


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

void initSnack() //初始化蛇 - 死后 复活
{
  dir=RIGHT;
  initFood();
  struct Snack *new = NULL;
  while (head != NULL)
  {
    new = head;
    head = head->next;
    free(new);
  }

  head = (struct Snack *)malloc(sizeof(struct Snack));
  head->line = 2;
  head->row = 2;
  head->next = NULL;
  tail = head;

  addSnack();
  addSnack();
  addSnack();
}

void myPrintMap() //打印地图
{
  int line, row;

  move(0, 0); //每次新的地图都移动到(0,0),覆盖之前的地图实现实时性
  for (line = 0; line < 20; ++line)
  {
    if (line == 0)
    {
      for (row = 0; row < 20; row++)
        printw("--");
      printw("\n");
    }

    if (line >= 0 && line < 20)
    {
      for (row = 0; row <= 20; row++)
      {
        if (row == 0)
          printw("|");
        else if (row == 20)
          printw("|\n");
        else if (haveSnack(line, row))
          printw("[]");
           else if (haveFood(line, row))
          printw("##");
        else
          printw("  ");
      }
      if (line == 19)
      {
        for (row = 0; row < 20; row++)
        {
          if (row == 19)
            printw("--\nby mxjun");
          else
            printw("--");
        }
      }
    }
  }
}

void delSnack()
{
  struct Snack *new;
  new = head;
  head = head->next;
  free(new);
}
int ifSnackDead() //判断边界
{
 if(tail->line<0 || tail->line==20 || tail->row==0 || tail->row==20)
   return 1;
 struct Snack *p=head;
 while(p->next!=NULL)
  {
    if(p->line==tail->line && p->row==tail->row)
      return 1;
      p=p->next;
  } 
return 0;

}


void moveSnack()
{ 
  if(tail->line==food.line && tail->row==food.row) //吃到食物蛇变长
  {
  addSnack();
  initFood();
  }
  else //不然只是移动
  {
  addSnack();
  delSnack();
  }
  // 判断是否撞到墙
  if (ifSnackDead())
  {
    initSnack();//死了重开
  }
}

void *refreshInterface() //线程之一,实现蛇的自动行走
{

  while (1)
  {

    moveSnack();
    myPrintMap();
    refresh();
    usleep(100000);
  }
}

void turn(int newDir) //防止蛇出行头变为尾巴这样的逆天走位
{
 if(abs(newDir)!=abs(dir))
   dir=newDir;

}

void *inputKey() //第二个线程,时刻等待键盘输入
{

  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 th1;
  pthread_t th2;
//初始化蛇和Ncurse
  initNcurse();
  initSnack();

  pthread_create(&th1, NULL, refreshInterface, NULL);
  pthread_create(&th2, NULL, inputKey, NULL);
  while (1) //避免程序退出
  {
  }
  getch();
  endwin(); //结束使用ncurse,退出程序,避免乱码

  getch();
  return 0;
}

公文派2025:免费社区版重大安装更新! 距离上一次更新已经过去了将近一年的时间,今天我们带来了全新的免费2025社区版,该版本也是目前最新的版本,无需授权即可使用所有的功能。 阅读详情

相关推荐

使用kali对局域网内的主机进行远程控制

输入命令:hydra -l administrator -P/usr/share/woerdlists/rockyou.txt 192.168.100.241 smb -V。账户(adminitrator)密码:123456 【一般账户都是我们知晓了,如果不知道账户进行破解那几乎不太可能,密码如果设置的特别复杂无规律也是特别难破解的】【-r:扫描整个网段 后面就是设置 192.168.241.100/24的网络地址段 为 192.168.241.0/24 0和/24之间不要空格】

2301_77599769的博客 2279

ncurses库:一个框架例程源码

ncurses库:一个框架例程源码

编程之道在明明德在亲民在止于至善 2338

ROS2_IGH方案配置(二)——Ubuntu22.04 实时内核性能验证与调优

本文详细介绍了在Ubuntu22.04系统上配置ROS2_IGH方案时,如何验证和调优PREEMPT_RT实时内核性能。通过使用cyclictest工具进行基准测试和压力测试,分析中断与硬件延迟,并优化内核参数,确保系统满足工业控制领域对硬实时性的苛刻要求。文章还提供了针对ROS2的特殊优化建议和性能监控方案,帮助开发者实现毫秒级延迟的稳定控制。

weixin_30791095的博客 224

c语言—贪吃蛇

贪吃蛇

2301_79405674的博客 1139

保姆级教程:用ncnn把自训练的YOLOv8模型塞进Android App(附完整代码)

本文提供了一份详细的保姆级教程,指导开发者如何将自训练的YOLOv8模型通过ncnn框架部署到Android应用中。教程涵盖环境配置、模型训练与转换、Android工程集成及性能优化等全流程,并附完整代码实现,帮助开发者快速掌握移动端AI模型部署技术。

weixin_42659194的博客 255

ESP-IDF 5.4下esp32-camera组件编译报错?手把手教你解决头文件缺失问题

本文详细解析了ESP-IDF 5.4环境下esp32-camera组件编译时出现的头文件缺失问题,提供了从目录结构优化、CMake配置到VSCode智能感知设置的完整解决方案。针对第三方组件集成难题,文章特别强调了PRIV_REQUIRES依赖声明和路径配置的关键作用,帮助开发者高效解决编译错误并建立稳定的开发环境。

weixin_28829629的博客 309

C语言中的图形用户界面开发:使用库如GTK+或ncurses创建GUI应用程序(二)

ncurses库为C语言开发者在命令行环境下提供了强大的文本界面开发能力,无论是简单的菜单导航、文本输入,还是复杂的多窗口布局、鼠标支持,ncurses都能提供相应的API和功能支持,助力开发者构建高效、易用的终端GUI应用程序。

weixin_56154577的博客 1537

Qt 文件对话框(QFileDialog)实战指南 —— 从基础到高级应用

本文是Qt文件对话框(QFileDialog)的实战指南,从基础静态函数调用到高级对象模式应用,全面解析了文件选择、保存、目录选取及多选等核心功能。文章深入探讨了MIME类型过滤、自定义侧边栏、信号槽实时响应及状态持久化等高级技巧,并提供了跨平台开发中的避坑指南与最佳实践,帮助开发者高效、稳健地集成文件操作功能。

weixin_29306261的博客 376

C语言项目--贪吃蛇之ncurse

贪吃蛇在运行的时候,需要与用户进行交互,而在C语言已经学到过的与用户交互的函数有:scanf,gets,getchar,但这些函数有一个问题,当我们输入完数据之后,都需要按下回车才能完成交互。但在贪吃蛇运行过程中,我们按下方向键之后肯定是不需要按回车的。所以我们就使用ncurse来实现。

qq_62283001的博客 322

EBS开发_离散工单创建API

--以下代码于20171213在TONY环境中实现 DECLARE     l_iface_rec    wip.wip_job_schedule_interface%ROWTYPE; --工单任务接口表     l_group_id     NUMBER;     l_returnstatus VARCHAR2(40);     l_errormsg     VARCHAR2(2000

蜗牛先生快跑的博客 2596

单目标跟踪算法及其复现过程---SiamFC(一)

在test.py文件中,就是利用训练出来的模型进行测试,需要更改预训练模型的路径,测试集的路径,以OTB100为例,最后输出的是对每一帧目标位置的坐标点。代码如下:首先需要下载got10k官方库,只需要在终端输入(注意:在终端安装各种库的时候不能使用网络代理),在环境已经配置到的情况下,只需要该其中的路径和就可以运行。这个系列博客仅为了记录各目标跟踪算法的复现(大多为跑通大佬们实现的代码),包括其中出现的很多问题和错误,学到的新知识等等。解决,而且只使用在线的方法,限制了他们可以学习的模型的丰富性。

weixin_58244117的博客 4761

用C语言和ncurses库实现终端贪吃蛇游戏:从原理到实践

在计算机科学教育中,编写经典游戏是学习编程语言和算法的最佳实践之一。贪吃蛇作为一款简单却富有挑战性的游戏,涵盖了数据结构、算法、用户输入处理和图形渲染等多个编程核心概念。本文将详细介绍如何使用C语言和ncurses库在终端环境中实现一个完整的贪吃蛇游戏,从基础原理到代码实现,再到功能扩展思路,为读者提供一个全面的开发指南。

vvilkin的学习备忘 1327

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

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

C语言链表+ncurses库实现贪吃蛇小游戏一、前言二、项目展示三、项目流程四、代码结构五、源码 一、前言 跟着陈老师的课程学习c语言一段时间后,利用c语言链表和ncurses库实现贪吃蛇游戏项目。项目涉及到ncurses库的基本使用、c语言指针、链表的基本知识以及linux多线程的基本使用。 二、项目展示 a、贪吃蛇撞墙死亡,游戏重启 b、贪吃蛇撞到自己死亡,游戏重启 c、正常游戏,下方记录分数以及下一个food的位置坐标 三、项目流程 四、代码结构 为了在更新游戏界面的同时能够让程序对键盘的输

ONERYJHHH的博客 685

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C语言实现Linux终端贪吃蛇:多线程与ncurses库实战

在Linux系统编程中,多线程和终端图形化是构建交互式应用的核心技术。多线程通过并发执行解决了程序阻塞问题,例如在游戏中同时处理用户输入和画面刷新。终端图形化则依赖ncurses库,它提供了一套高级API来管理光标、绘制字符界面和处理键盘事件,是实现命令行工具可视化交互的基础。这些技术的结合,在游戏开发、系统监控工具和命令行界面(CLI)应用中具有广泛价值。本文以贪吃蛇游戏为例,深入探讨了如何运用链表数据结构管理游戏状态,并通过多线程模型分离逻辑与输入,同时利用ncurses库在终端中实现动态画面渲染,为学

weixin_32147929的博客 233

80行C代码实现ncurses版贪吃蛇!

事情是这样的,周末我在家打开电脑排查现网问题,安德森先生对这个电脑非常感兴趣,凑过来非要看看,我给他演示了sl小火车。小小和疯子也都在旁边看着。 我说这个sl小火车是一个现成的程序,然后就被小小和疯子鄙视了,她们以为这个小火车是我自己做的…搞了半天是下载的现成的东西… 我觉得我得自己做点可以玩的小东西,哪怕再简单的,只要看起来像回事就行,以挽回面子。 还是贪吃蛇最简单,这个东西以前我写过不止一版了: https://blog.youkuaiyun.com/dog250/article/details/5303351 h

TCP/IP 4065

c++ 代码_80行C代码实现ncurses版贪吃蛇!

事情是这样的,周末我在家打开电脑排查现网问题,安德森先生对这个电脑非常感兴趣,凑过来非要看看,我给他演示了sl小火车。小小和疯子也都在旁边看着。我说这个sl小火车是一个现成的程序,然后就被小小和疯子鄙视了,她们以为这个小火车是我自己做的…搞了半天是下载的现成的东西…我觉得我得自己做点可以玩的小东西,哪怕再简单的,只要看起来像回事就行,以挽回面子。还是贪吃蛇最简单,这个东西以前我写过不止一...

weixin_39845825的博客 194

linux C语言ncurses实现贪吃蛇代码

/* ■ ■ ■ ■ ■ ■ ■ ■ ■ * 退格: 263 * Ctr+C: 3 * 回车: 10 * 上: 259 * 下: 258 * 左: 260 * 右: 261 * 拉动窗口: 410 * ■ ■ ■ ■ ■ ■ ■ ■ ■ */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ncurses.h> #include <unistd

weixin_45010650的博客 332

C语言贪吃蛇:基于Linux中ncurses库实的贪吃蛇小游戏

历史记录数量不固定,静态数组无法满足需求,用动态数组(自定义vector)实现自动扩容,每次容量满时翻倍,平衡扩容频率和内存利用率。核心代码(Myvector.h/Myvector.c)// 动态数组结构体:适配历史记录动态存储// 存储每条历史记录字符串int size;// 当前有效记录数// 数组容量(初始4,满后自动扩容)}vector;// 核心函数声明// 初始化数组// 尾部新增记录// 容量检测与扩容// 释放内存(防泄漏)

2301_79969685的博客 1487

C贪吃蛇代码详解(ncurse)

#include<curses.h> //使用 ncurse 必须调用它的函数库 #include<stdlib.h> #include<time.h> #define UP 1 //宏定义 UP 与 1 等效 #define DOWN -1 #define LEFT 2 #define RIGHT -2 struct Snake //结构体 { int hang; int lie; struct Snake *next; }; s

weixin_49472648的博客 939

基于Ncurse库下的贪吃蛇游戏运行(Ubuntu 20.04.1)

为何古老图形库ncurse?(GTK、QT) ncurse 封装的库比C自带的库响应速度快并且做了些许优化; 无需去过多关注ncurse,目的在使用ncurse完成贪吃蛇项目,加强对于C语言的使用以及理解。 ncurse的自带函数:(已经截图) nurse 对方向键的响应: (ncurse3.c) #include <curses.h> //这段代码若是超是超过窗口界面则会“堆积”。 int main() { int key; initscr();

汉密士的博客 929

C语言小项目:基于ncurses库和链表的贪吃蛇小游戏

一、项目准备 在Ubuntu的Linux系统上安装好ncurses图形库,不需要对ncurses库十分精通,只要会基本使用即可,该小项目的目的是对于C语言的一个总结与提高,tingshen

qq_46323094的博客 856

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

c语言阶段性练习,贪吃蛇游戏

m0_53255684的博客 254

C语言项目——贪吃蛇小游戏

endwin();防止破坏终端界面getchar();不希望进程退出abs();取绝对值函数。

zongzi的博客 282

基于Ncurses的贪吃蛇小游戏

基于Ncurses的贪吃蛇小游戏 宏定义方向键 #define UP 1 #define DOWN -1 #define LEFT 2 #define RIGHT -2 Ncurses初始化 void initNcurse() { initscr(); keypad(stdscr, 1); noecho(); } 蛇身在移动过程中变化(改变节点坐标) void addNode() { struct Snake *new = (struct Snake*)malloc(sizeof(st

weixin_47642634的博客 268
上一篇: C语言复习-链表
下一篇: 创建第一个51文件
mx_jun
博客等级 码龄5年 1605粉丝 148原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值