鱼C论坛

 找回密码
 立即注册
查看: 1611|回复: 2

[技术交流] 学习了ncurses绘图库的一些函数的使用方法

[复制链接]
发表于 2020-3-9 12:37:08 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 就是要努力呀 于 2020-3-9 12:37 编辑
  1. #include <stdio.h>
  2. #include <ncurses.h>

  3. int main(void)
  4. {
  5.         initscr();      /*      */
  6.         cbreak();       /*初始化ncurses(再使用ncurses库的都要先调用这三个函数)*/
  7.         noecho();       /*      */

  8.         curs_set(0);    //隐藏光标

  9.         move(10, 10);   //移动光标
  10.         addch('A');     //打印一个字符
  11.         addstr("ABCD"); //打印一串字符串
  12.         refresh();      //刷新屏幕

  13.         getch();        //类似于getchar() 但getch()会在用户按键后立刻执行 不需要等待回车

  14.         endwin();       //退出ncurses

  15.         return 0;
  16. }
复制代码
感谢人造人大佬给我提出的ncurse函数库
今天在b站通过学习一位up主写flappybird这个游戏学习了ncurses库的一些使用方法,在这里分享给大家
ncurse库不是linux自带的库,所以需要在命令行执行 sudo apt-get install libncurses5-dev 安装这个库
在编译的时候也需要加上-lncurese选项连接这个库

以下是flappybird的代码 因为是一边跟着up写的 所以就没有注释
  1. #include <stdio.h>
  2. #include <ncurses.h>
  3. #include <stdlib.h>
  4. #include <signal.h>
  5. #include <sys/time.h>

  6. #define BIRD 'o'
  7. #define PIPE '*'
  8. #define BLANK ' '

  9. typedef struct Pipe
  10. {
  11.         int x;
  12.         int y;
  13.         struct pipe *next;
  14. }
  15. Pipe;

  16. Pipe *HEAD, *TAIL;

  17. int X, Y;        //小鸟坐标
  18.                
  19. void drop(int sig); 小鸟下坠
  20. int set_ticker(int n_msec); 设定时间发送信号
  21. void clear_bird(); 清楚小鸟之前的位置
  22. void draw_bird(); 打印出小鸟现在的位置
  23. void clear_pipe(int x, int y); 清除一个柱子之前的位置
  24. void draw_pipe(int x, int y); 打印一个柱子现在的位置
  25. void init_pipes(); 初始化柱子的链表
  26. void draw_pipes(); 打印所有柱子
  27. void clear_pipes(); 清除所有柱子
  28. void move_pipes(); 移动所有柱子

  29. void move_pipes()
  30. {
  31.         Pipe *p;

  32.         for(p = HEAD->next; p->next != NULL; p = p->next)
  33.         {
  34.                 p->x--;
  35.         }
  36. }

  37. void draw_pipes()
  38. {
  39.         Pipe *p;

  40.         for(p = HEAD->next; p->next != NULL; p = p->next)
  41.         {
  42.                 draw_pipe(p->x, p->y);
  43.         }
  44. }

  45. void clear_pipes()
  46. {
  47.         Pipe *p;

  48.         for(p = HEAD->next; p->next != NULL; p = p->next)
  49.         {
  50.                 clear_pipe(p->x, p->y);
  51.         }
  52. }

  53. void init_pipes()
  54. {
  55.         HEAD = (Pipe *)malloc(sizeof(Pipe));

  56.         if(HEAD == NULL)
  57.         {
  58.                 exit(0);
  59.         }

  60.         HEAD->next = NULL;

  61.         Pipe *temp, *p = HEAD;
  62.         int i;

  63.         for(i = 0; i < 5; i++)
  64.         {
  65.                 temp = (Pipe *)malloc(sizeof(Pipe));

  66.                 if(temp == NULL)
  67.                 {
  68.                         exit(0);
  69.                 }

  70.                 temp->x = (i + 1) * 20;
  71.                 temp->y = rand()%16 + 10;

  72.                 p->next = temp;
  73.                 temp->next = NULL;
  74.                 p = temp;
  75.         }

  76.         TAIL = p;
  77. }

  78. void draw_pipe(int x, int y)
  79. {
  80.         int i, j;

  81.         for(i = 0; i < 5; i++)
  82.         {
  83.                 for(j = 0; j < 20; j++)
  84.                 {
  85.                         move(y - j - 5, x + i);
  86.                         addch(PIPE);

  87.                         move(y + j + 5, x + i);
  88.                         addch(PIPE);
  89.                 }
  90.         }
  91. }

  92. void clear_pipe(int x, int y)
  93. {       
  94.         int i, j;

  95.         for(i = 0; i < 5; i++)
  96.         {
  97.                 for(j = 0; j < 20; j++)
  98.                 {
  99.                         move(y - j - 5, x + i);
  100.                         addch(BLANK);

  101.                         move(y + j + 5, x + i);
  102.                         addch(BLANK);
  103.                 }
  104.         }

  105. }

  106. void draw_bird()
  107. {
  108.         move(X, Y);
  109.         addch(BIRD);
  110.         refresh();

  111.         if((char)inch() == PIPE)
  112.         {
  113.                 set_ticker(0);
  114.                 endwin();
  115.                 exit(0);
  116.         }
  117. }

  118. void clear_bird()
  119. {
  120.         move(X, Y);
  121.         addch(' ');
  122.         refresh();
  123. }

  124. int set_ticker(int n_msec)
  125. {
  126.         struct itimerval timeset;
  127.         long int n_sec, n_usec;

  128.         n_sec = n_msec / 1000;
  129.         n_usec = (n_msec % 1000) * 1000L;

  130.         timeset.it_interval.tv_sec = n_sec;
  131.         timeset.it_interval.tv_usec = n_usec;

  132.         timeset.it_value.tv_sec = n_sec;
  133.         timeset.it_value.tv_usec = n_usec;

  134.         return setitimer(ITIMER_REAL, ×et, NULL);
  135. }

  136. void drop(int sig)
  137. {
  138.         clear_bird();

  139.         X++;

  140.         draw_bird();

  141.         clear_pipes();

  142.         Pipe *p = HEAD->next;

  143.         if(p->x < 0)
  144.         {
  145.                 HEAD->next = p->next;

  146.                 free(p);

  147.                 Pipe *temp = (Pipe *)malloc(sizeof(Pipe));

  148.                 if(temp == NULL)
  149.                 {
  150.                         exit(0);
  151.                 }

  152.                 temp->x = 80;
  153.                 temp->y = 15;
  154.                 TAIL->next = temp;
  155.                 temp->next = NULL;
  156.                 TAIL = temp;
  157.         }

  158.         move_pipes();
  159.         draw_pipes();
  160. }

  161. int main(void)
  162. {
  163.         int i;
  164.         char ch;

  165.         X = 5;
  166.         Y = 10;

  167.         initscr();
  168.         cbreak();
  169.         noecho();
  170.         curs_set(0);
  171.         srand(time(NULL));
  172.        
  173.         signal(SIGALRM, drop);
  174.         set_ticker(500);

  175.         init_pipes();

  176.         while(true)
  177.         {
  178.                 clear_bird();
  179.                 draw_bird();
  180.                 clear_pipes();
  181.                 draw_pipes();

  182.                 if((ch = getch()) == ' ')
  183.                 {
  184.                         clear_bird();

  185.                         X--;
  186.                 }
  187.                 else if(ch == 'q' || ch == 'Q')
  188.                 {
  189.                         break;
  190.                 }
  191.         }

  192.         endwin();
  193.        
  194.         return 0;
  195. }
