网站首页标题设置,鞍山做网站企业,wordpress费用,北京响应式网站如何开发ANSI Escape Sequence 下落的方块
1. ANSI Escape 的用途
无意中发现 B站有人讲解#xff0c; 完全基于终端实现俄罗斯方块。 基本想法是借助于 ANSI Escape Sequence 实现方方块的绘制、 下落动态效果等。对于只了解 ansi escape sequence 用于 log 的颜色打印的人来说 完全基于终端实现俄罗斯方块。 基本想法是借助于 ANSI Escape Sequence 实现方方块的绘制、 下落动态效果等。对于只了解 ansi escape sequence 用于 log 的颜色打印的人来说 这无疑是拓宽了认识。 这一篇简单的列一下 ansi escape sequence 中的稀奇古怪的数字的含义 并最终给出一个绿色方块下落的动态效果和对应的代码。 基于本篇给出的表格和代码 可以把它拓展为自由落体的游戏效果 也可以跟着 B 站视频更容易的写出终端里的俄罗斯方块。
同时也注意到 ansi escape sequence 有它的局限性 无法绘制比较大的圆形 使用 ansi escape sequence 会限制界面显示、 游戏开发的上限。
2. ANSI Escape Sequence 有什么用
终端会把 ANSI Escape 序列的字符解释为命令而不是原本的内容。这些命令在终端上控制如下内容
鼠标位置颜色字体样式其他选项
使用 ANSI Escape Sequence 做 log 打印的例子比较多 但其实还可以那它用作绘图显示 把终端当成是 256 色的图像 在终端显示图像内容。
3. 形式
3.1 格式概况
绝大多数有用的序列 ESC[ 开头序列的重置 ESC[0m 意思是各种设置的属性都撤销掉恢复为没有设置时的状态
一些“黑话”:
CSI (Control Sequence Introducer): ESC[ 的别名, ASCII escape 数值是27 实际使用时 ESC 换成 \x1b(16进制), \033(8进制) 或 \eSGR (Select Graphic Rendition): CSI n m 的别名用于设定字符的颜色和风格。其中: CSI 要换成 \x1b[, \033[ 或 \e[n 要换成具体的数字在 0~107 之间
根据 wikipedia 得到的解释
起始: ESC[ (这个组合又叫做 CSI, Control Sequence Introducer)parameter bytes: 任意数量的 0x30-0x3F 范围的字符, 也就是 0-9:;?intermediate bytes: 任意数量的 0x20-0x2F 范围的字符也就是 !#$%()*,-./final bytes: 任意数量的 0x40-0x7E 范围的字符也就是 “A–Z[]^_a–z{|}~”private bytes: 包含 ? 或 0x70-0x7E 范围(p-z{|}~) 的字符, 各厂商自行定义和使用的设定多个属性: ; 分隔的单个属性重置: ESC[0m
而网上其他资料 以及实际验证 发现维基百科有遗漏内容 ESC[ (CSI) 之后可以紧跟着 0~0x2F 范围的数字, 例如 n1 对应到 “字体加粗” 的属性。
3.2 格式的具体情况
n名字含义、作用0Reset or normal重置所有属性1Bold or increased intensity字体加粗2Faint, decresed intensity, or dim字体变暗3Italic斜体。据说没有被广泛使用4Underline下划线. 算是扩展 在 Kitty, VTE, mintty, iTERM2, Konsole 里有效5Slow blink设定光标闪烁时间在每分钟内小于150次(暂时不会用)6Rapid blink光标闪烁加速每分钟内超过150次; 没有被广泛支持7Reverse video or invert对调背景和前景的颜色8Conceal or hide没有被广泛的支持iTerm2 上没有效果9Crossed-out, or strike让字符带有删除线10Primary(default) font默认字体11~19Alternative font选择编号为 n-10 的字体20Fraktur(Gothic)很少使用。iTerm2 上没有效果21Doubly underlined; or: not bold双下划线、或者不要加粗22Normal intensity既不加粗、也不变暗23Neither italic, nor blackletter既不斜体 也不黑色字母24Not underlined不要有单个下划线 也不要有双下划线25Not blinking不要闪烁光标26Proportional spacing终端上没有在使用27Not reservediTerm2 上没有效果28Reveal不要隐瞒29Not crossed out去掉“删除线30-37Set foreground color设置前景颜色30Black 黑色前景31Red 红色前景32Green 绿色前景33Yellow 黄色前景34Blue 蓝色前景35Magenta 紫色前景36Cyan 靛蓝色前景37White 白色前景38Set foreground color设置前景颜色, 接下来的参数是 5;n 或 2;r;g;b39Default foreground color默认前景颜色40-47设置背景颜色40Black 黑色背景41Red 红色背景42Green 绿色背景43Yellow 黄色背景44Blue 蓝色背景45Magenta 紫色背景46Cyan 靛蓝色背景47White 白色背景48Set background color设置前景颜色 接下来的参数是 5;n 或 2;r;g;b49默认背景颜色50Disable proportional spacing禁用等比例空格51Framedmintty 中被实现为 emoji 选择器(?)52Encircled同上53Overlinked没效果54Neither framed nor encircled55Not overlined58Set underline color设置下划线颜色。不是标准规定的。Kitty, VTE, iTerm2里有实现下一个参数需要是 5;n 或 2;r;g;b 形式59Default underline color默认下划线颜色. 非标准。在 Kitty, VTE, iTerm2里有实现60~65通常没有实现73-74Superscript, Subscript上标和下标。只在 mintty 里有实现75-76Neither superscript nor subscript取消上标和下标90-97Set bright foreground color设置前景颜色亮度。非标准. iTerm2里有效90Bright Black亮黑色前景色91Bright Red亮红色前景色92Bright Green亮绿色前景色93Bright Yellow亮黄色前景色94Bright Blue亮蓝色前景色95Bright Magenta亮紫色前景色96Bright Cyan亮靛蓝色前景色97Bright White亮白色前景色100-107Set bright background color背景颜色亮度. iTerm2里有效100Bright Black亮黑色背景色101Bright Red亮红色背景色102Bright Green亮绿色背景色103Bright Yellow亮黄色背景色104Bright Blue亮蓝色背景色105Bright Magenta亮紫色背景色106Bright Cyan亮靛蓝色背景色107Bright White亮白色背景色
其中 n 为 38 是设置前景颜色 ESC[38;5;{ID}m n 为 48 是设置背景颜色 ESC[48;5;{ID}m, ID 是具体的颜色 见下图: 3.3 常见私有模式 (Common Private Modes)
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
ESC 代码序列描述ESC[?25l]隐藏光标ESC[?25h]显示光标ESC[?47l]恢复屏幕ESC[?47h]保存屏幕ESC[?1049h]启用可选bufferESC[?1049l]禁用可选bufer
3.4 控制光标
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#cursor-controls
ESC 代码序列描述ESC[H光标移动到 (0, 0) 位置ESC[#A光标向上移动 # 行ESC[#B光标向下移动 # 行
3.5 擦除功能 (Erase Functions)
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#erase-functions
ESC CodeDescriptionESC[J清除光标位置到屏幕结束位置ESC[0J同 ESC[JESC[1J清除光标位置到屏幕开始ESC[2J清除整个屏幕ESC[3J清除保存的行ESC[K清除当前光标位置到当前行末尾ESC[0K同 ESC[KESC[1K删除当前光标位置到当前行首ESC[2K删除整行
4. 简单例子 #include stdio.h
#include iostream
#include string
#include vector
#include numericint main()
{std::vectorint codes {1, 2, 3, 4, 7, 8, 9};std::generate_n(std::back_inserter(codes), 8, [n 30]() mutable { return n; });std::generate_n(std::back_inserter(codes), 8, [n 40]() mutable { return n; });std::generate_n(std::back_inserter(codes), 8, [n 90]() mutable { return n; });std::generate_n(std::back_inserter(codes), 8, [n 100]() mutable { return n; });for (const auto code : codes){printf(\e[%dmHello\e[mworld (n%d)\n, code, code);}printf(\e[1;34mHello\e[0mworld (n1;34)\n);printf(\e[38;5;2mHello\e[0mworld (n38;5;2)\n);printf(\e[48;5;2mHello\e[0mworld (n48;5;2)\n);return 0;
}5. 复杂例子 - 方块下落
绘制最小的绿色矩形 打印“空格” 字符 并且让空格字符的前景颜色红色的
printf(\e[42m \e[0m\n); 绘制较大的红色矩形 每一行打印多个空格 连续打印多行 每一行打印时使用转义字符。
printf(\e[42m \e[0m\n); 绘制会下落的红色矩形框: 先绘制一个长度持续增加的。
void draw_box()
{for (int i 0; i 10; i){printf(\e[42m \e[0m\n);std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}通过 ANSI Escape Sequence, 修改光标位置 然后再绘制矩形:
void draw_box2()
{printf(\e[H); // 光标移动到 (0,0) 位置printf(\e[42m \e[0m); // 绘制绿色背景的空格printf(\e[1B); // 光标往下一行。 注意此时 column 方向上 光标不是在0位置printf(\e[43m \e[0m); // 绘制黄色背景的空格
}让每一行的绘制 都从第 6 列开始绘制, 并且每次绘制后 等待 100 毫秒:
void draw_box6()
{printf(\e[?25l); // 隐藏光标 避免光标导致的白色小方框for (int i 0; i 10; i){printf(\e[2J); // 清空整个屏幕printf(\x1b[%d;%dH\e[0m, i, 6); // 光标一定到第i 行第 6 列printf(\e[42m \e[0m); // 绘制绿色矩形 也就是绘制绿色背景的空格fflush(stdout); // 确保绘制到控制台std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 暂停 500 毫秒营造下落的视觉效果}printf(\e[?25h); // 恢复光标的可见性
}6. ANSI Escape 的局限
无法绘制圆形。 因为终端绘制的最小单位 是单个字符每个字符通常是竖条而不是正方形 并且竖条比较大 大于通常看到的图像像素。 这就导致 稍微复杂的图形无法绘制 需要选择其他的方案
使用 opencv 的 Mat 绘制 用 imshow 显示使用 SFML / SDL / Dear imgui / Qt 绘制和显示
7. References
手把手教你写俄罗斯方块2-如何在终端上绘图ANSI Escape CodesC语言实现 log 库