Files
PixelDefense/engine/tests/btree_test.c

171 lines
5.2 KiB
C

#define BZ_ENTRYPOINT
#include <breeze.h>
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 = bzBTCompSelector(nodePool, printBT, true);
bzBTDecorDelay(nodePool, pseq, 2.0f);
BzBTNode *node = bzBTDecorRepeat(nodePool, pseq, 5);
BzBTNode *seq = bzBTCompSequence(nodePool, node, false);
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_P_SELECTOR ||
type == BZ_BT_COMP_SEQUENCE ||
type == BZ_BT_COMP_P_SEQUENCE;
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);
}
}