{"id":13675050,"url":"https://github.com/esengine/BehaviourTree-ai","last_synced_at":"2025-04-28T23:30:28.955Z","repository":{"id":38270166,"uuid":"167498226","full_name":"esengine/BehaviourTree-ai","owner":"esengine","description":"基于ecs-framework开发的AI（BehaviourTree、UtilityAI、FSM）系统。适用于egret/laya/cocos","archived":false,"fork":false,"pushed_at":"2023-03-04T23:57:51.000Z","size":14315,"stargazers_count":100,"open_issues_count":9,"forks_count":31,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-17T20:08:44.443Z","etag":null,"topics":["behaviourtree","cocos","egret","fsm","laya","selector"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/esengine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-01-25T06:40:46.000Z","updated_at":"2025-04-01T12:51:44.000Z","dependencies_parsed_at":"2024-01-17T05:31:26.602Z","dependency_job_id":null,"html_url":"https://github.com/esengine/BehaviourTree-ai","commit_stats":null,"previous_names":["esengine/egret-behaviourtree-ai"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esengine%2FBehaviourTree-ai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esengine%2FBehaviourTree-ai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esengine%2FBehaviourTree-ai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esengine%2FBehaviourTree-ai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/esengine","download_url":"https://codeload.github.com/esengine/BehaviourTree-ai/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251404405,"owners_count":21584088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["behaviourtree","cocos","egret","fsm","laya","selector"],"created_at":"2024-08-02T12:00:28.280Z","updated_at":"2025-04-28T23:30:23.947Z","avatar_url":"https://github.com/esengine.png","language":"JavaScript","readme":"# BehaviourTree、UtilityAI、FSM\n基于ecs-framework开发的AI（BehaviourTree、UtilityAI、FSM）系统，一套已经非常完整的系统。教程较少，可以自行看源代码来学习。\n\n## 目录结构\n\n- src `源目录`\n  - behaviourTree   `行为树主目录`\n    - actions `动作是行为树的节点。比如： 播放动画，触发事件等。`\n    - composites `Composites是行为树中的父节点，他们容纳一个或多个子节点，并以不同的方式执行。`\n    - conditionals `它们由IConditional接口标识。它们会检查游戏世界的某些情况，并返回成功或失败`\n    - decorators `装饰器可以通过各种方式修改子任务的行为，例如： 反转结果，运行知道失败等`\n  - utilityAI `实用AI主目录`\n    - actions `AI执行的操作`\n    - considerations `列出评估和行为清单。计算一个分数，用数字表示Action的有效使用情况。`\n    - reasoners `从附加的Reasoner的事项列表中选择最佳的事项。AI的根源`\n  - core    `egret核心扩展`\n  - test    `示例工程`\n    - utilityActions `实用AI示例目录`\n\n## 介绍\n\n### State Machine\n它实现 `状态作为对象` 模式。 StateMachine为每个状态使用单独的类，因此对于更复杂的系统而言，它是更好的选择。\n\n我们开始使用StateMachine来了解上下文的概念。 在编码中，上下文只是用于满足一般约束的类。 在Array\u003cstring\u003e中，字符串将是上下文类，即列表所基于的类。 使用所有其他的AI解决方案，您都可以指定上下文类。 它可能是您的敌人类，玩家类或包含与您的AI相关的任何信息（例如玩家，敌人列表，导航信息等）的帮助对象。\n\n这是一个显示用法的简单示例（为简洁起见，省略了State子类）： \n  \n```ts\n  // 创建一个状态机，该状态机将使用SomeClass类型的对象作为焦点，并具有PatrollingState的初始状态 \n  let machine = new SKStateMachine\u003cSomeClass\u003e( someClass, new PatrollingState() );\n  \n  // 我们现在可以添加任何其他状态 \n  machine.addState(new AttackState());\n  machine.addState(new ChaseState());\n  \n  // 通常在更新对象时调用此方法 \n  machine.update(es.Time.deltaTime);\n  \n  // 改变状态。 状态机将自动创建并缓存该类的实例（在本例中为ChasingState） \n  machine.changeState\u003cChasingState\u003e(ChasingState);\n```\n\n### Behavior Trees\n\n行为树由节点树组成。节点可以根据世界状态做出决策并执行操作。它包含一个BehaviorTreeBuilder类，它提供了一个用于设置行为树的API。BehaviorTreeBuilder是一种使行为树减少使用并快速启动的方法。\n\n#### Composites\n组合是行为树中的父节点。 他们有一个或多个子节点，并以不同的方式处理他们。 \n\n- Sequence\u003cT\u003e 一旦其子任务之一返回失败，则返回失败。 如果一个子任务返回成功，它将在树的下一帧顺序运行下一个子节点\n- Selector\u003cT\u003e 一旦其子任务之一返回成功，则返回成功。 如果子任务返回失败，则它将在下一帧顺序运行下一个子任务。 \n- Parallel\u003cT\u003e 运行每个子节点直到子节点返回失败。它不同于Sequence仅在于它在每帧都会运行所有子节点\n- ParallelSelector\u003cT\u003e 同Selector,除了它自身将在每帧都运行所有子节点\n- ParallelSequence\u003cT\u003e 同Sequence,除了它自身将在每帧都运行所有子节点\n- RandomSequence\u003cT\u003e 同Sequence，在执行前将子节点随机打乱后运行\n- RandomSelector\u003cT\u003e 同Selector, 在执行前将子节点随机打乱后运行\n\n#### Conditional\n条件是成功/失败节点。 它们由IConditional接口标识。 他们检查您的游戏世界的某些状况，并返回成功或失败。 它们本质上是特定于游戏的，因此框架仅提供一个开箱即用的通用条件，以及包装Function的辅助条件，因此您不必为每个条件创建单独的类。 \n  \n- RandomProbability\u003cT\u003e: 当随机概率高于指定的成功率时返回成功\n- ExecuteActionConditional\u003cT\u003e: 包装一个Func并未做Conditional执行。用于原型设计和避免为简单的条件创建单独的类。\n\n#### Decoration\n装饰器是具有单个子任务的包装器任务。 他们可以通过多种方式修改子任务的行为，例如反转结果，运行直到失败等。 \n\n- AlwaysFail\u003cT\u003e: 无论子结果如何，总是返回失败\n- AlwaysSuccedd\u003cT\u003e: 无论子结果如何，总是返回成功\n- ConditionalDecorator\u003cT\u003e: 包装条件，并且仅在满足条件时才运行其子项。\n- Repeater\u003cT\u003e: 重复其子任务指定次数\n- UntilFail\u003cT\u003e: 继续执行其子任务，直到返回失败\n- UntilSuccess\u003cT\u003e: 继续执行其子任务，直到返回成功\n- Inverter\u003cT\u003e: 反转子结果\n\n#### Action\n动作是行为树的叶子节点。 例如播放动画，触发事件等。 \n\n- ExecuteAction\u003cT\u003e: 包装一个Func并将其作为动作执行。\n- WaitAction\u003cT\u003e： 等待指定的时间\n- LogAction\u003cT\u003e：将字符串记录到控制台用于调试。\n- BehaviorTreeReference\u003cT\u003e:运行另一个行为树\n\n### 使用文档\n\n```typescript\nclass AiComponent{\n    private _tree: BehaviorTree\u003cAiComponent\u003e;\n    public state: State = new State();\n    private _distanceToNextLocation: number = 10;\n    public update(){\n        if (this._tree)\n            this._tree.tick();\n    }\n\n    public start(){\n        let builder = BehaviorTreeBuilder.begin(this);\n\n        builder.selector(AbortTypes.Self);\n\n        // 睡觉最重要\n        builder.conditionalDecoratorR(m =\u003e m.state.fatigue \u003e= State.MAX_FATIGUE, false);\n        builder.sequence(AbortTypes.LowerPriority)\n            .logAction(\"-- 累了,准备回家\")\n            .action(m =\u003e m.goToLocation(Locate.Home))\n            .logAction(\"-- 准备上床\")\n            .action(m =\u003e m.sleep())\n            .endComposite();\n\n        // 喝水第二重要\n        builder.conditionalDecoratorR(m =\u003e m.state.thirst \u003e= State.MAX_THIRST, false);\n        builder.sequence(AbortTypes.LowerPriority)\n            .logAction(\"-- 渴了! 准备喝水\")\n            .action(m =\u003e m.goToLocation(Locate.Saloon))\n            .logAction(\"-- 开始喝水\")\n            .action(m =\u003e m.drink())\n            .endComposite();\n\n        // 存钱第三重要\n        builder.conditionalDecoratorR(m =\u003e m.state.gold \u003e= State.MAX_GOLD, false);\n        builder.sequence(AbortTypes.LowerPriority)\n            .logAction( \"--- 背包满了，准备去银行存钱.\" )\n            .action( m =\u003e m.goToLocation( Locate.Bank ) )\n            .logAction( \"--- 开始存钱!\" )\n            .action( m =\u003e m.depositGold() )\n            .endComposite();\n\n        // 赚钱最后\n        builder.sequence()\n            .action(m =\u003e m.goToLocation(Locate.Mine))\n            .logAction(\"-- 开始挖矿！\")\n            .action(m =\u003e m.digForGold())\n            .endComposite();\n\n        builder.endComposite();\n\n        this._tree = builder.build();\n    }\n\n    private digForGold(): TaskStatus{\n        console.log(`开始金币增加: ${this.state.gold}.`);\n        this.state.gold++;\n        this.state.fatigue++;\n        this.state.thirst++;\n\n        if( this.state.gold \u003e= State.MAX_GOLD )\n            return TaskStatus.Failure;\n\n        return TaskStatus.Running;\n    }\n\n    private drink(): TaskStatus{\n        console.log(`开始喝水, 口渴程度: ${this.state.thirst}`);\n\n        if( this.state.thirst == 0 )\n            return TaskStatus.Success;\n\n        this.state.thirst--;\n        return TaskStatus.Running;\n    }\n\n    private sleep(): TaskStatus{\n        console.log(`开始睡觉, 当前疲惫值: ${this.state.fatigue}`);\n\n        if (this.state.fatigue == 0)\n            return TaskStatus.Success;\n        \n        this.state.fatigue--;\n        return TaskStatus.Running;\n    }\n\n    private goToLocation(location: Locate): TaskStatus{\n        console.log(`前往目的地: ${location}. 距离: ${this._distanceToNextLocation}`);\n\n        if (location != this.state.currentLocation){\n            this._distanceToNextLocation--; \n            if (this._distanceToNextLocation == 0){\n                this.state.fatigue ++;\n                this.state.currentLocation = location;\n                this._distanceToNextLocation = Math.floor(Random.range(2, 8));\n                return TaskStatus.Success;\n            }\n\n            return TaskStatus.Running;\n        }\n\n        return TaskStatus.Success;\n    }\n\n    private depositGold(): TaskStatus{\n        this.state.goldInBank += this.state.gold;\n        this.state.gold = 0;\n\n        console.log(`存钱进入银行. 当前存款 ${this.state.goldInBank}`);\n\n        return TaskStatus.Success;\n    }\n}\n```\n\n```typescript\nclass State{\n    public static MAX_FATIGUE: number = 10;\n    public static MAX_GOLD = 8;\n    public static MAX_THIRST = 5;\n\n    public fatigue: number = 0;\n    public thirst: number = 0;\n    public gold: number = 0;\n    public goldInBank: number = 0;\n    public currentLocation: Locate = Locate.Home;\n}\n\nenum Locate{\n    Home,\n    InTransit,\n    Mine,\n    Saloon,\n    Bank\n}\n```\n\n开始行为树\n\n```typescript\nthis.aiComponent = new AiComponent();\nthis.aiComponent.start();\n```\n\n最后还需要对aiComponent进行派发update事件更新\n\n```typescript\nthis.aiComponent.update();\n```\n  \n### Utility Based AI\n游戏效用理论。 最复杂的AI解决方案。 最适合在其计分系统最有效的动态环境中使用。 基于实用程序的AI更适用于AI可以采取大量潜在竞争行为的情况，例如在RTS中。\n  \n#### Reasoner\n从附加在Reasoner上的考虑因素列表中选择最佳考虑因素。一个实用AI的根。\n  \n#### Consideration\n拥有一个评估和一个行动的列表。计算一个分数，用数字表示其行动的效用。\n  \n#### Appraisal\n可以将一个或多个评估添加到Appraisal中。 他们计算并返回其使用代价的得分。\n  \n#### Action\n当一个特定的考虑因素被选中时，AI执行的行动。\n  \n## 依赖库\n\n[ecs-framework](https://github.com/esengine/ecs-framework)\n","funding_links":[],"categories":["AI"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesengine%2FBehaviourTree-ai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fesengine%2FBehaviourTree-ai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesengine%2FBehaviourTree-ai/lists"}