找回密码
 点一下
查看: 2267|回复: 10

StringSub函数执行次数限制问题

[复制链接]
发表于 2020-8-25 23:09:27 | 显示全部楼层 |阅读模式
本帖最后由 枪兵打巨像 于 2020-10-19 19:05 编辑

Bad Apple!! 星际争霸2赛博朋克版 V1.0.mp4_000315.jpg

最近我在做 Bad Apple!! 高清版地图,想把分辨率从之前的 24×18 提高到 48×36

为了实现这个目标,我将编码表导入算法从 数组赋值算法 改为了 字符串导入算法,用一个字符串存储每一帧中所有像素点的编码信息。
字符串导入算法 需要用到 StringSub函数 处理字符串,遍历字符串中的每一个字符,读取"0"或"1"的编码(对应 Bad Apple!!中 "白色" 或 "黑色" 像素点)。
在使用 StringSub函数 的过程中,我发现 StringSub函数 存在执行次数的限制,每场游戏不能超过 59546 次。
如果 StringSub函数 的执行次数超过了 59546 次,就会出现溢出。报错如下图所示:

Screenshot2020-08-25 21_36_32_1.jpg

因为这个限制,我只能导入 5% 的编码表。Bad Apple!! 视频全长220秒,我只能播放前10秒。
如果要完成这个作品,我必须突破 StringSub函数 执行次数的限制。我已经为此DeBug了两天了,可还是一筹莫展。
我尝试了N种方法想绕过这个限制,可是 59546 次的限制就像冷酷无情的真空光速一样,绝对不可撼动,超过1次都不行。

所以,求教论坛的大神们,如何突破 StringSub函数 执行次数 59546 次的限制 ?


Bad Apple!! 实现过程:
(1) 导入编码表字符串。
(2) 使用 StringSub函数 遍历字符串,读取编码。
(3) 将"0"或"1"编码转化为布尔值,并将布尔值存入二维数组。
(4) 以单位作为像素点,以第 (3) 步中的布尔值作为逻辑判定依据,使用 "替换单位"函数 播放 Bad Apple!!

Galaxy代码:
(1) 导入编码表字符串:
  1. p[1]="111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
  2. // 第1帧

  3. // ......
  4. // 第2帧到第2796帧省略

  5. p[2797]="111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
  6. // 第2797帧
复制代码

(2) 使用 StringSub函数 遍历字符串,读取编码:
  1. for(i=1;i<2798;i+=1){
  2.     for(j=1;j<433;j+=1){
  3.         px[i][j]=StringSub(p[i],j,j);
  4.     }
  5. }
复制代码

(3) 将"0"或"1"编码转化为布尔值,并将布尔值存入二维数组:
  1. for(i=1;i<2798;i+=1){
  2.     for(j=1;j<433;j+=1){
  3.         if(px[i][j]=="1"){
  4.             judge[i][j]=false;
  5.         }
  6.         else{
  7.             judge[i][j]=true;
  8.         }
  9.     }
  10. }
复制代码

(4) 以单位作为像素点,以第 (3) 步中的布尔值作为逻辑判定依据,使用 "替换单位"函数 播放 Bad Apple!!
  1. t1=0.08;
  2. // 每一帧停留时间
  3. for(i=1;i<2798;i+=1){
  4.     for(j=1;j<433;j+=1){
  5.         if(judge[i][j]==true){
  6.             libNtve_gf_ReplaceUnit(RegionGetAttachUnit(RegionFromId(j)), "ZakoomCrystalFragment", libNtve_ge_ReplaceUnitOptions_NewUnitsDefault);
  7.             RegionAttachToUnit(RegionFromId(j), libNtve_gf_LastReplacedUnit(), Point(0.0, 0.0));
  8.         }
  9.         else{
  10.             libNtve_gf_ReplaceUnit(RegionGetAttachUnit(RegionFromId(j)), "KorhalKeystone", libNtve_ge_ReplaceUnitOptions_NewUnitsDefault);
  11.             RegionAttachToUnit(RegionFromId(j), libNtve_gf_LastReplacedUnit(), Point(0.0, 0.0));
  12.         }
  13.     }
  14.     Wait(t1, c_timeReal);
  15. }
复制代码

 楼主| 发表于 2020-8-27 00:19:14 | 显示全部楼层
本帖最后由 枪兵打巨像 于 2020-10-19 19:06 编辑

经过3天艰苦deBug,问题已解决!

StringSub函数 不存在 执行次数 的限制,
但是存在 赋值次数 的限制,具体数值是 59546 次!超过这个限制就会溢出。

以下举例说明:
(1) 会出现溢出的代码,说明 StringSub函数 存在 赋值次数 的限制:
  1. for(i=1;i<2798;i+=1){
  2.     for(j=1;j<433;j+=1){
  3.         px[i][j]=StringSub(p[i],j,j);
  4.     }
  5. }
复制代码

(2) 不会出现溢出的代码1,说明 StringSub函数 不存在 执行次数 的限制:
  1. for(i=1;i<2798;i+=1){
  2.     for(j=1;j<433;j+=1){
  3.         StringSub(p[i],j,j);
  4.     }
  5. }