复制代码
当然自己也有很多没有弄明白的地方
<sys/time.h>头文件
signal函数 signal(SIGALRM, drop)(我知道这个函数的意思是接受数据就执行drop函数)

还有set_ticker这个函数中定义的 itimerval 结构体
以及 setitimer函数 setitimer(ITIMER_REAL, &TIMESET, NULL) (指定多少时间后就发送信号)
因为视频中对这几个函数都是略过或者根本没讲 所以一点也没搞懂


小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-9 14:16:24 | 显示全部楼层
参考这篇文章 https://blog.csdn.net/lixianlin/article/details/25604779

我看完这篇文章,一开始写下的测试代码是这样的
  1. #include <stdio.h>
  2. #include <signal.h>
  3. #include <sys/time.h>

  4. // 回调函数
  5. void handler(int sig)
  6. {
  7.     static int count;
  8.     printf("handler: %d\n", count++);
  9. }

  10. int main(void)
  11. {
  12.     // 注册回调函数
  13.     // 当程序收到SIGALRM信号后
  14.     // 暂停当前程序的执行,转去执行handler函数
  15.     // handler函数返回后再从暂停的位置继续向下执行
  16.     signal(SIGALRM, handler);
  17.     struct itimerval new_value;
  18.     new_value.it_interval.tv_sec = 0;
  19.     new_value.it_interval.tv_usec = 500000;
  20.     new_value.it_value.tv_sec = 0;
  21.     new_value.it_value.tv_usec = 0;
  22.    
  23.     // 设置定时器
  24.     // 当定时器超时后让系统发送一个信号给当前程序
  25.     // ITIMER_REAL参数指明要让系统发送SIGALRM信号
  26.     setitimer(ITIMER_REAL, &new_value, NULL);
  27.     while(1)
  28.         ;
  29.     return 0;
  30. }
