{ "180": "事件与转换", "181": "LimboHSM 自带一套事件系统,有助于把状态转换与状态实现解耦。一个转换与特定的事件、起始状态和目标状态相关联,当该事件被派发时,转换会自动执行。", "182": "要注册一个转换并把它与特定事件关联,可以使用 LimboHSM.add_transition 方法:", "183": "在这个示例中,我们注册了一个从 <1/> 到 <2/> 的转换,它在 <3/> 事件被派发时发生。", "184": "转换也可以不与任何特定的起始状态关联:", "185": "事件通过 LimboState.dispatch 方法派发。需要注意的是,该方法可以从状态机层级中的任何位置调用,也可以在状态机之外调用。事件会从叶状态向根状态传播。这意味着,如果某个事件被某个状态消费掉,它就不会再传播到其父状态。", "186": "状态还可以定义事件处理器,即对特定事件做出反应的方法。这些事件处理器通常不会导致状态转换;它们只是状态对特定事件做出反应的一种机制。你可以用 LimboState.add_event_handler 方法在状态中注册事件处理器:", "187": "如果事件处理器返回 <1/>,该事件将被视为已被消费,不会再继续传播,也不会导致状态转换。", "188": "状态的结构", "189": "把行为树与状态机结合使用", "190": "BTState 是 LimboHSM 中一种特殊的状态节点,它可以承载一个行为树。当 BTState 处于活动状态时,它每帧都会执行所承载的行为树,实际上就是把该行为树当作它的实现。", "191": "这样你就可以把行为树的强大能力与状态机的结构与控制结合起来。行为树非常适合定义复杂的层次化行为,而状态机则擅长管理不同行为之间的流转与转换。", "192": "创建好 LimboHSM 之后,就可以为给定的 LimboHSM 创建一个 BTState:", "193": "单文件状态机配置", "194": "在某些情况下,例如做原型或参加 Game Jam 时,把状态机代码放在单个文件里更实用。针对这类情况,LimboHSM 支持委托(delegation),并提供链式方法以便更轻松地完成配置。下面用一个实际的代码示例来说明:", "195": "重要类", "196": "LimboAI 中引入了很多类。下面列出你应该了解的最重要的那些:", "197": "BTTask", "198": "继承:BT", "199": "被继承:BTAction、BTComment、BTComposite、BTCondition、BTDecorator", "200": "所有 BehaviorTree 任务的基类。", "201": "说明", "202": "所有 BehaviorTree 任务的基类。任务是 BehaviorTree 中的基本积木块,代表某个具体行为或控制流。通过按层次组合和嵌套任务,可以构建出复杂的行为。", "203": "任务可以是以下类型之一:动作、条件、组合或装饰器。每种任务类型都有对应的子类:BTAction、BTCondition、BTDecorator、BTComposite。", "204": "任务通过 _tick 方法执行工作并返回状态。状态值定义在 Status 中。任务可以用 _setup 方法初始化。另见 _enter 与 _exit。", "205": "注意:不要直接继承 BTTask 来实现你自己的任务,而应继承上面提到的某个子类型。", "206": "属性", "207": "agent", "208": "Blackboard", "209": "blackboard", "210": "custom_name", "211": "elapsed_time", "212": "scene_root", "213": "Status", "214": "status", "215": "方法", "216": "_enter() <2/>", "217": "_exit() <2/>", "218": "_generate_name() <2/> <3/>", "219": "_get_configuration_warnings() <2/> <3/>", "220": "_setup() <2/>", "221": "_tick(delta: <2/>) <3/>", "222": "abort()", "223": "add_child(task: BTTask)", "224": "add_child_at_index(task: BTTask, idx: <3/>)", "225": "BTTask", "226": "clone() <2/>", "227": "BehaviorTree", "228": "editor_get_behavior_tree()", "229": "execute(delta: <2/>)", "230": "get_child(idx: <2/>) <3/>", "231": "get_child_count() <2/>", "232": "get_child_count_excluding_comments() <2/>", "233": "get_index() <2/>", "234": "get_parent() <2/>", "235": "get_root() <2/>", "236": "get_task_name()", "237": "has_child(task: BTTask) <3/>", "238": "initialize(agent: <2/>, blackboard: Blackboard, scene_root: <4/>)", "239": "is_descendant_of(task: BTTask) <3/>", "240": "is_root() <2/>", "241": "next_sibling() <2/>", "242": "print_tree(initial_tabs: <2/> = 0)", "243": "remove_child(task: BTTask)", "244": "remove_child_at_index(idx: <2/>)", "245": "属性说明", "246": "<1/> agent 🔗", "247": "<1/> set_agent(value: <2/>)", "248": "<1/> get_agent()", "249": "agent 是 BehaviorTree 实例的上下文对象。通常它是使用 BehaviorTree 资源的 BTPlayer 节点的父节点。", "250": "Blackboard blackboard 🔗", "251": "Blackboard get_blackboard()", "252": "提供对 Blackboard 的访问。黑板用于在同一 BehaviorTree 的各任务之间共享数据。", "253": "更多信息见 Blackboard。", "254": "<1/> custom_name = <2/> 🔗", "255": "<1/> set_custom_name(value: <2/>)", "256": "<1/> get_custom_name()", "257": "用户为任务提供的名称。如果不为空,编辑器会用它来表示该任务。见 get_task_name。", "258": "<1/> elapsed_time 🔗", "259": "<1/> get_elapsed_time()", "260": "自任务被“进入”以来所经过的时间。见 _enter。", "261": "当任务不处于 <2/> 状态时返回 <1/>。", "262": "<1/> scene_root 🔗", "263": "<1/> get_scene_root()", "264": "行为树所在场景的根节点(例如 BTPlayer 节点的拥有者)。可用于获取 <2/> 引用。", "265": "示例:", "266": "Status status 🔗", "267": "Status get_status()", "268": "_tick 返回的最后一次执行 Status。", "269": "方法说明", "270": "<1/> _enter() <2/> 🔗", "271": "当任务被“进入”时调用,即任务在不具有 <1/> status 的情况下被执行时。", "272": "在执行顺序上,它先于 _tick 被调用。当主要工作开始前需要做准备时使用此方法,通常是在任务需要不止一个 tick 才能完成时。另见 execute。", "273": "<1/> _exit() <2/> 🔗", "274": "当任务被“退出”时调用,即在 _tick 返回 <2/> 或 <3/> 状态之后。另见 execute。", "275": "<1/> _generate_name() <2/> <3/> 🔗", "276": "在未设置 custom_name 时,调用它来为任务生成显示名称。见 get_task_name。", "277": "<1/> _get_configuration_warnings() <2/> <3/> 🔗", "278": "此方法返回的字符串会作为警告消息显示在行为树编辑器中。任何重写了此方法的任务脚本都必须在文件顶部包含 <1/> 注解。", "279": "<1/> _setup() <2/> 🔗", "280": "在初始化阶段调用,用于初始化任务。它只会在任务第一次执行 tick 之前被调用一次。借助这个方法,你可以在任务开始执行之前为它设置所需的状态或配置。", "281": "Status _tick(delta: <2/>) <3/> 🔗", "282": "当任务被“tick”时调用,也就是在更新过程中由 BTPlayer 或 BTState 执行它时。", "283": "返回定义在 Status 中的执行状态。", "284": "注意:任务通过实现这个方法来执行其主要功能。", "285": "<1/> abort() 🔗", "286": "递归地重置该任务及其子任务。如果任务处于 <1/> 状态,它会被退出,并且其状态被重置为 <2/>。", "287": "<1/> add_child(task: BTTask) 🔗", "288": "添加一个子任务。<1/> 会被放到子任务列表的末尾。", "289": "<1/> add_child_at_index(task: BTTask, idx: <3/>) 🔗", "290": "添加一个子任务。<1/> 会被放到子任务列表中的 <2/> 位置。", "291": "BTTask clone() <2/> 🔗", "292": "复制该任务及其子任务,并复制导出的成员。出于效率考虑,子资源是共享的,但 BBParam 的子类型例外,它们总是会被复制。编辑器用它来实例化 BehaviorTree,以及复制粘贴任务。", "293": "BehaviorTree editor_get_behavior_tree() 🔗", "294": "返回拥有此任务的行为树。仅在编辑器中可用。", "295": "Status execute(delta: <2/>) 🔗", "296": "执行该任务。执行遵循特定的顺序:", "297": "如果任务当前的 status 不是 <2/>,会先调用 _enter 方法。", "298": "接着调用 _tick 方法来执行任务的工作。", "299": "如果 _tick 方法返回 <2/> 或 <3/> 状态,接下来会调用 _exit 方法,作为执行清理的一部分。", "300": "BTTask get_child(idx: <2/>) <3/> 🔗", "301": "通过指定索引返回一个子任务。", "302": "<1/> get_child_count() <2/> 🔗", "303": "返回子任务的数量。", "304": "<1/> get_child_count_excluding_comments() <2/> 🔗", "305": "返回子任务的数量,不把 BTComment 任务计算在内。", "306": "<1/> get_index() <2/> 🔗", "307": "返回该任务在行为树分支中的位置。如果该任务不属于任务树(也就是没有父任务),则返回 <1/>。", "308": "BTTask get_parent() <2/> 🔗", "309": "返回该任务的父任务。", "310": "BTTask get_root() <2/> 🔗", "311": "返回行为树的根任务。", "312": "<1/> get_task_name() 🔗", "313": "此方法返回的字符串用于在编辑器中表示该任务。", "314": "除非设置了 custom_name,否则会调用 _generate_name 方法为任务生成显示名称。", "315": "<1/> has_child(task: BTTask) <3/> 🔗", "316": "如果 <2/> 是此任务的子任务,则返回 <1/>。", "317": "<1/> initialize(agent: <2/>, blackboard: Blackboard, scene_root: <4/>) 🔗", "318": "初始化该任务。为它赋值 agent 和 blackboard,并对该任务及其子任务调用 _setup。", "319": "该方法会对每个子任务递归调用。<1/> 应当是行为树所在场景的根节点(例如包含该行为树的节点的拥有者)。", "320": "<1/> is_descendant_of(task: BTTask) <3/> 🔗", "321": "如果此任务是 <2/> 的后代,则返回 <1/>。换句话说,此任务必须是 <3/> 的子任务,或者是它的子任务、孙任务之一。" }