复制代码

(3) 不会出现溢出的代码2,说明 StringSub函数 不存在 返回值逻辑判断次数 的限制:
  1. //--------------------------------------------------------------------------------
  2. // 以单位作为像素点,使用 "替换单位"函数 播放 Bad Apple!!
  3. //--------------------------------------------------------------------------------
  4. t1=0.0625;
  5. // 每一帧停留时间
  6. for(i=1;i<2798;i+=1){
  7.     for(j=1;j<433;j+=1){
  8.         if(StringSub(p[i],j,j)=="0"){
  9. // 直接使用 StringSub函数 的返回值进行逻辑判断,不再使用一个二维数组作为媒介,避免在赋值给二维数组时溢出
  10.             libNtve_gf_ReplaceUnit(RegionGetAttachUnit(RegionFromId(j)), "ZakoomCrystalFragment", libNtve_ge_ReplaceUnitOptions_NewUnitsDefault);
  11.             RegionAttachToUnit(RegionFromId(j), libNtve_gf_LastReplacedUnit(), Point(0.0, 0.0));
  12.         }
  13.         else{
  14.             libNtve_gf_ReplaceUnit(RegionGetAttachUnit(RegionFromId(j)), "KorhalKeystone", libNtve_ge_ReplaceUnitOptions_NewUnitsDefault);
  15.             RegionAttachToUnit(RegionFromId(j), libNtve_gf_LastReplacedUnit(), Point(0.0, 0.0));
  16.         }
  17.     }
  18.     Wait(t1, c_timeReal);
  19. }
复制代码

回复

使用道具 举报

发表于 2020-8-26 13:03:11 | 显示全部楼层
本帖最后由 Nostalie 于 2020-8-26 13:26 编辑

应该是超时了。(超步数)随便啥动作都有执行次数限制。不是stringsub的问题。
分割一下。
用多个触发器执行或者用同个触发器执行多次。(i的起始值和结束值用全局变量替代。每次加就行了)(不要调用函数写。因为调用函数的时间会算在主触发器里。)
回复

使用道具 举报

发表于 2020-8-26 13:23:51 | 显示全部楼层
本帖最后由 Nostalie 于 2020-8-26 13:28 编辑

其实我很好奇。你编码表咋搞的。
用啥工具怎么搞的
可以教我嘛,,,

点评

编码表获取方法: 1、用PR或者AE把《Bad Apple!!》原版视频输出为图片序列。由于PR只支持常规帧率输出,不支持16帧的特殊帧率输出,所以以下以AE举例说明: (1) 将视频拖入AE渲染轨道内,点击输出模式,输出格  详情 回复 发表于 2020-9-6 14:36
回复

使用道具 举报

发表于 2020-8-26 19:45:52 | 显示全部楼层
1.jpg

2.jpg

显然并不是全局有执行次数限制,应该是其他地方出了问题,比如超时之类的。
回复

使用道具 举报

发表于 2020-8-26 20:01:10 | 显示全部楼层
另,建议每两帧时间间隔是0.0625游戏时间秒,也就是说每秒16帧,否则会和游戏运算周期不吻合。间隔0.125游戏时间秒也行,但是帧率太低,画面看起来会跳。
回复

使用道具 举报

发表于 2020-8-28 00:42:17 | 显示全部楼层
顺便一提的是,使用等待真实时间并无法让你跳过游戏周期的限制。在触发器里无论你怎么等待,最少也得等待半个周期也就是0.03125秒
回复 1 0

使用道具 举报

 楼主| 发表于 2020-9-6 14:36:42 | 显示全部楼层
本帖最后由 枪兵打巨像 于 2020-9-6 22:41 编辑
Nostalie 发表于 2020-8-26 13:23
其实我很好奇。你编码表咋搞的。
用啥工具怎么搞的
可以教我嘛,,,

编码表获取方法:

1、用PR或者AE把《Bad Apple!!》原版视频输出为图片序列。由于PR只支持常规帧率输出,不支持16帧的特殊帧率输出,所以以下以AE举例说明:

(1) 将视频拖入AE渲染轨道内,点击输出模式,输出格式选择"JPEG Sequence",分辨率设定为80*60(根据实际需要设定)↓↓↓

BA Code 002.jpg


(2) 点击渲染设置,将帧率设定为16(根据实际需要设定)↓↓↓

BA Code 001.jpg


(3) 设定图片序列命名规则,选择图片输出路径,最后点击"Render"输出图片序列 ↓↓↓

BA Code 004.jpg


(4) 输出的图片序列如下所示,按16帧的帧率,最终输出了3504张帧画面 ↓↓↓

BA Code 01.jpg