复制代码


首先系统会在一个单位时间后对it_value递减,单位时间是多少,取决于你的系统,可能是10毫秒也可能是1毫秒,甚至是微妙、纳秒
总之就是系统会对it_value减一个合适的值,并不一定是减1,减多少取决于系统
系统每一个单位时间都对it_value减一个合适的值,直到it_value小于等于0
然后系统会做两件事
1.把it_interval复制到it_value,开始新一轮定时
2.发送一个信号,我们通过参数ITIMER_REAL要求发送SIGALRM

  1.     new_value.it_interval.tv_sec = 0;
  2.     new_value.it_interval.tv_usec = 500000;
  3.     new_value.it_value.tv_sec = 0;
  4.     new_value.it_value.tv_usec = 0;
复制代码


我期望的是500毫秒发一个信号
调用完setitimer函数后立刻发一个信号,因为it_value为0

但是系统不允许我这样做,系统会把一开始的it_value为0作为定时器停止的标志

那么修改代码
  1. #include <stdio.h>
  2. #include <signal.h>
  3. #include <sys/time.h>

  4. void handler(int sig)
  5. {
  6.     static int count;
  7.     printf("handler: %d\n", count++);
  8. }

  9. int main(void)
  10. {
  11.     signal(SIGALRM, handler);
  12.     struct itimerval new_value;
  13.     new_value.it_interval.tv_sec = 0;
  14.     new_value.it_interval.tv_usec = 500000;
  15.     new_value.it_value = new_value.it_interval;
  16.     setitimer(ITIMER_REAL, &new_value, NULL);
  17.     while(1)
  18.         ;
  19.     return 0;
  20. }
复制代码


让it_value直接等于it_interval,也就是不要一开始就发信号了
这样确实可以了,500ms发一次信号

不知道你是不是对 tv_sec 和 tv_usec 的设置有疑问
我是应该只设置tv_sec还是只设置tv_usec  ?
这两个是怎么表示时间的?

https://blog.csdn.net/lyc_daniel/article/details/11733715
“tv_sec为Epoch到创建struct timeval时的秒数,tv_usec为微秒数,即秒后面的零头”

看到 “秒后面的零头”,我明白了
这两个参数是一起表示时间的,就像是整数和小数分开存储一样
tv_sec存储秒,tv_usec存储微秒

那我又有了另一个问题,我能不能把tv_sec设置为0,通过设置tv_usec来定时任意时间?
  1. #include <stdio.h>
  2. #include <signal.h>
  3. #include <sys/time.h>

  4. void handler(int sig)
  5. {
  6.     static int count;
  7.     printf("handler: %d\n", count++);
  8. }

  9. int main(void)
  10. {
  11.     signal(SIGALRM, handler);
  12.     struct itimerval new_value;
  13.     new_value.it_interval.tv_sec = 0;
  14.     new_value.it_interval.tv_usec = 1000000;        // 1秒,6个0
  15.     new_value.it_value = new_value.it_interval;
  16.     setitimer(ITIMER_REAL, &new_value, NULL);
  17.     while(1)
  18.         ;
  19.     return 0;
  20. }
复制代码



通过测试是
不能这样,tv_sec 表示秒的部分
tv_usec只能表示微秒和毫秒,会忽略超过毫秒的部分

  1. #include <stdio.h>
  2. #include <signal.h>
  3. #include <sys/time.h>

  4. void handler(int sig)
  5. {
  6.     static int count;
  7.     printf("handler: %d\n", count++);
  8. }

  9. int main(void)
  10. {
  11.     signal(SIGALRM, handler);
  12.     struct itimerval new_value;
  13.     new_value.it_interval.tv_sec = 0;
  14.     new_value.it_interval.tv_usec = 100000;        // 100毫秒,5个0
  15.     new_value.it_value = new_value.it_interval;
  16.     setitimer(ITIMER_REAL, &new_value, NULL);
  17.     while(1)
  18.         ;
  19.     return 0;
  20. }
复制代码


这样是可以的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-9 16:43:53 From FishC Mobile | 显示全部楼层
人造人 发表于 2020-3-9 14:16
参考这篇文章 https://blog.csdn.net/lixianlin/article/details/25604779

我看完这篇文章,一开始写下 ...

好奥利给我会仔细看的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-2 15:18

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表