#define BZ_ENTRYPOINT #include BzObjectPool *nodePool = NULL; BzObjectPool *nodeStatePool = NULL; BzAIBTNode *printBT = NULL; BzAIBTState agentState; BzAIBTStatus printAction(void *data) { bzLogInfo("Hello, world!"); return BZ_AIBT_SUCCESS; } bool init(int *game) { rlImGuiSetup(true); nodePool = bzObjectPoolCreate(&(BzObjectPoolDesc) { .objectSize = bzAIBTGetNodeSize(), }); nodeStatePool = bzObjectPoolCreate(&(BzObjectPoolDesc) { .objectSize = bzAIBTGetNodeStateSize() }); // for 1..5: // seq // delay 1s // print "Hello, world!" printBT = bzAIBTMakeRoot(nodePool); BzAIBTNode *node = bzAIBTDecorRepeat(nodePool, printBT, 5); BzAIBTNode *seq = bzAIBTCompSequence(nodePool, node, false); bzAIBTDecorDelay(nodePool, seq, 1.0f); bzAIBTAction(nodePool, seq, printAction, "printAction"); agentState = bzAIBTCreateState(&(BzAIBTStateDesc) { .root = printBT, .pool = nodeStatePool, .userData = NULL }); return true; } void deinit(int *game) { bzObjectPoolDestroy(nodePool); bzObjectPoolDestroy(nodeStatePool); } void igRenderBTNode(const BzAIBTNode *node, const BzAIBTNodeState *state, bool sameLine, i32 depth) { const BzAIBTNode *child = bzAIBTNodeChild(node); BzAIBTNodeType type = bzAIBTGetNodeType(node); char extraInfo[128]; extraInfo[0] = '\0'; bool hasState = bzAIBTNodeMatchesState(node, state); switch (type) { case BZ_AIBT_DECOR_REPEAT: if (hasState) { snprintf(extraInfo, sizeof(extraInfo), " (%d < %d)", bzAIBTRepeatStateGetIter(state), bzAIBTDecorGetRepeat(node)); } else { snprintf(extraInfo, sizeof(extraInfo), " (%d)", bzAIBTDecorGetRepeat(node)); } break; case BZ_AIBT_DECOR_DELAY: if (hasState) { snprintf(extraInfo, sizeof(extraInfo), " (%.2f < %.2fms)", bzAIBTDelayStateGetElapsed(state), bzAIBTDecorGetDelay(node)); } else { snprintf(extraInfo, sizeof(extraInfo), " (%.2fms)", bzAIBTDecorGetDelay(node)); } break; case BZ_AIBT_ACTION: snprintf(extraInfo, sizeof(extraInfo), " (%s:%p)", bzAIBTActionGetName(node), bzAIBTActionGetFn(node)); break; default: break; } if (hasState) state = bzAIBTNodeStateNext(state); ImVec4 color = {1.0f, 1.0f, 1.0f, 1.0f}; if (hasState) color = (ImVec4) {1.0f, 1.0f, 0.5f, 1.0f}; bool hasSingleChild = false; if (child && bzAIBTNodeNext(child) == NULL) hasSingleChild = true; const char *suffix = hasSingleChild ? " > " : ": "; if (sameLine) { igTextColored(color, "%s%s%s", bzAIBTNodeTypeToStr(type), extraInfo, suffix); } else { igTextColored(color, "%*s%s %s", depth * 2, "", bzAIBTNodeTypeToStr(type), extraInfo, suffix); depth++; } while (child) { if (hasSingleChild) igSameLine(0, 0); igRenderBTNode(child, state, hasSingleChild, depth); child = bzAIBTNodeNext(child); } } void igRenderBT(BzAIBTState *state) { const BzAIBTNode *root = state->root; if (igBegin("BehaviourTree", NULL, 0)) { igRenderBTNode(root, state->first, false, 0); } igEnd(); } void render(float dt, int *game) { ClearBackground(WHITE); BzAIBTStatus status = bzAIBTExecute(&agentState, dt); 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; }