Keep your place in this quest

Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.

在上一课中,您了解了如何使用 Python 控制游戏运行中的实体。但 Cave 中的 Python 不仅限于运行游戏时使用。您还可以用它创建编辑器工具,帮助您更快地构建游戏。

这尤其有用,因为许多项目中会涉及重复性任务。例如,您可能经常放置敌人、创建检查点、整理文件夹、测试数值或检查场景数据。与其每次手动完成,不如创建一些小工具来自动化部分工作流程。您甚至可以创建更高级的编辑器,实现程序生成关卡、程序生成建筑等更多功能。

本课内容包括:

  • 游戏脚本与编辑器脚本的区别。
  • 编辑器工具的用途。
  • 编辑器标签工具的结构。
  • 为什么 #editoronly 很重要。
  • 何时值得创建自定义工具。

刚开始不必立即制作工具,但了解该系统的存在很有帮助。随着项目增长,这些功能将更显价值。

游戏脚本与编辑器工具

简而言之:

  • 游戏脚本 在游戏运行时执行。
  • 编辑器工具 在编辑器内运行,帮助您进行项目制作。
脚本类型 运行环境 示例
游戏脚本 运行模式和导出游戏。 玩家移动、敌人 AI、门、拾取物。
编辑器工具 Cave 编辑器。 关卡助手、批量重命名、场景检查器、程序建筑生成、放置工具。

例如,门开启脚本是游戏逻辑,因为玩家在游戏中会体验它;而沿走廊放置十把火炬的工具是编辑器逻辑,帮助搭建关卡,但不需包含在导出游戏中。

编辑器工具的用途

刚开始听到自定义工具,可能觉得只有大团队才需使用。

但即使是独立开发者,小工具也能减少重复的手工作业。如果您频繁执行相同任务,简单的编辑器脚本能让项目制作速度明显提升。

编辑器工具可以帮助:

  • 放置实体组。
  • 检查是否缺少必需组件。
  • 创建常用场景设置。
  • 打印调试信息。
  • 在不进入运行模式的情况下测试数值。
  • 帮助设计师调整游戏数据。

举例来说,假设您制作第三人称游戏,有许多敌人营地。与其每次手动创建相同文件夹结构,不如创一个工具,可自动添加“Enemy Group”、若干生成点和触发区域。


编辑器专有脚本

编辑器脚本通常以如下内容开头:

#editoronly

这告诉 Cave 该脚本仅供编辑器使用。

这很关键,因为编辑器工具可能调用仅在编辑器中有效的 API 或功能。您通常不希望关卡设计辅助或调试面板包含在最终游戏运行时。

这也帮助 Cave 确定启动游戏时应运行哪些脚本,忽略哪些脚本。默认情况下,它会运行所有脚本,若想忽略某脚本,需在首行加入此注释。

因此,若您写的脚本仅是为辅助 Cave 编辑器工作,务必设为编辑器专有。

编辑器标签工具

创建工具的一种常见方式是用编辑器标签

image.png

编辑器标签是 Cave 编辑器中的自定义面板。它有一个 draw() 方法,Cave 在该标签可见时会调用此方法,工具据此绘制按钮、文本、属性和其他控件。

一个极简编辑器标签示例:

#editoronly
import cave

class ExampleTab(cave.ui.DebugTab):
    def __init__(self):
        super().__init__()
        self.counter = 0

    def draw(self):
        cave.ui.text("这是一个示例工具。")
        cave.ui.separator()

        self.counter = cave.ui.prop("计数器", self.counter)

        if cave.ui.buttonDark("计数器+1"):
            self.counter += 1
            print("计数器增加了 +1")

这也是添加编辑器标签时的默认代码。点击属性标签中的该标签,然后切换到编辑器工具标签,会看到示例标签作为调试标签出现。只需注册或重载标签,它就会出现在界面中:

image.png

示例虽简单,但展示了基本思路:

  • cave.ui.DebugTab 创建自定义编辑器标签。
  • draw() 定义标签的显示内容。
  • cave.ui.text() 绘制文本。
  • cave.ui.prop() 绘制可编辑属性。
  • cave.ui.buttonDark() 创建按钮。
  • print() 用于向控制台输出信息。

这就是创建 Cave 编辑器自定义工具的简单方法。之后您可以用相同结构制作实用工具。

draw() 方法的含义

draw() 方法不同于游戏组件中的 start()

它会在工具可见期间反复调用,因为编辑器 UI 需要绘制和更新。draw() 内的代码应描述工具当前的界面。

例如:

def draw(self):
    cave.ui.text("关卡助手:")

    if cave.ui.buttonDark("创建敌人组"):
        print("点击了创建敌人组")

标签更新时按钮会被重绘,但 if 内的代码仅在用户点击按钮时执行。

这种模式在编辑器工具中非常常见。

一个实用工具案例

假设您正在制作关卡,常用这些基础文件夹:

  • Environment
  • Enemies
  • Gameplay Triggers
  • Lighting
  • Audio
  • Debug Helpers

可以制作一个名为“Create Level Folders”的编辑器工具按钮。点击时,它会在当前场景创建这些文件夹实体。注意:场景图中的文件夹只是没有组件的实体。

虽然看似微小,类似这样的工具让大型项目更易管理,也能帮助您遵守项目规范,无需每次都手动操作。


编辑器组件

有时,您需要将游戏逻辑和编辑器逻辑混合。例如,您可能希望在实体上附加组件,同时运行编辑器逻辑,用于显示调试信息或调试范围指示球。此时,应使用 cave.EditorComponent,而非 cave.Component

当实体需要特殊编辑器行为,但该行为不应成为游戏正式内容时,这很有用。

例子:

  • 生成点在编辑器中绘制辅助信息。
  • 触发区域暴露调试控件。
  • 关卡标记验证配置是否正确。

关键是编辑器脚本专注于辅助游戏制作工作流,游戏脚本专注于游戏自身。

重要提示:

在此情形中,行为与普通组件略有不同,因为编辑器组件有一个编辑器更新方法,该方法会在编辑器运行且游戏未运行时每帧调用。更重要的是,该组件将随实体一同注册、初始化并启动,无论是否处于运行模式。因此,如果您在该组件的 start 方法内写逻辑,即使不在运行模式,逻辑也会执行。

这可能带来风险,例如:若您在编辑器组件的 start 方法里写删除场景中所有实体的逻辑,那么您的游戏会在编辑器中被彻底删除(无法撤销)。这不是漏洞,而是设计使然,请务必注意。

更安全的做法是使用 Python 代码组件(Python Code Component),它同样有编辑器更新方法,且编辑器中不会调用 start 和 end 方法(不会干扰)。可以查看 Cave 初始项目中的 Enemy,它用此组件绘制敌人周围的调试球,指示其可移动半径。是学习的好途径。


何时应制作工具?

不要为每个细小操作都做自定义工具。

制作工具应解决实际工作流问题,例如:

  • 反复执行同一任务。
  • 易被遗忘的设置步骤。
  • 需对场景进行验证。
  • 设计师需要更清晰的界面调整数值。
  • 原型测试需快速调试按钮。

对初学者来说,先手动制作游戏对象更好,理解步骤后再自动化重复乏味的部分。

您应记住的

Cave 中的 Python 既可用于游戏运行逻辑,也可用于编辑器工具制作。

游戏脚本控制游戏运行时发生的事;编辑器脚本则协助您在 Cave 编辑器内构建、检查、调试或整理项目。

制作第一个游戏时不必用上编辑器工具,但项目扩展后它们非常强大。今天节省五分钟的小工具,未来可能节省数小时。