#define BZ_ENTRYPOINT #include BzObjectPool *nodePool = NULL; BzObjectPool *nodeStatePool = NULL; BzBTNode *printBT = NULL; BzBTState agentState; BzBTStatus printAction(void *data, f32 dt) { bzLogInfo("Hello, world!"); return BZ_BT_SUCCESS; } bool init(int *game) { rlImGuiSetup(true); nodePool = bzObjectPoolCreate(&(BzObjectPoolDesc) { .objectSize = bzBTGetNodeSize(), }); nodeStatePool = bzObjectPoolCreate(&(BzObjectPoolDesc) { .objectSize = bzBTGetNodeStateSize() }); // for 1..5: // seq // delay 1s // print "Hello, world!" printBT = bzBTMakeRoot(nodePool); BzBTNode *pseq = bzBTCompPSelector(nodePool, printBT); BzBTNode *node = bzBTDecorFail(nodePool, pseq); bzBTDecorDelay(nodePool, node, 2.0f); node = bzBTDecorRepeat(nodePool, pseq, 5); BzBTNode *seq = bzBTCompSequence(nodePool, node); bzBTDecorDelay(nodePool, seq, 1.0f); node = bzBTAction(nodePool, seq, printAction); bzBTNodeSetName(node,"printAction"); agentState = bzBTCreateState(&(BzBTStateDesc) { .root = printBT, .pool = nodeStatePool, .userData = NULL }); return true; } void deinit(int *game) { bzObjectPoolDestroy(nodePool); bzObjectPoolDestroy(nodeStatePool); } void igVisualizeBTState(const BzBTNode *node, const BzBTNodeState *state, bool isActive, bool sameLine, i32 depth); void igRenderBT(BzBTState *state) { const BzBTNode *root = state->root; if (igBegin("BehaviourTree", NULL, 0)) { igText("NodeState pool: %d", bzObjectPoolGetNumFree(nodeStatePool)); igSeparatorText(""); igVisualizeBTState(root, state->_first, true, false, 0); } igEnd(); } void render(float dt, int *game) { ClearBackground(WHITE); BzBTStatus status = bzBTExecute(&agentState, dt); assert(status != BZ_BT_ERROR); rlImGuiBegin(); igRenderBT(&agentState); igShowDemoWindow(NULL); rlImGuiEnd(); } bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) { appDesc->init = (BzAppInitFunc) init; appDesc->deinit = (BzAppDeinitFunc ) deinit; appDesc->render = (BzAppRenderFunc) render; return true; } static const BzBTNodeState *findNodeState(const BzBTNode *node, const BzBTNodeState *state) { const BzBTNodeState *pState = state; // Although it's painfully slow, it serves as a debug tool, // so speed is not a critical concern. while (pState) { const BzBTNodeState *next = bzBTNodeStateNext(pState); if (bzBTNodeMatchesState(node, pState)) return pState; pState = next; } return NULL; } void igVisualizeBTState(const BzBTNode *node, const BzBTNodeState *state, bool isActive, bool sameLine, i32 depth) { const BzBTNode *child = bzBTNodeChild(node); BzBTNodeType type = bzBTGetNodeType(node); char extraInfo[128]; extraInfo[0] = '\0'; const BzBTNodeState *nodeState = findNodeState(node, state); bool hasState = nodeState != NULL; isActive |= hasState; switch (type) { case BZ_BT_DECOR_REPEAT: if (hasState) { snprintf(extraInfo, sizeof(extraInfo), " (%d < %d)", bzBTRepeatStateGetIter(nodeState), bzBTDecorGetRepeat(node)); } else { snprintf(extraInfo, sizeof(extraInfo), " (%d)", bzBTDecorGetRepeat(node)); } break; case BZ_BT_DECOR_DELAY: if (hasState) { snprintf(extraInfo, sizeof(extraInfo), " (%.2f < %.2fms)", bzBTDelayStateGetElapsed(nodeState), bzBTDecorGetDelay(node)); } else { snprintf(extraInfo, sizeof(extraInfo), " (%.2fms)", bzBTDecorGetDelay(node)); } break; case BZ_BT_ACTION: snprintf(extraInfo, sizeof(extraInfo), " (%s:%p)", bzBTNodeGetName(node) ? bzBTNodeGetName(node) : "?", bzBTActionGetFn(node)); break; default: break; } ImVec4 color = {1.0f, 1.0f, 1.0f, 1.0f}; if (isActive) color = (ImVec4) {1.0f, 1.0f, 0.5f, 1.0f}; bool hasSingleChild = true; if (child && bzBTNodeNext(child)) hasSingleChild = false; const char *suffix = hasSingleChild ? " > " : ": "; if (sameLine) { igTextColored(color, "%s%s%s", bzBTNodeTypeToStr(type), extraInfo, suffix); } else { igTextColored(color, "%*s%s %s", depth * 2, "", bzBTNodeTypeToStr(type), extraInfo, suffix); depth++; } bool isComposite = type == BZ_BT_COMP_SELECTOR || type == BZ_BT_COMP_PSELECTOR || type == BZ_BT_COMP_SEQUENCE || type == BZ_BT_COMP_PSEQUENCE; while (child) { if (hasSingleChild) igSameLine(0, 0); bool childActive = isActive && hasSingleChild; if (hasState && isComposite && !childActive) childActive = bzBTCompStateGetRunningChild(state) == child; igVisualizeBTState(child, state, childActive, hasSingleChild, depth); child = bzBTNodeNext(child); } }