跳转到内容

框架结构详解

本节概述了 LightScript 集成的基础结构,涵盖关键技术要求、真实案例、命名规范和效率技巧。它详细介绍了更新循环、计量器行为、效果触发逻辑,并重点指出了常见的陷阱。无论您是在调试、从头构建还是维护他人的代码,本指南都将清晰度、稳定性和性能作为高质量集成的核心标准。

本节从维护角度快速概述如何设置 LightScript,重点关注问题通常发生的位置以及如何发现和修复错误。我们将从一个理想的 LightScript 结构的简要演练开始,让您熟悉代码,然后介绍故障排除,最后是常见问题解答。

基本框架需要 <head><body><script> 三个部分。所有计量器和用户控件声明放在 <head> 内。所有 canvas 声明属于 <body>。其他所有内容应放在 <script> 部分。

<head> 是任何 LightScript 中最关键和最复杂的部分之一。此处有问题的用户控件或计量器可能导致崩溃循环,或禁用其自身以及在其后声明的任何计量器。

创建计量器时,您需要确保:

  • 语法完美(避免崩溃和计量器损坏)
  • 没有重复的计量器名称(重复项会被覆盖)
  • 没有计量器超出屏幕边界(会导致崩溃和错误)
  • 计量器中没有缺少或多余的选项(会导致崩溃)
  • 所有计量器都包含分辨率调整(确保一致的行为)

关于分辨率,最常见的宽高比为:

  • 16:9(3840x2160、2560x1440、1920x1080、1600x900、1366x768、1360x768、1280x720)
  • 16:10(2560x1600、1920x1200、1680x1050、1440x900、1280x800)
  • 21:9(5120x2160、3440x1440)

默认情况下,我们使用分辨率 2560x1440

所有 LightScript 必须支持 16:916:1021:9 宽高比。虽然 4:3 在我们的用户群中占比不大,但为了未来的兼容性仍应予以考虑。

以下是具有多个分辨率设置的计量器结构示例:

计量器的默认位置和大小适用于同一宽高比内的所有其他分辨率。例如,如果您最初将计量器调整为适用于 1600x900,该计量器应在所有其他 16:9 分辨率上正常工作。但存在例外情况。Fortnite 甚至在同一宽高比内也有多个不同的计量器位置,某些宽高比本身也可能具有误导性。例如,1366x768 是全球常见的分辨率,通常被列为 16:9,但实际上并不是真正的 16:9 比例,这并不罕见。同样,21:9 等超宽比例很少与其标称尺寸相符。根据我作为集成开发者的经验,尽管分辨率被标记为 21:9,我从未遇到过确切的 21:9 分辨率。因此,每个超宽分辨率都必须单独创建、测试和配置。

所有调整必须放在开放的 <meta> 和关闭的 </meta> 标签之间,否则它们将不起作用。如果您的默认计量器基于 16:9 且在这些分辨率上表现一致,则无需为其他 16:9 分辨率添加调整。但是,您必须为其他宽高比(如 16:1021:9)中的每个分辨率添加条目,即使比例是一致的。

最后,除 OCR 计量器外,每个计量器都需要 HSL 范围来触发。以下因素可能使这些范围变得复杂:

  • 透明 UI 元素
  • 颜色区域中的渐变
  • 屏幕扭曲效果
  • 游戏内菜单打开
  • 每个分辨率的 UI 调整
  • 手柄与键盘使用
  • 视频录制,可能引入与压缩相关的像素错误

HSL 和标准化坐标的基本说明已在我们的开发者文档中介绍,此处不再重复。测试这些计量器将在”识别问题”部分讨论,但有一点需要强调:验证所有计量器完美运行所需的测试量按以下公式计算:(计量器数量)×(分辨率调整数量)×(游戏模式数量)×(可玩角色数量)×(平均游戏时长)。这很容易累积到每个游戏数小时的验证时间,尤其是在没有练习模式或其他解决方法时。

保持计量器高效,我们的标准是完美。

<body> 标签是声明实际 canvas 元素的地方。它的外观应始终大致如以下示例所示。实际 canvas 的 id 可以更改,但确保在脚本中正确获取它。

节省时间——直接复制粘贴这段代码。

此标签内必须发生四件事情(适用于每个集成):

  • 获取 canvas 并用于创建 2D 上下文。
  • 初始更新循环设置计量器值,然后无限循环地调用自身以维持这些值。
  • 更新循环保持用户控件变量的更新。
  • 计量器稳定时执行其回调函数。

