Skip to content

性能优化

前言

文字游戏的性能问题,通常不会表现为“掉帧”,而是每次输入后要等一两秒才响应。这一篇讲讲卡顿从哪来、怎么找、怎么改。

教程依赖

本教程假设您已完成入门教程完整实战:打工养成

先测量,再优化

不要凭感觉猜。Emuera 提供了计时函数:

erb
#Dim T0 = 0
#Dim T1 = 0
GETMILLISECOND
T0 = RESULT

; ……要测量的处理……

GETMILLISECOND
T1 = RESULT
PRINTFORML 耗时 {T1 - T0} 毫秒

先量出到底是哪一段慢,再动手。大多数时候,瓶颈都集中在少数几个地方。

瓶颈一:循环

这是最常见的性能来源。几条经验:

用内置命令代替手写循环

同样的“批量操作”,内置命令通常快得多:

需求手写循环推荐
给数组批量赋值FOR 逐个赋值VARSET / CVARSET
排序自己实现冒泡 / 快排ARRAYSORT
复制数组FOR 逐个复制ARRAYCOPY
平移 / 删除元素FOR 手动挪动ARRAYSHIFT / ARRAYREMOVE

例如给 FLAG 全部清零,写 VARSET FLAG, 0 远比 FOR … NEXT 快。

减少循环内的重复计算

把不变的东西挪到循环外面:

erb
; 不好:每次循环都重复求 VARSIZE
FOR I, 0, VARSIZE("FLAG")
  ...
NEXT

; 更好:只在循环外求一次
#Dim N = 0
N = VARSIZE("FLAG")
FOR I, 0, N
  ...
NEXT

尽量早退出

找到结果就用 BREAK / RETURN 结束,别把整个数组都遍历完。

瓶颈二:字符串

  • 少在循环里做大量的 + 拼接,累积成一段再一次性输出;
  • 避免在循环里反复调用 STRLEN / STRLENS 等度量函数,能提前算好就提前算;
  • 需要重复显示同一段内容时,缓存到字符串变量里。

瓶颈三:绘制

  • フレーム毎秒(每秒帧数)越小,绘制越省;牺牲一点动画流畅度换取响应速度,往往是值得的;
  • 不需要每帧更新时,用 REDRAW 0 暂停自动重绘,只在需要输入时刷新;
  • 避免在循环里反复 CLEARLINE + 重绘整屏。

耗时任务:分批 + AWAIT

如果某一步确实要算很久(例如初始化大量数据),不要让它“卡死”界面。可以边算边显示进度:

erb
REDRAW 0
FOR I, 0, 100
  PRINTSL "处理中…… " + TOSTR(I) + "% 完成"
  AWAIT
  CLEARLINE 1
  ; 这一批的处理
NEXT

AWAIT 会暂停 ERB 执行、让 Windows 处理消息,避免窗口“无响应”。但也不要调用得过于频繁,否则反而变慢。

一个反直觉的建议

可读性优先于微优化。

绝大多数文字游戏,经过上面的调整后性能都绰绰有余。为了省几毫秒把代码写得晦涩难懂,通常是得不偿失的——真正需要死抠性能的场景,其实很少。

小结

  • 先用 GETMILLISECOND 测量,再优化;
  • 循环是主要瓶颈:优先用内置的批量命令;
  • 把循环内不变的计算挪出去,尽早 BREAK / RETURN
  • 减少字符串拼接与重复度量;
  • REDRAWフレーム毎秒 控制绘制开销;
  • 耗时任务分批处理并配合 AWAIT

相关链接

GPL-3.0+ Licensed