ncurses实现一个会滚动的圆圈

我一直想知道sl蒸汽机小火车是怎么做的,我惊奇于它那烟囱里冒出的炫酷的烟,以及车轮的滚动:
ncurses实现一个会滚动的圆圈_第1张图片

于是我想自己试一试,我就做一个滚动的圆就不错了,也不奢望能有什么好看的效果,就类似下面的样子(我故意usleep(500000);调了慢速):
ncurses实现一个会滚动的圆圈_第2张图片
12个字母在一个圆上轮转,以展示滚动的效果,我这些是完全算出来的:

  • 一个list_head双链表模拟圆周的点。
  • 二维平面逐行扫描顺序转换为圆周顺序。
  • 每次删除表头插入表尾以模拟转动。
  • 遍历链表展示效果。

我的代码非常简单,如下所示:

#include 
#include 
#include 
// list.h是我抽取的Linux kernel的,不在这里贴了。
#include "list.h"

#define	LINES	100
#define	COLS	150

struct node {
	struct list_head list;
	int X;
	int Y;
};

struct list_head circle;
struct list_head stack;

void init_term()
{
	initscr();
	noecho();
	keypad(stdscr, 1);
	nodelay(stdscr, 1);
	curs_set(0);
}

char pad[LINES][COLS];
void init(struct list_head *list, struct list_head *stack, int x, int y, int R)
{
	int i, j, iter = 0;
	struct list_head *tmp, *n;

	list_for_each_safe(tmp, n, list) {
		struct node *p = list_entry(tmp, struct node, list);
		for (j = 0; j < LINES; j++) {
			for (i = 0; i < COLS; i++) {
				if ((i - x)*(i - x) + (j - y)*(j - y) == (R-0)*(R-0) &&
				//    (i - x)*(i - x) + (j - y)*(j - y) < (R+1)*(R+0) &&
					pad[j][i] != 1) {
					pad[j][i] = 1;
					p->X = i;
					p->Y = j;
					// 下面是为了把逐行扫描顺讯转换为圆周顺序。stack链表模拟一个栈
					if (iter % 2) {
						list_del(tmp);
						list_add(tmp, stack);
					}
					iter ++;
					i += COLS;
					j += LINES;
				}
			}
		}
	}
	// 依次pop出来,加入circle链表,完成圆周顺序的转换。
	list_for_each_safe(tmp, n, stack) {
		list_del(tmp);
		list_add_tail(tmp, list);
	}
}

//char *fl[16] = {"#####", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A"};
int main(int argc, char **argv)
{
	int i, num;
	struct list_head *head;

	num = atoi(argv[1]);
	INIT_LIST_HEAD(&circle);
	INIT_LIST_HEAD(&stack);
	for (i = 0; i < num; i++) {
		struct node *p = calloc(1, sizeof(struct node));
		INIT_LIST_HEAD(&p->list);
		list_add_tail(&p->list, &circle);
	}
	head = circle.next;

	memset(pad, 0, sizeof(pad));
	init_term();
	init(&circle, &stack, 20, 20, 10);
	memset(pad, 0, sizeof(pad));

	i = 1;
	while (i++) {
		struct list_head *tmp;
		char c[2] = {'A', 0};
		int idx = 0;
		list_for_each(tmp, &circle) {
			struct node *p = list_entry(tmp, struct node, list);
			mvprintw(p->Y, p->X + i, c);
			c[0] ++;
		}
		refresh();
		usleep(500000);
		clear();
		list_del(head);
		list_add_tail(head, &circle);
		head = circle.next;
	}
}



在此之前,我下载了sl的代码:
https://github.com/mtoyoda/sl
我编译,然后我运行,但我一直没有看代码,我希望自己完成一个还算过得去的效果之后,再来学习这个代码。

手欠,运行了一个strings命令,然后就看到了下面的:

[root@localhost sl]# strings ./sl
/lib64/ld-linux-x86-64.so.2
libncurses.so.5
__gmon_start__
COLS
stdscr
...
------'|oOo|=[]=- O=======O=======O    |  ||=======_|__
/~\____|___|/~\_|      ||      ||      |__|+-/~\_|
------'|oOo|==[]=- O=======O=======O   |  ||=======_|__
------'|oOo|===[]=- O=======O=======O  |  ||=======_|__
------'|oOo|===[]=-    ||      ||      |  ||=======_|__
/~\____|___|/~\_|    O=======O=======O |__|+-/~\_|
------'|oOo|==[]=-     ||      ||      |  ||=======_|__
/~\____|___|/~\_|   O=======O=======O  |__|+-/~\_|
      ====        ________                ___________
  _D _|  |_______/        \__I_I_____===__|_________|
   |(_)---  |   H\________/ |   |        =|___ ___|
   /     |  |   H  |  |     |   |         ||_| |_||
  |      |  |   H  |__--------------------| [___] |
  | ________|___H__/__|_____/[][]~\_______|       |
  |/ |   |-----------I_____I [][] []  D   |=======|__
__/ =| o |=-~~\  /~~\  /~~\  /~~\ ____Y___________|__
 |/-=|___|=    ||    ||    ||    |_____/~\___/
  \_/      \O=====O=====O=====O_/      \_/

 |/-=|___|=O=====O=====O=====O   |_____/~\___/
  \_/      \__/  \__/  \__/  \__/      \_/
__/ =| o |=-O=====O=====O=====O \ ____Y___________|__
__/ =| o |=-~O=====O=====O=====O\ ____Y___________|__
 |/-=|___|=   O=====O=====O=====O|_____/~\___/
  \_/      \_O=====O=====O=====O/      \_/
;*3$"
GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-36)
crtstuff.c
__JCR_LIST__
deregister_tm_clones
__do_global_dtors_aux

好家伙,原来这么好玩的东西不是算出来的啊, 原来这么好玩的东西竟然是直接逐帧画出来的!

虽然它是ncurses的字符帧,但原理上还是空间换了时间,就像Windows图标总是准备好几个,大的,中等的,小的,它们都是提前准备好的位图Resource文件,而不是即时计算出来的矢量图…

我怎么就没有想到,我还老老实实傻乎乎的去计算,如果我也循着这个直接画帧的思路,也许可以在周末的时候就能完成一个骷髅头☠️了,然后以此逗安德森先生高兴高兴了。

唉,还是功力不够啊!没能及时想到时间空间的自如转换,这也太经理了。

最后,我觉得无论如何对ncurses来讲,还真的没必要比较两种方式的性能,字符终端毕竟不是像素终端,即使是遍历,也消耗不了多少资源。


浙江温州皮鞋湿,下雨进水不会胖。

你可能感兴趣的:(ncurses实现一个会滚动的圆圈)