我们已经设置了基本代码框架。下一步是从头到尾演练触发效果的执行循环。

  1. 视频游戏 UI 以彩色条、按钮、文本框等形式显示信息。SignalRGB 每秒多次捕获此数据,但实际捕获速率在很大程度上取决于代码的效率。明确地说,一个循环或未声明的变量可以破坏整个脚本,甚至导致 SignalRGB 崩溃。更糟糕的是,很容易编写出技术上可以运行但效率极低的代码,导致仅以 1-2 FPS 的速度捕获信息。
  2. <head> 中声明的每个计量器必须尽可能小而高效,以减少开销。尽早并频繁地进行计算;占据 25% 屏幕的计量器永远不会高效。对于 OCR 计量器,捕获单个字母而不是整个单词。对于血条和法力条,只监视必要的片段。保持计量器尽可能小。
  3. 计量器捕获信息,每次循环都会刷新。
  4. 前面我们介绍了 Meter 类定义,它存储计量器数据并在信息数组稳定时触发回调。在脚本顶部,在一个代码块中声明所有 Meter。您可以对它们进行组织或按字母顺序排列;只是不要将它们分散在数千行代码中。您最终需要调整稳定性值,如果还需要记住将它们放在哪里,那就是在浪费时间。
  5. 在更新函数内,这些计量器每次循环都会从屏幕读取逻辑接收值。它们的内部逻辑评估稳定性,并在稳定时触发其关联的回调函数。
  6. 这些回调函数应在脚本中声明,但在更新函数之外。在其中检查 Meter 值(valuedecreasedincreaseddiff)的状态,并使用这些状态来确定是否播放效果动画。以这种方式构建代码,而不是将所有内容直接放在更新循环内,使我们能够构建可扩展的集成。

现在您已经有了基本概念,我将快速演练一个真实案例的循环。

  • 我正在玩游戏英雄联盟,它用明亮的黄色高亮显示可用的技能。
  • 每次循环,特定的技能计量器都会将此颜色识别为值 “1”,因为它完全通过了计量器的 HSL 范围。
  • 这个 “1” 被传递给附加到屏幕读取计量器的 Meter 实例,并插入该 Meter 的信息数组中。
  • 如果该数组中的每个值都是 “1”,则认为它是稳定的,并将激活附加的效果回调函数。如果每个值都是 “0”“.1”,该回调函数也会被激活;Meter 只关心稳定性。这里有一个重要注意事项:如果 Meter 持续以相同值稳定,回调函数不会被持续激活——只有具有值的稳定性才会激活回调。
  • 一旦执行回调函数,我们就会进行一些条件检查——在这种情况下,我们只需检查 Meter.value 是否为 “0”,表示技能已被使用。
  • 由于 Meter value“1”,我们不通过此检查,不会播放技能效果。
  • 几秒钟后,我激活技能,按钮周围的黄色高亮消失。
  • 新的计量器值为 0,被传递给其 Meter 类。
  • 达到稳定后,回调激活,通过我们的条件判断,播放技能效果。延迟完全取决于 Meter 数组的长度,这是在声明时设置的。更长的数组意味着更多延迟和更少的误触发,因此请确保进行测试直到找到良好的平衡点。

屏幕读取计量器应有简单、清晰和描述性的名称,始终以小写字母开头。将血条计量器命名为 “healthBar” 非常好。当两个计量器追踪同一区域中的不同颜色时,将它们命名为 “healthBarRed”“healthBarGreen” 也很好。但将一个只在某个英雄终极技能效果期间出现的小计量器命名为 “hrO21_yes” 只会给任何其他试图修复代码的人带来痛苦。弄清楚一个命名不当的小计量器在追踪什么,如果运气不好,可能需要花一个小时盯着单个像素,所以请不要这样做。

Meter 类实例应大写并以 Meter 一词结尾。像 “Q_Meter”“TookDamageMeter”“TowerDestroyedMeter” 这样的示例都完全没问题。这些应与在 <head> 部分声明的计量器明显区分。

效果函数也应尽可能简单和描述性地命名。某些游戏有数百个这样的函数,其他游戏可能只有不到十个。如果多个英雄有独特的技能,请将英雄的名字作为前缀,如 “SonaQ”“ChamberE”“AshUlt”。例如,在英雄联盟中,有 “DragonEffect”“TowerEffect”“Q_Effects” 等函数,它们包含多个条件并被几个计量器使用。因此,这种命名方式也有助于针对规模进行优化。

请勿拼写错误单词。如果您不确定如何拼写某词,请查阅。无论是谁在处理代码,也无论过了多少时间,名称必须清晰易读。按字母顺序组织名称有助于快速查找,特别是如果您会经常编辑该部分的话。虽然这种级别的组织并不是代码运行的必要条件,但对我们的维护开发者来说会有很大的不同。