2、使用Matlab的 rgb2gray函数 处理图片序列,遍历每一张帧画面的所有像素点,获取像素点的灰度值,输出编码表。
     如果灰度值大于200,则输出"0",否则输出"1"。Matlab代码如下 ↓↓↓
  1. str='C:\\Picture queue\picture queue 4\BA';
  2. FID=fopen('C:\\Pixel\BA4.txt','a+');

  3. for i=1:10
  4.     I=imread([str,'000',num2str(i-1),'.jpg']);
  5.     I1=rgb2gray(I);
  6.     for i1=1:60
  7.        for i2=1:80
  8.            if(I1(i1,i2)>200)
  9.                fprintf(FID,'0 ');
  10.            else
  11.                fprintf(FID,'1 ');
  12.            end
  13.        end
  14.        fprintf(FID,'\r\n');
  15.    end
  16. end

  17. for i=11:100
  18.     I=imread([str,'00',num2str(i-1),'.jpg']);
  19.     I1=rgb2gray(I);
  20.     for i1=1:60
  21.        for i2=1:80
  22.            if(I1(i1,i2)>200)
  23.                fprintf(FID,'0 ');
  24.            else
  25.                fprintf(FID,'1 ');
  26.            end
  27.        end
  28.        fprintf(FID,'\r\n');
  29.    end
  30. end

  31. for i=101:1000
  32.     I=imread([str,'0',num2str(i-1),'.jpg']);
  33.     I1=rgb2gray(I);
  34.     for i1=1:60
  35.        for i2=1:80
  36.            if(I1(i1,i2)>200)
  37.                fprintf(FID,'0 ');
  38.            else
  39.                fprintf(FID,'1 ');
  40.            end
  41.        end
  42.        fprintf(FID,'\r\n');
  43.    end
  44. end

  45. for i=1001:3504
  46.     I=imread([str,num2str(i-1),'.jpg']);
  47.     I1=rgb2gray(I);
  48.     for i1=1:60
  49.        for i2=1:80
  50.            if(I1(i1,i2)>200)
  51.                fprintf(FID,'0 ');
  52.            else
  53.                fprintf(FID,'1 ');
  54.            end
  55.        end
  56.        fprintf(FID,'\r\n');
  57.    end
  58. end

  59. sta=fclose(FID);
复制代码


3、Matlab输出的文本格式编码表 ↓↓↓

BA Code 03.jpg


4、将文本格式的编码表导入Excel,进行后续处理 ↓↓↓

BA Code 04.jpg


5、使用Excel VBA将编码表转化为Galaxy字符串。
     由于Galaxy字符串的长度限制为2045个字符,而每一帧有80*60=4800个"0/1"字符编码,所以设定每一个字符串存储每一帧1/3的字符编码,即1600个字符编码。
     Excel VBA代码如下 ↓↓↓
  1. Sub GalaxyPixel()

  2. Dim i As Long
  3. Dim j As Long
  4. Dim k As Long
  5. Dim n1 As Long
  6. Dim n2 As Long
  7. Dim n3 As Long
  8. Dim Pixel As Long
  9. Dim PixelArray As String

  10. For k = 1 To 3504
  11.     PixelArray = ""
  12.     For i = 1 To 20
  13.         For j = 1 To 80
  14.                 n1 = 3 * k - 2
  15.                 Pixel = Sheet1.Cells((k - 1) * 60 + i, j)
  16.                 PixelArray = PixelArray & Pixel
  17.         Next j
  18.     Next i
  19.     Sheet3.Cells(n1, 1) = "p1[" & k & "]=""" & PixelArray & """;"
  20. Next k

  21. For k = 1 To 3504
  22.     PixelArray = ""
  23.     For i = 21 To 40
  24.         For j = 1 To 80
  25.                 n2 = 3 * k - 1
  26.                 Pixel = Sheet1.Cells((k - 1) * 60 + i, j)
  27.                 PixelArray = PixelArray & Pixel  
  28.         Next j
  29.     Next i
  30.     Sheet3.Cells(n2, 1) = "p2[" & k & "]=""" & PixelArray & """;"
  31. Next k

  32. For k = 1 To 3504
  33.     PixelArray = ""
  34.     For i = 41 To 60
  35.         For j = 1 To 80
  36.                 n3 = 3 * k
  37.                 Pixel = Sheet1.Cells((k - 1) * 60 + i, j)
  38.                 PixelArray = PixelArray & Pixel
  39.         Next j
  40.     Next i
  41.     Sheet3.Cells(n3, 1) = "p3[" & k & "]=""" & PixelArray & """;"
  42. Next k

  43. End Sub
复制代码


6、Excel VBA输出的Galaxy字符串,可以直接复制到Galaxy编辑器中使用 ↓↓↓

BA Code 06.jpg


7、最后放一下在星际争霸2上的成品效果吧 ↓↓↓
     萨尔那加神器版:https://www.bilibili.com/video/BV1EA411n7dB/
     高能瓦斯版:https://www.bilibili.com/video/BV1mT4y1L7ZD/

Bad Apple!! 星际争霸2萨尔那加神器版 80×60 16FPS.mp4_000104.951.jpg
Bad Apple!! 星际争霸2高能瓦斯版 80×60 16FPS.mp4_000104.382.jpg
回复

使用道具 举报

发表于 2020-9-9 18:18:21 | 显示全部楼层
点赞!点赞!点赞!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-11-21 20:34 , Processed in 0.155190 second(s), 32 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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