feat: add baby and teen projects, update sample data

This commit is contained in:
mac committed 2026-05-21 20:51:32 +08:00
1 parent 9d0261fcd7
commit 895629a007
18 files changed
+5587 -1946

No files matched your search

+2 -1
View File
@@ -89,7 +89,8 @@ export interface NodeDef {
```shell
npm install # 安装依赖
npm start # 运行测试
npm test # 运行测试
npm run dev # 启动开发环境
npm run build # 编译可执行文件
```
+115
View File
@@ -0,0 +1,115 @@
#include "baby_idle_behavior.h"
#include "esp_log.h"
#include "esp_random.h"
#include "esp_timer.h"
static const char* TAG = "BabyIdleBehavior";
namespace sweekar {
namespace demo7 {
namespace {
constexpr int64_t kFirstRandomIdleDelayUs = 5000000; // 5s after entering idle
constexpr int64_t kRandomIdleCooldownUs = 7000000; // 7s after a random idle script
constexpr const char* kBaseIdleScript = "baby/idle/look_around";
constexpr const char* kCuriousIdleScript = "baby/interaction/curious";
constexpr const char* kShyIdleScript = "baby/interaction/shy";
} // namespace
void BabyIdleBehavior::OnEnter(IPetContext* ctx) {
PlayBaseIdle(ctx);
ScheduleRandomIdle(kFirstRandomIdleDelayUs);
phase_ = Phase::WAITING_RANDOM_IDLE;
}
void BabyIdleBehavior::OnExit(IPetContext* ctx) {
ctx->StopScript();
next_random_idle_us_ = 0;
phase_ = Phase::PLAYING_BASE_IDLE;
}
bool BabyIdleBehavior::HandleEvent(IPetContext* ctx, const Event& evt) {
switch (evt.type) {
case EventType::EVT_TOUCH_TAP:
ESP_LOGI(TAG, "Baby got touched. Play surprised.");
ctx->PlayScript("interaction/surprised");
phase_ = Phase::PLAYING_RANDOM_IDLE;
return true;
case EventType::EVT_KEY_LEFT_CLICK:
ESP_LOGI(TAG, "Left clicked in BabyIdle. Opening Baby Menu.");
ctx->RequestModeSwitch(PetModeType::MODE_MENU);
return true;
case EventType::EVT_KEY_RIGHT_CLICK:
ESP_LOGI(TAG, "Right clicked in BabyIdle. Learn to talk.");
ctx->PlayScript("interaction/learned_to_talk");
phase_ = Phase::PLAYING_RANDOM_IDLE;
return true;
case EventType::EVT_GYRO_SHAKE:
ESP_LOGI(TAG, "Baby shaken. Play dizzy.");
ctx->PlayScript("interaction/dizzy");
phase_ = Phase::PLAYING_RANDOM_IDLE;
return true;
case EventType::EVT_TOUCH_SWIPE_LEFT:
ESP_LOGI(TAG, "Baby touch swipe left. Play hurt.");
ctx->PlayScript("baby/interaction/hurt");
phase_ = Phase::PLAYING_RANDOM_IDLE;
return true;
case EventType::EVT_TOUCH_SWIPE_RIGHT:
ESP_LOGI(TAG, "Baby touch swipe right. Play curious.");
ctx->PlayScript(kCuriousIdleScript);
phase_ = Phase::PLAYING_RANDOM_IDLE;
return true;
case EventType::EVT_SCRIPT_DONE:
ESP_LOGI(TAG, "Baby idle script done.");
PlayBaseIdle(ctx);
if (phase_ == Phase::PLAYING_RANDOM_IDLE) {
ScheduleRandomIdle(kRandomIdleCooldownUs);
phase_ = Phase::COOLDOWN_AFTER_RANDOM;
}
return true;
default:
return false;
}
}
void BabyIdleBehavior::OnTick(IPetContext* ctx) {
if (!IsRandomIdleDue()) {
return;
}
PlayRandomIdle(ctx);
phase_ = Phase::PLAYING_RANDOM_IDLE;
}
void BabyIdleBehavior::PlayBaseIdle(IPetContext* ctx) {
ESP_LOGI(TAG, "Play base idle script: %s", kBaseIdleScript);
ctx->PlayScript(kBaseIdleScript);
}
void BabyIdleBehavior::PlayRandomIdle(IPetContext* ctx) {
uint32_t roll = esp_random() % 100;
const char* script = roll < 50 ? kCuriousIdleScript : kShyIdleScript;
ESP_LOGI(TAG, "Play random idle script: %s, roll=%lu", script, static_cast<unsigned long>(roll));
ctx->PlayScript(script);
}
void BabyIdleBehavior::ScheduleRandomIdle(int64_t delay_us) {
next_random_idle_us_ = esp_timer_get_time() + delay_us;
}
bool BabyIdleBehavior::IsRandomIdleDue() const {
if (phase_ != Phase::WAITING_RANDOM_IDLE && phase_ != Phase::COOLDOWN_AFTER_RANDOM) {
return false;
}
return next_random_idle_us_ > 0 && esp_timer_get_time() >= next_random_idle_us_;
}
} // namespace demo7
} // namespace sweekar
+443
View File
@@ -0,0 +1,443 @@
{
"$override": {
},
"custom": {
},
"desc": "宝宝待机行为树 v2:Selector 优先级级联 + 效用曲线 + 双层脑信号(WARNING/CRITICAL)。优先级:精力耗尽 > 饥饿 > 悲伤 > 开心 > 好奇 > 默认待机。",
"export": true,
"group": [
],
"import": [
],
"name": "example",
"prefix": "",
"root": {
"$id": "root001",
"children": [
{
"$id": "idleRepeat001",
"args": {
},
"children": [
{
"$id": "idleSeq001",
"children": [
{
"$id": "idleWaitRhythm",
"args": {
"random": 1.5,
"time": 2
},
"id": "40",
"name": "Wait"
},
{
"$id": "idleSelector001",
"children": [
{
"$id": "exhaustedSeq",
"children": [
{
"$id": "exhaustedCheck",
"args": { "attr": "energy", "op": "<=", "value": 15 },
"id": "43",
"name": "CheckPhysio"
},
{
"$id": "exhaustedScript",
"args": { "script": "baby/need/sleepy" },
"id": "44",
"name": "PlayScript"
}
],
"id": "42",
"name": "Sequence"
},
{
"$id": "hungrySeq",
"children": [
{
"$id": "hungryCheck",
"args": { "attr": "fullness", "op": "<=", "value": 25 },
"id": "46",
"name": "CheckPhysio"
},
{
"$id": "hungryScript",
"args": { "script": "baby/need/hungry" },
"id": "48",
"name": "PlayScript"
},
{
"$id": "hungryMoodDrop",
"args": { "attr": "happiness", "amount": -2 },
"id": "49",
"name": "AddPhysio"
}
],
"id": "45",
"name": "Sequence"
},
{
"$id": "sadSeq",
"children": [
{
"$id": "sadCheck",
"args": { "attr": "sad", "op": ">", "value": 0.5 },
"id": "51",
"name": "CheckUtility"
},
{
"$id": "sadScript",
"args": { "script": "baby/need/sad_mild" },
"id": "52",
"name": "PlayScript"
}
],
"id": "50",
"name": "Sequence"
},
{
"$id": "laughSeq",
"children": [
{
"$id": "laughCheck",
"args": { "attr": "laugh", "op": ">", "value": 0.5 },
"id": "54",
"name": "CheckUtility"
},
{
"$id": "laughScript",
"args": { "script": "baby/interaction/laugh" },
"id": "55",
"name": "PlayScript"
}
],
"id": "53",
"name": "Sequence"
},
{
"$id": "curiousSeq",
"children": [
{
"$id": "curiousCheck",
"args": { "attr": "curious", "op": ">", "value": 0.4 },
"id": "57",
"name": "CheckUtility"
},
{
"$id": "curiousScript",
"args": { "script": "baby/interaction/curious" },
"id": "58",
"name": "PlayScript"
}
],
"id": "56",
"name": "Sequence"
},
{
"$id": "idleFallback",
"args": { "script": "baby/interaction/shy" },
"id": "59",
"name": "PlayScript"
}
],
"id": "41",
"name": "Selector"
}
],
"id": "3",
"name": "Sequence"
}
],
"id": "2",
"name": "Repeat"
},
{
"$id": "listenTriple001",
"args": {
"event": "EVT_TOUCH_TRIPLE_TAP"
},
"children": [
{
"$id": "shyScript001",
"args": {
"script": "baby/interaction/shy"
},
"id": "17",
"name": "PlayScript"
}
],
"id": "16",
"name": "Listen"
},
{
"$id": "listenTap001",
"args": {
"event": "EVT_TOUCH_TAP"
},
"children": [
{
"$id": "tapSelector001",
"children": [
{
"$id": "dirtyTapSeq",
"children": [
{
"$id": "dirtyTapCheck",
"args": { "attr": "cleanliness", "op": "<=", "value": 20 },
"id": "62",
"name": "CheckPhysio"
},
{
"$id": "dirtyTapScript",
"args": { "script": "baby/interaction/hurt" },
"id": "64",
"name": "PlayScript"
},
{
"$id": "dirtyTapMoodDrop",
"args": { "attr": "happiness", "amount": -1 },
"id": "65",
"name": "AddPhysio"
}
],
"id": "61",
"name": "Sequence"
},
{
"$id": "curiousTapSeq",
"children": [
{
"$id": "curiousTapCheck",
"args": { "attr": "curious", "op": ">", "value": 0.55 },
"id": "67",
"name": "CheckUtility"
},
{
"$id": "wantedScript001",
"args": { "script": "baby/interaction/wanted" },
"id": "69",
"name": "PlayScript"
},
{
"$id": "tapHappinessUp",
"args": { "attr": "happiness", "amount": 3 },
"id": "70",
"name": "AddPhysio"
}
],
"id": "66",
"name": "Sequence"
},
{
"$id": "sadTapSeq",
"children": [
{
"$id": "sadTapCheck",
"args": { "attr": "sad", "op": ">", "value": 0.4 },
"id": "72",
"name": "CheckUtility"
},
{
"$id": "comfortScript",
"args": { "script": "baby/need/sad_mild" },
"id": "73",
"name": "PlayScript"
}
],
"id": "71",
"name": "Sequence"
},
{
"$id": "tapFallback",
"args": { "script": "baby/interaction/hurt" },
"id": "74",
"name": "PlayScript"
}
],
"id": "60",
"name": "Selector"
}
],
"id": "18",
"name": "Listen"
},
{
"$id": "listenLeftEar001",
"args": {
"abortType": "interrupt",
"event": "EVT_KEY_LEFT_CLICK"
},
"children": [
{
"$id": "openMenu001",
"args": {
"mode": "MODE_MENU"
},
"id": "24",
"name": "RequestModeSwitch"
}
],
"id": "23",
"name": "Listen"
},
{
"$id": "listenBrainFullnessWarning",
"args": { "event": "EVT_INTERNAL_BRAIN_FULLNESS_WARNING" },
"children": [
{
"$id": "hungryWarnScript",
"args": { "script": "baby/need/hungry" },
"id": "30",
"name": "PlayScript"
}
],
"id": "29",
"name": "Listen"
},
{
"$id": "listenBrainEnergyWarning",
"args": { "event": "EVT_INTERNAL_BRAIN_ENERGY_WARNING" },
"children": [
{
"$id": "sleepyWarnScript",
"args": { "script": "baby/need/sleepy" },
"id": "32",
"name": "PlayScript"
}
],
"id": "31",
"name": "Listen"
},
{
"$id": "listenBrainHappinessWarning",
"args": { "event": "EVT_INTERNAL_BRAIN_HAPPINESS_WARNING" },
"children": [
{
"$id": "sadWarnScript",
"args": { "script": "baby/need/sad_mild" },
"id": "34",
"name": "PlayScript"
}
],
"id": "33",
"name": "Listen"
},
{
"$id": "listenBrainCleanlinessWarning",
"args": { "event": "EVT_INTERNAL_BRAIN_CLEANLINESS_WARNING" },
"children": [
{
"$id": "dirtyWarnScript",
"args": { "script": "baby/need/dirty" },
"id": "36",
"name": "PlayScript"
}
],
"id": "35",
"name": "Listen"
},
{
"$id": "listenBrainFullnessCritical",
"args": { "event": "EVT_INTERNAL_BRAIN_FULLNESS_CRITICAL", "abortType": "interrupt" },
"children": [
{
"$id": "hungryCriticalSeq",
"children": [
{
"$id": "hungryCriticalScript",
"args": { "script": "baby/need/hungry" },
"id": "82",
"name": "PlayScript"
},
{
"$id": "hungryCriticalMoodDrop",
"args": { "attr": "happiness", "amount": -5 },
"id": "83",
"name": "AddPhysio"
}
],
"id": "81",
"name": "Sequence"
}
],
"id": "80",
"name": "Listen"
},
{
"$id": "listenBrainEnergyCritical",
"args": { "event": "EVT_INTERNAL_BRAIN_ENERGY_CRITICAL", "abortType": "interrupt" },
"children": [
{
"$id": "energyCriticalSeq",
"children": [
{
"$id": "energyCriticalScript",
"args": { "script": "baby/need/sleepy" },
"id": "86",
"name": "PlayScript"
},
{
"$id": "energyCriticalMoodDrop",
"args": { "attr": "happiness", "amount": -5 },
"id": "87",
"name": "AddPhysio"
}
],
"id": "85",
"name": "Sequence"
}
],
"id": "84",
"name": "Listen"
},
{
"$id": "listenBrainHappinessCritical",
"args": { "event": "EVT_INTERNAL_BRAIN_HAPPINESS_CRITICAL", "abortType": "interrupt" },
"children": [
{
"$id": "sadCriticalScript",
"args": { "script": "baby/need/sad_mild" },
"id": "89",
"name": "PlayScript"
}
],
"id": "88",
"name": "Listen"
},
{
"$id": "listenBrainCleanlinessCritical",
"args": { "event": "EVT_INTERNAL_BRAIN_CLEANLINESS_CRITICAL", "abortType": "interrupt" },
"children": [
{
"$id": "dirtyCriticalSeq",
"children": [
{
"$id": "dirtyCriticalScript",
"args": { "script": "baby/need/dirty" },
"id": "92",
"name": "PlayScript"
},
{
"$id": "dirtyCriticalMoodDrop",
"args": { "attr": "happiness", "amount": -3 },
"id": "93",
"name": "AddPhysio"
}
],
"id": "91",
"name": "Sequence"
}
],
"id": "90",
"name": "Listen"
}
],
"id": "1",
"name": "Parallel"
},
"vars": [
],
"version": "2.0.0"
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+13
View File
@@ -0,0 +1,13 @@
{
"nodeConf": "node-config.b3-setting",
"metadata": [],
"files": [
{
"path": "example.json",
"desc": "最小宠物养成行为树"
}
],
"settings": {
"checkExpr": true
}
}
+115 -1852
View File
File diff suppressed because it is too large. Load diff
+59 -39
View File
@@ -1,72 +1,92 @@
{
"version": "1.8.0",
"name": "monster",
"$override": {
},
"custom": {
},
"desc": "怪物测试AI",
"firstid": 1,
"export": true,
"group": ["Test"],
"import": [],
"vars": [],
"group": [
"Test"
],
"import": [
],
"name": "monster",
"prefix": "",
"root": {
"id": 1,
"name": "Sequence",
"desc": "怪物测试AI",
"$id": "UzMJ4RCPJi",
"children": [
{
"id": 2,
"name": "Sequence",
"desc": "攻击",
"$id": "22VgEJ8qBb",
"children": [
{
"id": 3,
"name": "GetHp",
"output": ["hp"],
"$id": "sPc1hCO5Y0",
"children": [
{
"id": 4,
"name": "Sequence",
"$id": "IliI30nEez",
"desc": "新建行为树",
"id": "4",
"name": "Sequence",
"path": "workdir/subtree2.json"
}
],
"id": "3",
"name": "GetHp",
"output": [
"hp"
]
},
{
"id": 6,
"name": "Cmp",
"$id": "UflkVPzbM2",
"args": {
"value": "hp",
"gt": 50
"gt": 50,
"value": "hp"
},
"input": ["hp"]
"id": "6",
"input": [
"hp"
],
"name": "Cmp"
},
{
"id": 7,
"name": "TestB3",
"desc": "攻击",
"$id": "vGBhrKx6OT",
"args": {
"time": 1,
"open": true,
"check": "1",
"name": "1",
"status": "FAILURE"
}
"open": true,
"status": "FAILURE",
"time": 1
},
"desc": "攻击",
"id": "7",
"name": "TestB3"
},
{
"id": 8,
"name": "Sequence",
"$id": "0XPfo7WtaM",
"desc": "新建行为树",
"id": "8",
"name": "Sequence",
"path": "workdir/subtree1.json"
}
]
],
"desc": "攻击",
"id": "2",
"name": "Sequence"
},
{
"id": 11,
"name": "Log",
"desc": "逃跑",
"$id": "k3OVVSX9ih",
"args": {
"message": "Run!"
}
},
"desc": "逃跑",
"id": "11",
"name": "Log"
}
]
}
}
],
"desc": "怪物测试AI",
"id": "1",
"name": "Sequence"
},
"vars": [
],
"version": "2.0.0"
}
+28 -18
View File
@@ -1,30 +1,40 @@
{
"version": "1.8.0",
"name": "subtree1",
"$override": {
},
"custom": {
},
"desc": "子树1",
"firstid": 1,
"group": [],
"import": [],
"vars": [],
"group": [
],
"import": [
],
"name": "subtree1",
"prefix": "",
"root": {
"id": 1,
"name": "Sequence",
"desc": "新建行为树",
"$id": "IP1AisFtFv",
"children": [
{
"id": 2,
"name": "Log",
"$id": "yZbdLrFj5E",
"args": {
"message": "d"
}
},
"id": "2",
"name": "Log"
},
{
"id": 3,
"name": "Wait",
"$id": "xkChWKGQn1",
"args": {
"time": 1
}
},
"id": "3",
"name": "Wait"
}
]
}
}
],
"desc": "新建行为树",
"id": "1",
"name": "Sequence"
},
"vars": [
],
"version": "2.0.0"
}
+29 -20
View File
@@ -1,30 +1,39 @@
{
"version": "1.8.0",
"name": "subtree1",
"$override": {
},
"custom": {
},
"desc": "子树1",
"firstid": 1,
"group": [],
"import": [],
"vars": [],
"group": [
],
"import": [
],
"name": "subtree1",
"prefix": "",
"root": {
"id": 1,
"name": "Sequence",
"desc": "新建行为树",
"$id": "GosdwkpHRi",
"children": [
{
"id": 2,
"name": "Log",
"args": {
"message": "hello"
}
"$id": "VJjl0tZcRq",
"desc": "新建行为树",
"id": "2",
"name": "Sequence",
"path": "workdir/sub/subtree1.json"
},
{
"id": 3,
"name": "Wait",
"$id": "6OKeNNuNW9",
"args": {
"time": 1
}
},
"id": "5",
"name": "Wait"
}
]
}
}
],
"desc": "新建行为树",
"id": "1",
"name": "Sequence"
},
"vars": [
],
"version": "2.0.0"
}
+28 -16
View File
@@ -1,22 +1,34 @@
{
"version": "1.8.0",
"name": "subtree2",
"$override": {
},
"custom": {
},
"desc": "子树2",
"firstid": 1,
"group": [],
"import": [],
"vars": [],
"group": [
],
"import": [
],
"name": "subtree2",
"prefix": "",
"root": {
"id": 1,
"name": "Sequence",
"desc": "新建行为树",
"$id": "TZZbFRZLIC",
"children": [
{
"id": 2,
"name": "Cmp",
"args": {},
"input": ["x"]
"$id": "iF9KMbqNoB",
"args": {
},
"id": "2",
"input": [
"x"
],
"name": "Cmp"
}
]
}
}
],
"desc": "新建行为树",
"id": "1",
"name": "Sequence"
},
"vars": [
],
"version": "2.0.0"
}
+44
View File
@@ -0,0 +1,44 @@
{
"$override": {
},
"custom": {
},
"group": [
],
"import": [
],
"name": "example",
"prefix": "",
"root": {
"$id": "WlN4KrHMeI",
"children": [
{
"$id": "VewHwrsZoK",
"args": {
"level": "log",
"message": "hello"
},
"id": "2",
"name": "Log"
},
{
"$id": "w2qpYhd3fi",
"args": {
"time": 1
},
"id": "3",
"name": "Wait"
},
{
"$id": "bro2CDGyFh",
"id": "4",
"name": "unknow"
}
],
"id": "1",
"name": "Sequence"
},
"vars": [
],
"version": "2.0.0"
}
+856
View File
@@ -0,0 +1,856 @@
[
{
"name": "AlwaysFailure",
"type": "Decorator",
"children": 1,
"status": [
"failure",
"|running"
],
"desc": "始终返回失败",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `running` 时,返回 `running`\n+ 其它情况,不管子节点是否成功都返回 `failure`\n"
},
{
"name": "AlwaysRunning",
"type": "Decorator",
"children": 1,
"status": [
"running"
],
"desc": "始终返回运行中状态",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 始终返回 `running`\n"
},
{
"name": "AlwaysSuccess",
"type": "Decorator",
"children": 1,
"status": [
"success",
"|running"
],
"desc": "始终返回成功",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `running` 时,返回 `running`\n+ 其它情况,不管子节点是否成功都返回 `success`\n"
},
{
"name": "Assert",
"type": "Decorator",
"children": 1,
"status": [
"success"
],
"desc": "断言",
"args": [
{
"name": "message",
"type": "string",
"desc": "消息"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `failure` 时,抛出异常\n+ 其余情况返回子节点的执行状态\n"
},
{
"name": "Calculate",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "简单的数值公式计算",
"args": [
{
"name": "value",
"type": "expr",
"desc": "计算公式"
}
],
"output": [
"计算结果"
],
"doc": "+ 做简单的数值公式计算,返回结果到输出\n"
},
{
"name": "Case",
"type": "Composite",
"children": 2,
"status": [
"&success",
"|failure",
"|running"
],
"desc": "分支选择",
"doc": "+ 必须有两个子节点\n+ 第一个子节点为判断条件\n+ 第二个子节点为判断为 `success` 时执行的节点\n+ 此节点不会真正意义的执行,而是交由 `Switch` 节点来执行\n"
},
{
"name": "Check",
"type": "Condition",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "检查True或False",
"args": [
{
"name": "value",
"type": "expr",
"desc": "值"
}
],
"doc": "+ 做简单数值公式判定,返回 `success` 或 `failure`\n"
},
{
"name": "Concat",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "将两个输入合并为一个数组,并返回新数组",
"input": [
"数组1",
"数组2"
],
"output": [
"新数组"
],
"doc": "+ 如果输入不是数组,则返回 `failure`\n"
},
{
"name": "Delay",
"type": "Decorator",
"children": 1,
"status": [
"success"
],
"desc": "延时执行子节点",
"input": [
"延时时间?"
],
"args": [
{
"name": "delay",
"type": "float?",
"desc": "延时时间",
"oneof": "延时时间"
},
{
"name": "cacheVars",
"type": "string[]?",
"desc": "暂存环境变量"
}
],
"doc": "+ 当延时触发时,执行第一个子节点,多个仅执行第一个\n+ 如果子节点返回 `running`,会中断执行并清理执行栈"
},
{
"name": "Filter",
"type": "Decorator",
"children": 1,
"status": [
"success",
"failure",
"|running"
],
"desc": "返回满足条件的元素",
"input": [
"输入数组"
],
"output": [
"变量",
"新数组"
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 遍历输入数组,将当前元素写入`变量`,满足条件的元素放入新数组\n+ 只有当新数组不为空时,才返回 `success`\n"
},
{
"name": "ForEach",
"type": "Decorator",
"children": 1,
"status": [
"success",
"|running",
"|failure"
],
"desc": "遍历数组",
"input": [
"数组"
],
"output": [
"变量",
"索引?"
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 遍历输入数组,将当前元素写入`变量`\n+ 当子节点返回 `failure` 时,退出遍历并返回 `failure` 状态\n+ 执行完所有子节点后,返回 `success`"
},
{
"name": "GetField",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "获取对象的字段值",
"args": [
{
"name": "field",
"type": "string?",
"desc": "字段(field)",
"oneof": "字段(field)"
}
],
"input": [
"对象",
"字段(field)?"
],
"output": [
"字段值(value)"
],
"doc": "+ 合法元素不包括 `undefined` 和 `null`\n+ 只有获取到合法元素时候才会返回 `success`,否则返回 `failure`\n"
},
{
"name": "IfElse",
"type": "Composite",
"children": 3,
"status": [
"|success",
"|failure",
"|running"
],
"desc": "条件执行",
"doc": "+ 必须有三个子节点\n+ 第一个子节点为条件节点\n+ 第二个子节点为条件为 `success` 时执行的节点\n+ 第三个子节点为条件为 `failure` 时执行的节点,\n"
},
{
"name": "Includes",
"type": "Condition",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "判断元素是否在数组中",
"input": [
"数组",
"元素"
],
"doc": "+ 若输入的元素不合法,返回 `failure`\n+ 只有数组包含元素时返回 `success`,否则返回 `failure`\n"
},
{
"name": "Index",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "索引输入的数组",
"args": [
{
"name": "index",
"type": "int?",
"desc": "索引",
"oneof": "索引"
}
],
"input": [
"数组",
"索引?"
],
"output": [
"值"
],
"doc": "+ 合法元素不包括 `undefined` 和 `null`\n+ 索引数组的时候,第一个元素的索引为 0\n+ 只有索引到有合法元素时候才会返回 `success`,否则返回 `failure`\n"
},
{
"name": "Invert",
"type": "Decorator",
"children": 1,
"status": [
"!success",
"!failure",
"|running"
],
"desc": "反转子节点运行结果",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `success` 时返回 `failure`\n+ 当子节点返回 `failure` 时返回 `success`\n+ 当子节点返回 `error` 时返回 `error`\n"
},
{
"name": "IsNull",
"type": "Condition",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "判断变量是否不存在",
"input": [
"判断的变量"
]
},
{
"name": "JustFailure",
"type": "Action",
"children": 0,
"status": [
"failure"
],
"desc": "什么都不干,只返回失败"
},
{
"name": "JustSuccess",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "什么都不干,只返回成功"
},
{
"name": "Let",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "定义新的变量名",
"input": [
"已存在变量名?"
],
"args": [
{
"name": "value",
"type": "json?",
"desc": "值(value)",
"oneof": "已存在变量名"
}
],
"output": [
"新变量名"
],
"doc": "+ 如果有输入变量,则给已有变量重新定义一个名字\n+ 如果`值(value)`为 `null`,则清除变量\n"
},
{
"name": "Listen",
"type": "Decorator",
"children": 1,
"status": [
"success"
],
"desc": "侦听事件",
"input": [
"目标对象?"
],
"output": [
"事件目标?",
"事件参数..."
],
"args": [
{
"name": "event",
"type": "string",
"desc": "事件",
"options": [
{
"source": [
{
"name": "行为树被中断",
"value": "treeInterrupted"
},
{
"name": "行为树开始执行前",
"value": "treeBeforeTicked"
},
{
"name": "行为树执行完成后",
"value": "treeAfterTicked"
},
{
"name": "行为树执行成功后",
"value": "treeTickedSuccess"
},
{
"name": "行为树执行失败后",
"value": "treeTickedFailure"
},
{
"name": "行为树被清理",
"value": "treeCleaned"
}
]
}
]
}
],
"doc": "+ 当事件触发时,执行第一个子节点,多个仅执行第一个\n+ 如果子节点返回 `running`,会中断执行并清理执行栈"
},
{
"name": "Log",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "打印日志",
"input": [
"日志?"
],
"args": [
{
"name": "message",
"type": "string",
"desc": "日志"
},
{
"name": "level",
"type": "string",
"desc": "日志级别",
"default": "log",
"options": [
{
"source": [
{
"name": "LOG",
"value": "log"
},
{
"name": "INFO",
"value": "info"
},
{
"name": "DEBUG",
"value": "debug"
},
{
"name": "WARN",
"value": "warn"
},
{
"name": "ERROR",
"value": "error"
}
]
}
]
}
]
},
{
"name": "Math",
"type": "Action",
"desc": "执行数学运算",
"input": [
"参数..."
],
"output": [
"结果"
],
"status": [
"success",
"failure"
],
"args": [
{
"name": "op",
"type": "string",
"desc": "数学运算类型",
"options": [
{
"source": [
{
"name": "绝对值",
"value": "abs"
},
{
"name": "向上取整",
"value": "ceil"
},
{
"name": "向下取整",
"value": "floor"
},
{
"name": "四舍五入",
"value": "round"
},
{
"name": "符号",
"value": "sign"
},
{
"name": "正弦",
"value": "sin"
},
{
"name": "余弦",
"value": "cos"
},
{
"name": "正切",
"value": "tan"
},
{
"name": "反正切2",
"value": "atan2"
},
{
"name": "幂运算",
"value": "pow"
},
{
"name": "平方根",
"value": "sqrt"
},
{
"name": "自然对数",
"value": "log"
},
{
"name": "最小值",
"value": "min"
},
{
"name": "最大值",
"value": "max"
},
{
"name": "随机数",
"value": "random"
},
{
"name": "随机整数",
"value": "randInt"
},
{
"name": "随机浮点数",
"value": "randFloat"
},
{
"name": "求和",
"value": "sum"
},
{
"name": "平均值",
"value": "average"
},
{
"name": "乘积",
"value": "product"
}
]
}
]
},
{
"name": "value1",
"type": "float?",
"desc": "参数1(优先使用)"
},
{
"name": "value2",
"type": "float?",
"desc": "参数2(优先使用)"
}
]
},
{
"name": "NotNull",
"type": "Condition",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "判断变量是否存在",
"input": [
"判断的变量"
]
},
{
"name": "Now",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "获取当前时间",
"output": [
"当前时间"
]
},
{
"name": "Once",
"type": "Decorator",
"children": 1,
"status": [
"success",
"failure",
"|running"
],
"desc": "只执行一次",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 第一次执行完全部子节点时返回 `success`,之后永远返回 `failure`"
},
{
"name": "Parallel",
"type": "Composite",
"status": [
"success",
"|running"
],
"children": -1,
"desc": "并行执行",
"doc": "+ 并行执行所有子节点\n+ 当有子节点返回 `running` 时,返回 `running` 状态\n+ 执行完所有子节点后,返回 `success`"
},
{
"name": "Push",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "向数组中添加元素",
"input": [
"数组",
"元素"
],
"doc": "+ 当变量`数组`不是数组类型时返回 `failure`\n+ 其余返回 `success`\n"
},
{
"name": "Race",
"type": "Composite",
"status": [
"|success",
"&failure",
"|running"
],
"children": -1,
"desc": "竞争执行",
"doc": "+ 并行执行所有子节点\n+ 当有子节点返回 `success` 时,立即返回 `success` 状态,并中断其他子节点\n+ 如果所有子节点返回 `failure`或 `error` 则返回 `failure`"
},
{
"name": "RandomIndex",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "随机返回输入的其中一个!",
"input": [
"输入目标"
],
"output": [
"随机目标",
"索引?"
],
"doc": "+ 合法元素不包括 `undefined` 和 `null`\n+ 在输入数组中,随机返回其中一个\n+ 当输入数组为空时,或者没有合法元素,返回 `failure`\n"
},
{
"name": "Repeat",
"type": "Decorator",
"children": 1,
"status": [
"success",
"|running",
"|failure"
],
"desc": "循环执行",
"input": [
"循环次数?"
],
"args": [
{
"name": "count",
"type": "int?",
"desc": "循环次数",
"oneof": "循环次数"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `failure` 时,退出遍历并返回 `failure` 状态\n+ 执行完所有子节点后,返回 `success`\n"
},
{
"name": "RetryUntilFailure",
"type": "Decorator",
"children": 1,
"status": [
"!success",
"failure",
"running"
],
"desc": "一直尝试直到子节点返回失败",
"input": [
"最大尝试次数?"
],
"args": [
{
"name": "count",
"type": "int?",
"desc": "最大尝试次数"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 只有当子节点返回 `failure` 时,才返回 `success`,其它情况返回 `running` 状态\n+ 如果设定了尝试次数,超过指定次数则返回 `failure`"
},
{
"name": "RetryUntilSuccess",
"type": "Decorator",
"children": 1,
"status": [
"|success",
"failure",
"running"
],
"desc": "一直尝试直到子节点返回成功",
"input": [
"最大尝试次数?"
],
"args": [
{
"name": "count",
"type": "int?",
"desc": "最大尝试次数"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 只有当子节点返回 `success` 时,才返回 `success`,其它情况返回 `running` 状态\n+ 如果设定了尝试次数,超过指定次数则返回 `failure`"
},
{
"name": "Selector",
"type": "Composite",
"children": -1,
"desc": "选择执行",
"status": [
"|success",
"&failure",
"|running"
],
"doc": "+ 一直往下执行,直到有子节点返回 `success` 则返回 `success`\n+ 若全部节点返回 `failure`或 `error` 则返回 `failure`"
},
{
"name": "Sequence",
"type": "Composite",
"children": -1,
"status": [
"&success",
"|failure",
"|running"
],
"desc": "顺序执行",
"doc": "+ 一直往下执行,只有当所有子节点都返回 `success`, 才返回 `success`\n+ 若子节点返回 `failure`,则直接返回 `failure` 状态\n+ 其余情况返回 `running` 状态\n"
},
{
"name": "SetField",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "设置对象字段值",
"input": [
"输入对象",
"字段(field)?",
"值(value)?"
],
"args": [
{
"name": "field",
"type": "string?",
"desc": "字段(field)",
"oneof": "字段(field)"
},
{
"name": "value",
"type": "json?",
"desc": "值(value)",
"oneof": "值(value)"
}
],
"doc": "+ 对输入对象设置 `field` 和 `value`\n+ 输入参数1必须为对象,否则返回 `failure`\n+ 如果 `field` 不为 `string`, 也返回 `failure`\n+ 如果 `value` 为 `undefined` 或 `null`, 则删除 `field` 的值\n"
},
{
"name": "Switch",
"type": "Composite",
"children": -1,
"status": [
"|success",
"|failure",
"|running"
],
"desc": "分支执行",
"doc": "+ 按顺序测试 `Case` 节点的判断条件(第一个子节点)\n+ 若测试返回 `success` 则执行 `Case` 第二个子节点,并返回子节点的执行状态\n+ 若没有判断为 `success` 的 `Case` 节点,则返回 `failure`\n"
},
{
"name": "Timeout",
"type": "Decorator",
"children": 1,
"status": [
"|success",
"|running",
"failure"
],
"desc": "超时",
"input": [
"超时时间?"
],
"args": [
{
"name": "time",
"type": "float?",
"desc": "超时时间",
"oneof": "超时时间"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点执行超时或返回 `failure` 时,返回 `failure`\n+ 其余情况返回子节点的执行状态\n"
},
{
"name": "Wait",
"type": "Action",
"children": 0,
"status": [
"success",
"running"
],
"desc": "等待",
"input": [
"等待时间?"
],
"args": [
{
"name": "time",
"type": "float?",
"desc": "等待时间",
"oneof": "等待时间"
},
{
"name": "random",
"type": "float?",
"desc": "随机范围"
}
]
},
{
"name": "WaitForEvent",
"type": "Action",
"children": 0,
"status": [
"success",
"running"
],
"desc": "等待事件触发",
"args": [
{
"name": "event",
"type": "string",
"desc": "事件名称"
}
]
},
{
"name": "Watchdog",
"type": "Composite",
"children": 3,
"status": [
"|success",
"|failure",
"|running"
],
"desc": "测试执行",
"doc": "+ 必须有3个子节点\n+ 第一个子节点为条件节点,返回 `success` 或 `failure` 状态\n+ 第二个子节点为条件为 `success` 时执行的节点\n+ 第三个子节点为条件为 `failure` 时执行的节点,不管子节点返回什么状态,都直接返回 `failure`\n+ 当第二个子节点返回 `running` 时,由本节点维护其运行状态\n+ 每一次 tick 都会先执行测试节点,只有当测试节点返回 `success`,才执行第二个子节点\n"
}
]
+4
View File
@@ -0,0 +1,4 @@
{
"nodeConf": "node-config.b3-setting",
"metadata": []
}
+429
View File
@@ -0,0 +1,429 @@
{
"$override": {},
"custom": {},
"desc": "幼年期待机状态树(依据 xlsx:幼年期行为树)",
"export": true,
"group": [],
"import": [],
"name": "idle_state",
"prefix": "",
"root": {
"$id": "rootIdle001",
"id": "1",
"name": "Parallel",
"children": [
{
"$id": "idleLoop001",
"id": "10",
"name": "Repeat",
"children": [
{
"$id": "idleSeq001",
"id": "11",
"name": "Sequence",
"children": [
{
"$id": "idleLog001",
"id": "12",
"name": "Log",
"args": {
"level": "info",
"message": "待机: 基础表情 BABY_EMOMID_BASIC_NORMAL"
}
},
{
"$id": "idleWait001",
"id": "13",
"name": "Wait",
"args": {
"time": 10
}
},
{
"$id": "idleCur001",
"id": "14",
"name": "Log",
"args": {
"level": "info",
"message": "待机触发: 好奇 BABY_EMOCHAT_CURIOUS_NORMAL"
}
}
]
}
]
},
{
"$id": "evSwipe001",
"id": "20",
"name": "Repeat",
"children": [
{
"$id": "evSwipeSeq",
"id": "21",
"name": "Sequence",
"children": [
{
"$id": "evSwipeWait",
"id": "22",
"name": "WaitForEvent",
"args": {
"event": "touch_strip_swipe"
}
},
{
"$id": "evSwipeIf",
"id": "23",
"name": "IfElse",
"children": [
{
"$id": "evSwipeCheck",
"id": "24",
"name": "Check",
"args": {
"value": "emotionHigh"
}
},
{
"$id": "evSwipeHigh",
"id": "25",
"name": "Log",
"args": {
"level": "info",
"message": "触摸条左/右滑(高情绪): 撒娇 BABY_EMOLOW_CLINGY_NORMAL"
}
},
{
"$id": "evSwipeLow",
"id": "26",
"name": "Log",
"args": {
"level": "info",
"message": "触摸条左/右滑(低情绪): 委屈 BABY_EMOCHAT_HURT_NORMAL"
}
}
]
}
]
}
]
},
{
"$id": "evLong001",
"id": "30",
"name": "Repeat",
"children": [
{
"$id": "evLongSeq",
"id": "31",
"name": "Sequence",
"children": [
{
"$id": "evLongWait",
"id": "32",
"name": "WaitForEvent",
"args": {
"event": "touch_strip_long"
}
},
{
"$id": "evLongLog",
"id": "33",
"name": "Log",
"args": {
"level": "info",
"message": "长时间抚摸: 害羞 BABY_EMOCHAT_SHY_NORMAL"
}
}
]
}
]
},
{
"$id": "evTap001",
"id": "40",
"name": "Repeat",
"children": [
{
"$id": "evTapSeq",
"id": "41",
"name": "Sequence",
"children": [
{
"$id": "evTapWait",
"id": "42",
"name": "WaitForEvent",
"args": {
"event": "touch_strip_tap_once"
}
},
{
"$id": "evTapLog",
"id": "43",
"name": "Log",
"args": {
"level": "info",
"message": "敲击1下: 疑惑 BABY_EMOCHAT_CONFUSE_NORMAL"
}
}
]
}
]
},
{
"$id": "evLeft001",
"id": "50",
"name": "Repeat",
"children": [
{
"$id": "evLeftSeq",
"id": "51",
"name": "Sequence",
"children": [
{
"$id": "evLeftWait",
"id": "52",
"name": "WaitForEvent",
"args": {
"event": "left_ear_press"
}
},
{
"$id": "evLeftLog",
"id": "53",
"name": "Log",
"args": {
"level": "info",
"message": "左耳按一下: 菜单呼出"
}
}
]
}
]
},
{
"$id": "evRight001",
"id": "60",
"name": "Repeat",
"children": [
{
"$id": "evRightSeq",
"id": "61",
"name": "Sequence",
"children": [
{
"$id": "evRightWait",
"id": "62",
"name": "WaitForEvent",
"args": {
"event": "right_ear_press"
}
},
{
"$id": "evRightLog",
"id": "63",
"name": "Log",
"args": {
"level": "info",
"message": "右耳按一下: 学说话 BABY_EMORAISING_LEARNTOTALK_NORMAL (音频缺失)"
}
}
]
}
]
},
{
"$id": "evRadarIn01",
"id": "70",
"name": "Repeat",
"children": [
{
"$id": "evRadarInSq",
"id": "71",
"name": "Sequence",
"children": [
{
"$id": "evRadarInWt",
"id": "72",
"name": "WaitForEvent",
"args": {
"event": "radar_person_enter_front_2_3m"
}
},
{
"$id": "evRadarInLg",
"id": "73",
"name": "Log",
"args": {
"level": "info",
"message": "雷达2-3m正面走来: 撒娇 BABY_EMOLOW_CLINGY_NORMAL"
}
}
]
}
]
},
{
"$id": "evRadarOut1",
"id": "80",
"name": "Repeat",
"children": [
{
"$id": "evRadarOutS",
"id": "81",
"name": "Sequence",
"children": [
{
"$id": "evRadarOutW",
"id": "82",
"name": "WaitForEvent",
"args": {
"event": "radar_person_leave_2_3m"
}
},
{
"$id": "evRadarOutL",
"id": "83",
"name": "Log",
"args": {
"level": "info",
"message": "走出雷达范围: 好奇 BABY_EMOCHAT_CURIOUS_NORMAL"
}
}
]
}
]
},
{
"$id": "evSound001",
"id": "90",
"name": "Repeat",
"children": [
{
"$id": "evSoundSeq",
"id": "91",
"name": "Sequence",
"children": [
{
"$id": "evSoundWait",
"id": "92",
"name": "WaitForEvent",
"args": {
"event": "sound_localized"
}
},
{
"$id": "evSoundLog",
"id": "93",
"name": "Log",
"args": {
"level": "info",
"message": "听到声音并定位: 学说话 BABY_EMORAISING_LEARNTOTALK_NORMAL"
}
}
]
}
]
},
{
"$id": "evPickup001",
"id": "100",
"name": "Repeat",
"children": [
{
"$id": "evPickupSeq",
"id": "101",
"name": "Sequence",
"children": [
{
"$id": "evPickupW",
"id": "102",
"name": "WaitForEvent",
"args": {
"event": "posture_pickup"
}
},
{
"$id": "evPickupL",
"id": "103",
"name": "Log",
"args": {
"level": "info",
"message": "识别拿起: 好奇 BABY_EMOCHAT_CURIOUS_NORMAL"
}
}
]
}
]
},
{
"$id": "evShake001",
"id": "110",
"name": "Repeat",
"children": [
{
"$id": "evShakeSeq",
"id": "111",
"name": "Sequence",
"children": [
{
"$id": "evShakeWait",
"id": "112",
"name": "WaitForEvent",
"args": {
"event": "posture_shake"
}
},
{
"$id": "evShakeLog",
"id": "113",
"name": "Log",
"args": {
"level": "warn",
"message": "识别摇晃: 晕了的表情(表情缺失)"
}
}
]
}
]
},
{
"$id": "evUpside001",
"id": "120",
"name": "Repeat",
"children": [
{
"$id": "evUpsideSeq",
"id": "121",
"name": "Sequence",
"children": [
{
"$id": "evUpsideWt",
"id": "122",
"name": "WaitForEvent",
"args": {
"event": "posture_upside_down"
}
},
{
"$id": "evUpsideLog",
"id": "123",
"name": "Log",
"args": {
"level": "warn",
"message": "识别倒立: 晕了的表情(表情缺失)"
}
}
]
}
]
}
]
},
"vars": [
{
"name": "emotionHigh",
"desc": "当前是否高情绪值,供触摸条左/右滑分支判断"
}
],
"version": "2.0.0"
}
+856
View File
@@ -0,0 +1,856 @@
[
{
"name": "AlwaysFailure",
"type": "Decorator",
"children": 1,
"status": [
"failure",
"|running"
],
"desc": "始终返回失败",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `running` 时,返回 `running`\n+ 其它情况,不管子节点是否成功都返回 `failure`\n"
},
{
"name": "AlwaysRunning",
"type": "Decorator",
"children": 1,
"status": [
"running"
],
"desc": "始终返回运行中状态",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 始终返回 `running`\n"
},
{
"name": "AlwaysSuccess",
"type": "Decorator",
"children": 1,
"status": [
"success",
"|running"
],
"desc": "始终返回成功",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `running` 时,返回 `running`\n+ 其它情况,不管子节点是否成功都返回 `success`\n"
},
{
"name": "Assert",
"type": "Decorator",
"children": 1,
"status": [
"success"
],
"desc": "断言",
"args": [
{
"name": "message",
"type": "string",
"desc": "消息"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `failure` 时,抛出异常\n+ 其余情况返回子节点的执行状态\n"
},
{
"name": "Calculate",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "简单的数值公式计算",
"args": [
{
"name": "value",
"type": "expr",
"desc": "计算公式"
}
],
"output": [
"计算结果"
],
"doc": "+ 做简单的数值公式计算,返回结果到输出\n"
},
{
"name": "Case",
"type": "Composite",
"children": 2,
"status": [
"&success",
"|failure",
"|running"
],
"desc": "分支选择",
"doc": "+ 必须有两个子节点\n+ 第一个子节点为判断条件\n+ 第二个子节点为判断为 `success` 时执行的节点\n+ 此节点不会真正意义的执行,而是交由 `Switch` 节点来执行\n"
},
{
"name": "Check",
"type": "Condition",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "检查True或False",
"args": [
{
"name": "value",
"type": "expr",
"desc": "值"
}
],
"doc": "+ 做简单数值公式判定,返回 `success` 或 `failure`\n"
},
{
"name": "Concat",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "将两个输入合并为一个数组,并返回新数组",
"input": [
"数组1",
"数组2"
],
"output": [
"新数组"
],
"doc": "+ 如果输入不是数组,则返回 `failure`\n"
},
{
"name": "Delay",
"type": "Decorator",
"children": 1,
"status": [
"success"
],
"desc": "延时执行子节点",
"input": [
"延时时间?"
],
"args": [
{
"name": "delay",
"type": "float?",
"desc": "延时时间",
"oneof": "延时时间"
},
{
"name": "cacheVars",
"type": "string[]?",
"desc": "暂存环境变量"
}
],
"doc": "+ 当延时触发时,执行第一个子节点,多个仅执行第一个\n+ 如果子节点返回 `running`,会中断执行并清理执行栈"
},
{
"name": "Filter",
"type": "Decorator",
"children": 1,
"status": [
"success",
"failure",
"|running"
],
"desc": "返回满足条件的元素",
"input": [
"输入数组"
],
"output": [
"变量",
"新数组"
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 遍历输入数组,将当前元素写入`变量`,满足条件的元素放入新数组\n+ 只有当新数组不为空时,才返回 `success`\n"
},
{
"name": "ForEach",
"type": "Decorator",
"children": 1,
"status": [
"success",
"|running",
"|failure"
],
"desc": "遍历数组",
"input": [
"数组"
],
"output": [
"变量",
"索引?"
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 遍历输入数组,将当前元素写入`变量`\n+ 当子节点返回 `failure` 时,退出遍历并返回 `failure` 状态\n+ 执行完所有子节点后,返回 `success`"
},
{
"name": "GetField",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "获取对象的字段值",
"args": [
{
"name": "field",
"type": "string?",
"desc": "字段(field)",
"oneof": "字段(field)"
}
],
"input": [
"对象",
"字段(field)?"
],
"output": [
"字段值(value)"
],
"doc": "+ 合法元素不包括 `undefined` 和 `null`\n+ 只有获取到合法元素时候才会返回 `success`,否则返回 `failure`\n"
},
{
"name": "IfElse",
"type": "Composite",
"children": 3,
"status": [
"|success",
"|failure",
"|running"
],
"desc": "条件执行",
"doc": "+ 必须有三个子节点\n+ 第一个子节点为条件节点\n+ 第二个子节点为条件为 `success` 时执行的节点\n+ 第三个子节点为条件为 `failure` 时执行的节点,\n"
},
{
"name": "Includes",
"type": "Condition",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "判断元素是否在数组中",
"input": [
"数组",
"元素"
],
"doc": "+ 若输入的元素不合法,返回 `failure`\n+ 只有数组包含元素时返回 `success`,否则返回 `failure`\n"
},
{
"name": "Index",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "索引输入的数组",
"args": [
{
"name": "index",
"type": "int?",
"desc": "索引",
"oneof": "索引"
}
],
"input": [
"数组",
"索引?"
],
"output": [
"值"
],
"doc": "+ 合法元素不包括 `undefined` 和 `null`\n+ 索引数组的时候,第一个元素的索引为 0\n+ 只有索引到有合法元素时候才会返回 `success`,否则返回 `failure`\n"
},
{
"name": "Invert",
"type": "Decorator",
"children": 1,
"status": [
"!success",
"!failure",
"|running"
],
"desc": "反转子节点运行结果",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `success` 时返回 `failure`\n+ 当子节点返回 `failure` 时返回 `success`\n+ 当子节点返回 `error` 时返回 `error`\n"
},
{
"name": "IsNull",
"type": "Condition",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "判断变量是否不存在",
"input": [
"判断的变量"
]
},
{
"name": "JustFailure",
"type": "Action",
"children": 0,
"status": [
"failure"
],
"desc": "什么都不干,只返回失败"
},
{
"name": "JustSuccess",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "什么都不干,只返回成功"
},
{
"name": "Let",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "定义新的变量名",
"input": [
"已存在变量名?"
],
"args": [
{
"name": "value",
"type": "json?",
"desc": "值(value)",
"oneof": "已存在变量名"
}
],
"output": [
"新变量名"
],
"doc": "+ 如果有输入变量,则给已有变量重新定义一个名字\n+ 如果`值(value)`为 `null`,则清除变量\n"
},
{
"name": "Listen",
"type": "Decorator",
"children": 1,
"status": [
"success"
],
"desc": "侦听事件",
"input": [
"目标对象?"
],
"output": [
"事件目标?",
"事件参数..."
],
"args": [
{
"name": "event",
"type": "string",
"desc": "事件",
"options": [
{
"source": [
{
"name": "行为树被中断",
"value": "treeInterrupted"
},
{
"name": "行为树开始执行前",
"value": "treeBeforeTicked"
},
{
"name": "行为树执行完成后",
"value": "treeAfterTicked"
},
{
"name": "行为树执行成功后",
"value": "treeTickedSuccess"
},
{
"name": "行为树执行失败后",
"value": "treeTickedFailure"
},
{
"name": "行为树被清理",
"value": "treeCleaned"
}
]
}
]
}
],
"doc": "+ 当事件触发时,执行第一个子节点,多个仅执行第一个\n+ 如果子节点返回 `running`,会中断执行并清理执行栈"
},
{
"name": "Log",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "打印日志",
"input": [
"日志?"
],
"args": [
{
"name": "message",
"type": "string",
"desc": "日志"
},
{
"name": "level",
"type": "string",
"desc": "日志级别",
"default": "log",
"options": [
{
"source": [
{
"name": "LOG",
"value": "log"
},
{
"name": "INFO",
"value": "info"
},
{
"name": "DEBUG",
"value": "debug"
},
{
"name": "WARN",
"value": "warn"
},
{
"name": "ERROR",
"value": "error"
}
]
}
]
}
]
},
{
"name": "Math",
"type": "Action",
"desc": "执行数学运算",
"input": [
"参数..."
],
"output": [
"结果"
],
"status": [
"success",
"failure"
],
"args": [
{
"name": "op",
"type": "string",
"desc": "数学运算类型",
"options": [
{
"source": [
{
"name": "绝对值",
"value": "abs"
},
{
"name": "向上取整",
"value": "ceil"
},
{
"name": "向下取整",
"value": "floor"
},
{
"name": "四舍五入",
"value": "round"
},
{
"name": "符号",
"value": "sign"
},
{
"name": "正弦",
"value": "sin"
},
{
"name": "余弦",
"value": "cos"
},
{
"name": "正切",
"value": "tan"
},
{
"name": "反正切2",
"value": "atan2"
},
{
"name": "幂运算",
"value": "pow"
},
{
"name": "平方根",
"value": "sqrt"
},
{
"name": "自然对数",
"value": "log"
},
{
"name": "最小值",
"value": "min"
},
{
"name": "最大值",
"value": "max"
},
{
"name": "随机数",
"value": "random"
},
{
"name": "随机整数",
"value": "randInt"
},
{
"name": "随机浮点数",
"value": "randFloat"
},
{
"name": "求和",
"value": "sum"
},
{
"name": "平均值",
"value": "average"
},
{
"name": "乘积",
"value": "product"
}
]
}
]
},
{
"name": "value1",
"type": "float?",
"desc": "参数1(优先使用)"
},
{
"name": "value2",
"type": "float?",
"desc": "参数2(优先使用)"
}
]
},
{
"name": "NotNull",
"type": "Condition",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "判断变量是否存在",
"input": [
"判断的变量"
]
},
{
"name": "Now",
"type": "Action",
"children": 0,
"status": [
"success"
],
"desc": "获取当前时间",
"output": [
"当前时间"
]
},
{
"name": "Once",
"type": "Decorator",
"children": 1,
"status": [
"success",
"failure",
"|running"
],
"desc": "只执行一次",
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 第一次执行完全部子节点时返回 `success`,之后永远返回 `failure`"
},
{
"name": "Parallel",
"type": "Composite",
"status": [
"success",
"|running"
],
"children": -1,
"desc": "并行执行",
"doc": "+ 并行执行所有子节点\n+ 当有子节点返回 `running` 时,返回 `running` 状态\n+ 执行完所有子节点后,返回 `success`"
},
{
"name": "Push",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "向数组中添加元素",
"input": [
"数组",
"元素"
],
"doc": "+ 当变量`数组`不是数组类型时返回 `failure`\n+ 其余返回 `success`\n"
},
{
"name": "Race",
"type": "Composite",
"status": [
"|success",
"&failure",
"|running"
],
"children": -1,
"desc": "竞争执行",
"doc": "+ 并行执行所有子节点\n+ 当有子节点返回 `success` 时,立即返回 `success` 状态,并中断其他子节点\n+ 如果所有子节点返回 `failure`或 `error` 则返回 `failure`"
},
{
"name": "RandomIndex",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "随机返回输入的其中一个!",
"input": [
"输入目标"
],
"output": [
"随机目标",
"索引?"
],
"doc": "+ 合法元素不包括 `undefined` 和 `null`\n+ 在输入数组中,随机返回其中一个\n+ 当输入数组为空时,或者没有合法元素,返回 `failure`\n"
},
{
"name": "Repeat",
"type": "Decorator",
"children": 1,
"status": [
"success",
"|running",
"|failure"
],
"desc": "循环执行",
"input": [
"循环次数?"
],
"args": [
{
"name": "count",
"type": "int?",
"desc": "循环次数",
"oneof": "循环次数"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点返回 `failure` 时,退出遍历并返回 `failure` 状态\n+ 执行完所有子节点后,返回 `success`\n"
},
{
"name": "RetryUntilFailure",
"type": "Decorator",
"children": 1,
"status": [
"!success",
"failure",
"running"
],
"desc": "一直尝试直到子节点返回失败",
"input": [
"最大尝试次数?"
],
"args": [
{
"name": "count",
"type": "int?",
"desc": "最大尝试次数"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 只有当子节点返回 `failure` 时,才返回 `success`,其它情况返回 `running` 状态\n+ 如果设定了尝试次数,超过指定次数则返回 `failure`"
},
{
"name": "RetryUntilSuccess",
"type": "Decorator",
"children": 1,
"status": [
"|success",
"failure",
"running"
],
"desc": "一直尝试直到子节点返回成功",
"input": [
"最大尝试次数?"
],
"args": [
{
"name": "count",
"type": "int?",
"desc": "最大尝试次数"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 只有当子节点返回 `success` 时,才返回 `success`,其它情况返回 `running` 状态\n+ 如果设定了尝试次数,超过指定次数则返回 `failure`"
},
{
"name": "Selector",
"type": "Composite",
"children": -1,
"desc": "选择执行",
"status": [
"|success",
"&failure",
"|running"
],
"doc": "+ 一直往下执行,直到有子节点返回 `success` 则返回 `success`\n+ 若全部节点返回 `failure`或 `error` 则返回 `failure`"
},
{
"name": "Sequence",
"type": "Composite",
"children": -1,
"status": [
"&success",
"|failure",
"|running"
],
"desc": "顺序执行",
"doc": "+ 一直往下执行,只有当所有子节点都返回 `success`, 才返回 `success`\n+ 若子节点返回 `failure`,则直接返回 `failure` 状态\n+ 其余情况返回 `running` 状态\n"
},
{
"name": "SetField",
"type": "Action",
"children": 0,
"status": [
"success",
"failure"
],
"desc": "设置对象字段值",
"input": [
"输入对象",
"字段(field)?",
"值(value)?"
],
"args": [
{
"name": "field",
"type": "string?",
"desc": "字段(field)",
"oneof": "字段(field)"
},
{
"name": "value",
"type": "json?",
"desc": "值(value)",
"oneof": "值(value)"
}
],
"doc": "+ 对输入对象设置 `field` 和 `value`\n+ 输入参数1必须为对象,否则返回 `failure`\n+ 如果 `field` 不为 `string`, 也返回 `failure`\n+ 如果 `value` 为 `undefined` 或 `null`, 则删除 `field` 的值\n"
},
{
"name": "Switch",
"type": "Composite",
"children": -1,
"status": [
"|success",
"|failure",
"|running"
],
"desc": "分支执行",
"doc": "+ 按顺序测试 `Case` 节点的判断条件(第一个子节点)\n+ 若测试返回 `success` 则执行 `Case` 第二个子节点,并返回子节点的执行状态\n+ 若没有判断为 `success` 的 `Case` 节点,则返回 `failure`\n"
},
{
"name": "Timeout",
"type": "Decorator",
"children": 1,
"status": [
"|success",
"|running",
"failure"
],
"desc": "超时",
"input": [
"超时时间?"
],
"args": [
{
"name": "time",
"type": "float?",
"desc": "超时时间",
"oneof": "超时时间"
}
],
"doc": "+ 只能有一个子节点,多个仅执行第一个\n+ 当子节点执行超时或返回 `failure` 时,返回 `failure`\n+ 其余情况返回子节点的执行状态\n"
},
{
"name": "Wait",
"type": "Action",
"children": 0,
"status": [
"success",
"running"
],
"desc": "等待",
"input": [
"等待时间?"
],
"args": [
{
"name": "time",
"type": "float?",
"desc": "等待时间",
"oneof": "等待时间"
},
{
"name": "random",
"type": "float?",
"desc": "随机范围"
}
]
},
{
"name": "WaitForEvent",
"type": "Action",
"children": 0,
"status": [
"success",
"running"
],
"desc": "等待事件触发",
"args": [
{
"name": "event",
"type": "string",
"desc": "事件名称"
}
]
},
{
"name": "Watchdog",
"type": "Composite",
"children": 3,
"status": [
"|success",
"|failure",
"|running"
],
"desc": "测试执行",
"doc": "+ 必须有3个子节点\n+ 第一个子节点为条件节点,返回 `success` 或 `failure` 状态\n+ 第二个子节点为条件为 `success` 时执行的节点\n+ 第三个子节点为条件为 `failure` 时执行的节点,不管子节点返回什么状态,都直接返回 `failure`\n+ 当第二个子节点返回 `running` 时,由本节点维护其运行状态\n+ 每一次 tick 都会先执行测试节点,只有当测试节点返回 `success`,才执行第二个子节点\n"
}
]
+13
View File
@@ -0,0 +1,13 @@
{
"nodeConf": "node-config.b3-setting",
"metadata": [],
"files": [
{
"path": "example.json",
"desc": "幼年期待机状态树"
}
],
"settings": {
"checkExpr": true
}
}
Binary file not shown.