仔爸 发表于 2024-8-27 10:21:55

行空板k10:文字跑马灯二

本帖最后由 仔爸 于 2024-10-23 15:21 编辑

K10
上一篇《行空板k10:文字跑马灯一》介绍了在行空板k10中实现纵向和横向的文字跑马灯效果。本次对跑马灯进行更进一步的研究,让跑马灯更具交互性。
一、项目背景
进一步探究文字跑马灯的效果,实现倾斜行空板让文字从不同方向进行跑马灯。特别是从左往右的方向上,文字实现了翻转。
https://www.bilibili.com/video/BV1hyspeBEpN/
二、硬件清单

[*]行空板
[*]数据线
[*]外接电池(可选)

三、项目实现
陀螺仪是行空板的板载传感器,利用这个传感器,我们可以轻松实现一些诸如板子倾斜,抖动、翻转、晃动等的侦测。以下两个积木就是用来使用陀螺仪的相关功能,本次我们将使用姿态侦测。



那么在我们将板子向前、向后、向左、向右倾斜的时候,让文字向该方向移动实现跑马灯,将是比较有趣的效果。
1. 定义“纵向跑马灯”函数
一个函数要实现两个方向的跑马灯,那么我们需要定义函数的时候设置一个数值参数,该参数可以取0(从上往下移动)或1(从下往上移动),为什么取0或1呢?当然我们可以在函数内部通过一个选择语句来判断0的话,给一个从上往下的移动脚本,同理,1的话,再写一个从下往上移动的脚本。如此一来,脚本会重复编写,不利于程序的简洁性。因此,我们可以将参数写入表达式,而省去选择语句。
通过上一个项目我们知道,字宽24像素的文字,在纵向一共有13行,那么如何根据0或1来确定起始位置呢?也就是从上往下移动的话,起始位置是第1行,而从下往上移动,起始位置是第13行。对应关系是:

[*]参数0 -> 第1行    行数增加
[*]参数1 -> 第13行行数减少

我们可以利用乘0的特性,写出如下表达式(方向即传递的参数):

另外,行数增减的脚本如下:

解决了这个问题,我们可以很容易通过修改上一个跑马灯中的脚本实现纵向跑马灯的函数了。

2. 定义“横向跑马灯”函数
横向跑马灯仍通过坐标的改变实现。因为我测试在同一个程序中,无法实现纵向和横向屏幕的切换,因此本次均在纵向屏幕上实现跑马灯效果。
那么在纵向屏幕上实现跑马灯,其实是从左或从右开始移动文字,起始位置x的坐标是不是0或240呢?请观察下图:

很显然,从右往左移动的话,文字的起始位置确实是240(即屏幕的最右侧坐标,其实是239)。但从左往右移动的话,文字一开始并不是摆放在x坐标为0的位置,而应该放在偏左一个文字长度的位置,即**0减去文字长度**的值是其起始位置。
通过下面的脚本可以求得文字中汉字的个数(求英文字符的个数更简单):

然后梳理出如下对应关系:

[*]参数0 -> 从左往右起始位置为:x坐标 = 0-文字长度    x坐标增加
[*]参数1 -> 从右往左   起始位置为:x坐标 = 240            x坐标减少

仍利用参数0相乘的特点,用下面的脚本实现起始位置(y坐标也在一定范围内随机获得):



重复移动时的结束条件是,文字已经被移出屏幕右侧或左侧,使用下面的脚本实现:



以及每次递增或递减20个像素的脚本:

“横向跑马灯”函数完整的脚本如下:



3. 反转字符串
以上横向跑马灯的效果,从右往左没有问题,而从左往右移动,我们会发现是这样的:


也就是文字结尾先出来,这样阅读起来有点奇怪 。因此我想到是不是可以在向右移动的时候,将文字翻转?那就写一个文字翻转的函数。但实践过程中发现,如果纯汉字或纯英文都没有问题,而如果里面出现中英文夹杂的情况,会有问题,因为一个汉字占3字节,一个英文或数字占1字节,在取字的时候,要区分开来操作。
翻转函数的实现原理是,针对源字符串,从第1个字符开始,如果是汉字就每次取3个字符长度,如果是英文或数字,只要每次取1个字符。将取出的字符**倒着**拼接到临时字符串变量中。最后将完成翻转的临时字符串覆盖源字符串变量。那么如何判断取出的字符是中文还是英文呢?其实我们可以根据字符的ASCII码值进行判断。通过查阅ASCII码表,我们发现数字0~9的ASCII码十进制是48~57,而大字字母的ASCII码值是65~97,小写字母的ASCII值是97~122,此外还有一些标点符号等。


干脆我们直接判断ASCII值的范围是不是在32到126之间,而不用区分数字、大小写字母和字符了。因此翻转字符串函数的脚本如下:



在“横向跑马灯”函数的开头和结尾添加如下脚本(注意是各添加一次如下脚本),也就是一开始如果是从左往右移动,先把字符串进行翻转,等显示结束,仍将字符串翻转回来成正常的字符串。


4. 主程序
主程序就比较简单了,除了一些初始化工作之外,循环里面进行一下行空板的姿态判断,根据判断的结果调用相应的跑马灯函数即可。



四、反思拓展
在本项目的实践过程中,我发现有两个bug并已经反馈。一个是文字从右往左移动的时候,如果选择文字是自动清除的话,会出问题。解决办法是文字不要自动清除,然后用一个矩形条覆盖文字。第二个问题是,翻转字符串函数与屏幕方向设置积木起冲突,解决办法是DF的柳春晓工程师写了一个函数,需要在“手动编辑”框中修改,参见操作视频。我之前用图形化写的翻转函数暂时没有使用,但可以用这个函数理解一下字符串翻转的原理。
//自定义翻转字符串的函数
int getUTF8CharLength(const char* str) {
unsigned char ch = str;
if ((ch & 0x80) == 0) return 1; // ASCII字符
if ((ch & 0xE0) == 0xE0) return 3; // 3字节字符
if ((ch & 0xC0) == 0xC0) return 2; // 2字节字符
return 1; // 默认1字节字符
}

String reverseUTF8String(String str) {
String reversedStr = "";
int length = str.length();
int i = 0;

while (i < length) {
    int charLength = getUTF8CharLength(str.c_str() + i); // 获取当前字符的字节数
    reversedStr = str.substring(i, i + charLength) + reversedStr;
    i += charLength; // 移动到下一个字符
}

return reversedStr;
}

https://www.bilibili.com/video/BV11LspetEqk/
另外在判断取得的字符是否是英文字符时,如果你觉得逻辑表达式过长,也可以用这样的脚本来代替(是不是觉得更繁琐了?就当提供另外的思路吧)


关于这个项目的拓展,你是不是可以考虑增加这样一个功能,就是根据板子的倾斜度,增加或减少文字移动的速度,试一试吧!
页: [1]
查看完整版本: 行空板k10:文字跑马灯二