Behaviour tree decorator implementation
This commit is contained in:
@@ -35,6 +35,8 @@ set(libraryDirs
|
|||||||
|
|
||||||
|
|
||||||
set(BreezeSources
|
set(BreezeSources
|
||||||
|
breeze/ai/behaviour_tree.c
|
||||||
|
|
||||||
breeze/core/logger.c
|
breeze/core/logger.c
|
||||||
breeze/core/module_system.c
|
breeze/core/module_system.c
|
||||||
|
|
||||||
@@ -54,6 +56,8 @@ set(BreezeSources
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(BreezeHeaders
|
set(BreezeHeaders
|
||||||
|
breeze/ai/behaviour_tree.h
|
||||||
|
|
||||||
breeze/core/logger.h
|
breeze/core/logger.h
|
||||||
|
|
||||||
breeze/math/vec2i.h
|
breeze/math/vec2i.h
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef BREEZE_H
|
#ifndef BREEZE_H
|
||||||
#define BREEZE_H
|
#define BREEZE_H
|
||||||
|
|
||||||
|
#include "breeze/ai/behaviour_tree.h"
|
||||||
|
|
||||||
#include "breeze/core/logger.h"
|
#include "breeze/core/logger.h"
|
||||||
|
|
||||||
#include "breeze/math/vec2i.h"
|
#include "breeze/math/vec2i.h"
|
||||||
|
|||||||
355
engine/breeze/ai/behaviour_tree.c
Normal file
355
engine/breeze/ai/behaviour_tree.c
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
#include "behaviour_tree.h"
|
||||||
|
|
||||||
|
#include "../memory/memory.h"
|
||||||
|
#include "../util/object_pool.h"
|
||||||
|
|
||||||
|
//#define GET_NODE(idx) ((BzAIBTNode *) bzObjectPoolGetObject(bt->nodePool, idx))
|
||||||
|
|
||||||
|
struct BzAIBTNode {
|
||||||
|
BzAIBTNode *parent;
|
||||||
|
// Children
|
||||||
|
BzAIBTNode *first;
|
||||||
|
BzAIBTNode *last;
|
||||||
|
// Siblings
|
||||||
|
BzAIBTNode *prev;
|
||||||
|
BzAIBTNode *next;
|
||||||
|
|
||||||
|
BzAIBTNodeType type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
i32 n;
|
||||||
|
} repeat;
|
||||||
|
struct {
|
||||||
|
f32 ms;
|
||||||
|
} delay;
|
||||||
|
struct {
|
||||||
|
BzAIBTActionFn fn;
|
||||||
|
} action;
|
||||||
|
} as;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BzAIBTNodeState {
|
||||||
|
const BzAIBTNode *node;
|
||||||
|
BzAIBTNodeState *next;
|
||||||
|
BzAIBTNodeState *prev;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
i32 iter;
|
||||||
|
} repeat;
|
||||||
|
struct {
|
||||||
|
f32 elapsed;
|
||||||
|
} delay;
|
||||||
|
} as;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
size_t bzAIBTGetNodeSize() {
|
||||||
|
return sizeof(BzAIBTNode);
|
||||||
|
}
|
||||||
|
size_t bzAIBTGetNodeStateSize() {
|
||||||
|
return sizeof(BzAIBTNodeState);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BzAIBTNode *bzAIBTNodeMake(BzObjectPool *nodePool, BzAIBTNode *parent, BzAIBTNodeType type) {
|
||||||
|
BZ_ASSERT(nodePool);
|
||||||
|
BZ_ASSERT(bzObjectPoolGetObjectSize(nodePool) == bzAIBTGetNodeSize());
|
||||||
|
BzAIBTNode *node = bzObjectPool(nodePool);
|
||||||
|
bzMemSet(node, 0, sizeof(*node));
|
||||||
|
|
||||||
|
node->type = type;
|
||||||
|
|
||||||
|
if (parent && parent->last) {
|
||||||
|
parent->last->next = node;
|
||||||
|
node->prev = parent->last;
|
||||||
|
parent->last = node;
|
||||||
|
} else if (parent) {
|
||||||
|
parent->first = node;
|
||||||
|
parent->last = node;
|
||||||
|
}
|
||||||
|
node->parent = parent;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
BzAIBTNode *bzAIBTMakeRoot(BzObjectPool *nodePool) {
|
||||||
|
return bzAIBTNodeMake(nodePool, NULL, BZ_AIBT_DECOR_DUMMY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bzAIBTDestroyRoot(BzObjectPool *nodePool, BzAIBTNode *node) {
|
||||||
|
BZ_ASSERT(node);
|
||||||
|
BzAIBTNode *pNode = node;
|
||||||
|
|
||||||
|
while (pNode) {
|
||||||
|
BzAIBTNode *next = pNode->next;
|
||||||
|
bzAIBTDestroyRoot(nodePool, pNode);
|
||||||
|
pNode = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
bzObjectPoolRelease(nodePool, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
BzAIBTNode *bzAIBTCompSelector(BzObjectPool *nodePool, BzAIBTNode *parent, bool parallel) {
|
||||||
|
BzAIBTNodeType type = parallel ?
|
||||||
|
BZ_AIBT_COMP_PARALLEL_SELECTOR :
|
||||||
|
BZ_AIBT_COMP_SELECTOR;
|
||||||
|
return bzAIBTNodeMake(nodePool, parent, type);
|
||||||
|
}
|
||||||
|
BzAIBTNode *bzAIBTCompSequence(BzObjectPool *nodePool, BzAIBTNode *parent, bool parallel) {
|
||||||
|
BzAIBTNodeType type = parallel ?
|
||||||
|
BZ_AIBT_COMP_PARALLEL_SEQUENCE :
|
||||||
|
BZ_AIBT_COMP_SEQUENCE;
|
||||||
|
return bzAIBTNodeMake(nodePool, parent, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
BzAIBTNode *bzAIBTDecorDummy(BzObjectPool *nodePool, BzAIBTNode *parent) {
|
||||||
|
return bzAIBTNodeMake(nodePool, parent, BZ_AIBT_DECOR_DUMMY);
|
||||||
|
}
|
||||||
|
BzAIBTNode *bzAIBTDecorSuccess(BzObjectPool *nodePool, BzAIBTNode *parent) {
|
||||||
|
return bzAIBTNodeMake(nodePool, parent, BZ_AIBT_DECOR_SUCCESS);
|
||||||
|
}
|
||||||
|
BzAIBTNode *bzAIBTDecorFail(BzObjectPool *nodePool, BzAIBTNode *parent) {
|
||||||
|
return bzAIBTNodeMake(nodePool, parent, BZ_AIBT_DECOR_FAIL);
|
||||||
|
}
|
||||||
|
BzAIBTNode *bzAIBTDecorInvert(BzObjectPool *nodePool, BzAIBTNode *parent) {
|
||||||
|
return bzAIBTNodeMake(nodePool, parent, BZ_AIBT_DECOR_INVERT);
|
||||||
|
}
|
||||||
|
BzAIBTNode *bzAIBTDecorUntilSuccess(BzObjectPool *nodePool, BzAIBTNode *parent) {
|
||||||
|
return bzAIBTNodeMake(nodePool, parent, BZ_AIBT_DECOR_UNTIL_SUCCESS);
|
||||||
|
}
|
||||||
|
BzAIBTNode *bzAIBTDecorUntilFail(BzObjectPool *nodePool, BzAIBTNode *parent) {
|
||||||
|
return bzAIBTNodeMake(nodePool, parent, BZ_AIBT_DECOR_UNTIL_FAIL);
|
||||||
|
}
|
||||||
|
BzAIBTNode *bzAIBTDecorRepeat(BzObjectPool *nodePool, BzAIBTNode *parent, i32 n) {
|
||||||
|
BzAIBTNode *node = bzAIBTNodeMake(nodePool, parent, BZ_AIBT_DECOR_REPEAT);
|
||||||
|
node->as.repeat.n = n;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
BzAIBTNode *bzAIBTDecorDelay(BzObjectPool *nodePool, BzAIBTNode *parent, f32 ms) {
|
||||||
|
BzAIBTNode *node = bzAIBTNodeMake(nodePool, parent, BZ_AIBT_DECOR_DELAY);
|
||||||
|
node->as.delay.ms = ms;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
BzAIBTNode *bzAIBTAction(BzObjectPool *nodePool, BzAIBTNode *parent, BzAIBTActionFn fn) {
|
||||||
|
BzAIBTNode *node = bzAIBTNodeMake(nodePool, parent, BZ_AIBT_ACTION);
|
||||||
|
node->as.action.fn = fn;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
BzAIBTNodeType bzAIBTGetNodeType(BzAIBTNode *node) {
|
||||||
|
return node->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
BzAIBTState bzAIBTCreateState(const BzAIBTStateDesc *desc) {
|
||||||
|
BZ_ASSERT(desc->pool);
|
||||||
|
BZ_ASSERT(bzObjectPoolGetObjectSize(desc->pool) == bzAIBTGetNodeStateSize());
|
||||||
|
BZ_ASSERT(desc->root);
|
||||||
|
return (BzAIBTState) {
|
||||||
|
.root = desc->root,
|
||||||
|
.first = NULL,
|
||||||
|
.last = NULL,
|
||||||
|
.nodeStatePool = desc->pool,
|
||||||
|
.userData = desc->userData
|
||||||
|
};
|
||||||
|
}
|
||||||
|
void bzAIBTDestroyState(BzAIBTState *state) {
|
||||||
|
BzAIBTNodeState *pNodeState = state->first;
|
||||||
|
while (pNodeState) {
|
||||||
|
BzAIBTNodeState *next = pNodeState->next;
|
||||||
|
bzObjectPoolRelease(state->nodeStatePool, pNodeState);
|
||||||
|
pNodeState = next;
|
||||||
|
}
|
||||||
|
bzMemSet(state, 0, sizeof(*state));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bzAIBTStatePush(BzAIBTState *state, BzAIBTNodeState *nodeState,
|
||||||
|
const BzAIBTNodeState *desc) {
|
||||||
|
BzAIBTNodeState *newState = bzObjectPool(state->nodeStatePool);
|
||||||
|
BZ_ASSERT(newState && desc);
|
||||||
|
*newState = *desc;
|
||||||
|
|
||||||
|
newState->next = NULL;
|
||||||
|
newState->prev = NULL;
|
||||||
|
|
||||||
|
if (nodeState == NULL)
|
||||||
|
nodeState = state->last;
|
||||||
|
|
||||||
|
if (nodeState) {
|
||||||
|
BzAIBTNodeState *next = nodeState->next;
|
||||||
|
nodeState->next = newState;
|
||||||
|
newState->prev = nodeState;
|
||||||
|
newState->next = next;
|
||||||
|
if (next)
|
||||||
|
next->prev = newState;
|
||||||
|
if (state->last == nodeState)
|
||||||
|
state->last = newState;
|
||||||
|
} else {
|
||||||
|
newState->prev = state->last;
|
||||||
|
state->last = newState;
|
||||||
|
if (state->first == NULL) state->first = newState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void bzAIBTStatePop(BzAIBTState *state, BzAIBTNodeState *nodeState) {
|
||||||
|
if (state->first == nodeState) state->first = nodeState->next;
|
||||||
|
if (state->last == nodeState) state->last = nodeState->prev;
|
||||||
|
BzAIBTNodeState *next = nodeState->next;
|
||||||
|
BzAIBTNodeState *prev = nodeState->prev;
|
||||||
|
if (nodeState->prev)
|
||||||
|
nodeState->prev->next = next;
|
||||||
|
if (nodeState->next)
|
||||||
|
nodeState->next->prev = prev;
|
||||||
|
bzObjectPoolRelease(state->nodeStatePool, nodeState);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BzAIBTStatus bzAIBTExecuteNode(const BzAIBTNode *node, f32 dt,
|
||||||
|
BzAIBTState *state, BzAIBTNodeState *nodeState);
|
||||||
|
/*
|
||||||
|
static inline BzAIBTStatus bzAIBTExecuteComposite(const BzObjectPool *nodePool, const BzAIBTNode *node,
|
||||||
|
BzAIBTState *state, BzAIBTNodeState *nodeState) {
|
||||||
|
switch (node->type) {
|
||||||
|
case BZ_AIBT_COMP_SELECTOR:
|
||||||
|
for (BzAIBTNode *child = node->first; child; child = child->next) {
|
||||||
|
BzAIBTStatus status = bzAIBTExecuteNode(bt, child);
|
||||||
|
if (status == BZ_AIBT_SUCCESS) return status;
|
||||||
|
if (status == BZ_AIBT_RUNNING) return status;
|
||||||
|
}
|
||||||
|
return BZ_AIBT_FAIL;
|
||||||
|
case BZ_AIBT_COMP_SEQUENCE:
|
||||||
|
for (BzAIBTNode *child = node->first; child; child = child->next) {
|
||||||
|
BzAIBTStatus status = bzAIBTExecuteNode(bt, child);
|
||||||
|
if (status == BZ_AIBT_FAIL) return status;
|
||||||
|
if (status == BZ_AIBT_RUNNING) return status;
|
||||||
|
}
|
||||||
|
return BZ_AIBT_SUCCESS;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return BZ_AIBT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static inline BzAIBTStatus bzAIBTExecuteDecorator(const BzAIBTNode *node, f32 dt,
|
||||||
|
BzAIBTState *state, BzAIBTNodeState *nodeState) {
|
||||||
|
// Ensure decorator has only one child
|
||||||
|
BZ_ASSERT(node->first && node->first == node->last);
|
||||||
|
BzAIBTNodeState *first = nodeState;
|
||||||
|
if (nodeState && first->node == node) {
|
||||||
|
first = first->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (node->type) {
|
||||||
|
case BZ_AIBT_DECOR_REPEAT:
|
||||||
|
if (!nodeState || nodeState->node != node) {
|
||||||
|
bzAIBTStatePush(state, nodeState, &(BzAIBTNodeState) {
|
||||||
|
.node = node,
|
||||||
|
.as.repeat.iter = 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_DECOR_DELAY:
|
||||||
|
if (!nodeState || nodeState->node != node) {
|
||||||
|
bzAIBTStatePush(state, nodeState, &(BzAIBTNodeState) {
|
||||||
|
.node = node,
|
||||||
|
.as.delay = {0.2f}
|
||||||
|
});
|
||||||
|
return BZ_AIBT_RUNNING;
|
||||||
|
}
|
||||||
|
nodeState->as.delay.elapsed += 0.2f;
|
||||||
|
if (nodeState->as.delay.elapsed < node->as.delay.ms) {
|
||||||
|
return BZ_AIBT_RUNNING;
|
||||||
|
}
|
||||||
|
bzAIBTStatePop(state, nodeState);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BzAIBTStatus inStatus = bzAIBTExecuteNode(node->first, dt, state, first);
|
||||||
|
|
||||||
|
// ERROR, RUNNING are propagated up
|
||||||
|
if (inStatus == BZ_AIBT_ERROR)
|
||||||
|
return BZ_AIBT_ERROR;
|
||||||
|
if (inStatus == BZ_AIBT_RUNNING)
|
||||||
|
return BZ_AIBT_RUNNING;
|
||||||
|
|
||||||
|
BzAIBTStatus status = BZ_AIBT_ERROR;
|
||||||
|
switch (node->type) {
|
||||||
|
case BZ_AIBT_DECOR_DUMMY:
|
||||||
|
case BZ_AIBT_DECOR_DELAY: // Delay already handled
|
||||||
|
status = inStatus;
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_DECOR_SUCCESS:
|
||||||
|
status = BZ_AIBT_SUCCESS;
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_DECOR_FAIL:
|
||||||
|
status = BZ_AIBT_FAIL;
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_DECOR_INVERT:
|
||||||
|
if (inStatus == BZ_AIBT_FAIL) status = BZ_AIBT_SUCCESS;
|
||||||
|
if (inStatus == BZ_AIBT_SUCCESS) status = BZ_AIBT_FAIL;
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_DECOR_UNTIL_SUCCESS:
|
||||||
|
if (inStatus == BZ_AIBT_SUCCESS)
|
||||||
|
status = BZ_AIBT_SUCCESS;
|
||||||
|
else
|
||||||
|
status = BZ_AIBT_RUNNING;
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_DECOR_UNTIL_FAIL:
|
||||||
|
if (inStatus == BZ_AIBT_FAIL)
|
||||||
|
status = BZ_AIBT_SUCCESS;
|
||||||
|
else
|
||||||
|
status = BZ_AIBT_RUNNING;
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_DECOR_REPEAT:
|
||||||
|
BZ_ASSERT(nodeState->node == node);
|
||||||
|
nodeState->as.repeat.iter++;
|
||||||
|
if (nodeState->as.repeat.iter >= node->as.repeat.n) {
|
||||||
|
bzAIBTStatePop(state, nodeState);
|
||||||
|
status = inStatus;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
status = BZ_AIBT_RUNNING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
static inline BzAIBTStatus bzAIBTExecuteNode(const BzAIBTNode *node, f32 dt,
|
||||||
|
BzAIBTState *state, BzAIBTNodeState *nodeState) {
|
||||||
|
BzAIBTStatus status = BZ_AIBT_ERROR;
|
||||||
|
switch (node->type) {
|
||||||
|
case BZ_AIBT_COMP_SELECTOR:
|
||||||
|
case BZ_AIBT_COMP_SEQUENCE:
|
||||||
|
case BZ_AIBT_COMP_PARALLEL_SELECTOR:
|
||||||
|
case BZ_AIBT_COMP_PARALLEL_SEQUENCE:
|
||||||
|
//status = bzAIBTExecuteComposite(bt, node, state, nodeState);
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_DECOR_DUMMY:
|
||||||
|
case BZ_AIBT_DECOR_SUCCESS:
|
||||||
|
case BZ_AIBT_DECOR_FAIL:
|
||||||
|
case BZ_AIBT_DECOR_INVERT:
|
||||||
|
case BZ_AIBT_DECOR_UNTIL_SUCCESS:
|
||||||
|
case BZ_AIBT_DECOR_UNTIL_FAIL:
|
||||||
|
case BZ_AIBT_DECOR_REPEAT:
|
||||||
|
case BZ_AIBT_DECOR_DELAY:
|
||||||
|
status = bzAIBTExecuteDecorator(node, dt, state, nodeState);
|
||||||
|
break;
|
||||||
|
case BZ_AIBT_ACTION:
|
||||||
|
BZ_ASSERT(node->as.action.fn);
|
||||||
|
return node->as.action.fn(state->userData);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
BzAIBTStatus bzAIBTExecute(BzAIBTState *state, f32 dt) {
|
||||||
|
BZ_ASSERT(state->nodeStatePool);
|
||||||
|
BZ_ASSERT(bzObjectPoolGetObjectSize(state->nodeStatePool) == bzAIBTGetNodeStateSize());
|
||||||
|
BZ_ASSERT(state);
|
||||||
|
BZ_ASSERT(state->root);
|
||||||
|
BzAIBTNodeState *first = state->first;
|
||||||
|
const BzAIBTNode *firstNode = first ? first->node : state->root;
|
||||||
|
BzAIBTStatus status = bzAIBTExecuteNode(firstNode, dt, state, first);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
82
engine/breeze/ai/behaviour_tree.h
Normal file
82
engine/breeze/ai/behaviour_tree.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#ifndef BREEZE_BEHAVIOUR_TREE_H
|
||||||
|
#define BREEZE_BEHAVIOUR_TREE_H
|
||||||
|
|
||||||
|
#include "../defines.h"
|
||||||
|
|
||||||
|
typedef struct BzAIBTNode BzAIBTNode;
|
||||||
|
|
||||||
|
typedef enum BzAIBTStatus {
|
||||||
|
BZ_AIBT_RUNNING,
|
||||||
|
BZ_AIBT_SUCCESS,
|
||||||
|
BZ_AIBT_FAIL,
|
||||||
|
BZ_AIBT_ERROR,
|
||||||
|
} BzAIBTStatus;
|
||||||
|
|
||||||
|
typedef BzAIBTStatus(*BzAIBTActionFn)(void *data);
|
||||||
|
|
||||||
|
typedef enum BzAIBTNodeType {
|
||||||
|
// Composite
|
||||||
|
BZ_AIBT_COMP_SELECTOR,
|
||||||
|
BZ_AIBT_COMP_SEQUENCE,
|
||||||
|
BZ_AIBT_COMP_PARALLEL_SELECTOR,
|
||||||
|
BZ_AIBT_COMP_PARALLEL_SEQUENCE,
|
||||||
|
// Decorator
|
||||||
|
BZ_AIBT_DECOR_DUMMY,
|
||||||
|
BZ_AIBT_DECOR_SUCCESS,
|
||||||
|
BZ_AIBT_DECOR_FAIL,
|
||||||
|
BZ_AIBT_DECOR_INVERT,
|
||||||
|
BZ_AIBT_DECOR_UNTIL_SUCCESS,
|
||||||
|
BZ_AIBT_DECOR_UNTIL_FAIL,
|
||||||
|
BZ_AIBT_DECOR_REPEAT,
|
||||||
|
BZ_AIBT_DECOR_DELAY,
|
||||||
|
// Action/Task
|
||||||
|
BZ_AIBT_ACTION,
|
||||||
|
} BzAIBTNodeType;
|
||||||
|
|
||||||
|
typedef struct BzObjectPool BzObjectPool;
|
||||||
|
typedef struct BzAIBTNodeState BzAIBTNodeState;
|
||||||
|
|
||||||
|
typedef struct BzAIBTState {
|
||||||
|
const BzAIBTNode *root;
|
||||||
|
BzAIBTNodeState *first;
|
||||||
|
BzAIBTNodeState *last;
|
||||||
|
|
||||||
|
BzObjectPool *nodeStatePool;
|
||||||
|
void *userData;
|
||||||
|
} BzAIBTState;
|
||||||
|
|
||||||
|
typedef struct BzAIBTStateDesc {
|
||||||
|
const BzAIBTNode *root;
|
||||||
|
|
||||||
|
BzObjectPool *pool;
|
||||||
|
void *userData;
|
||||||
|
} BzAIBTStateDesc;
|
||||||
|
|
||||||
|
size_t bzAIBTGetNodeSize();
|
||||||
|
size_t bzAIBTGetNodeStateSize();
|
||||||
|
|
||||||
|
BzAIBTNode *bzAIBTMakeRoot(BzObjectPool *nodePool);
|
||||||
|
void bzAIBTDestroyRoot(BzObjectPool *nodePool, BzAIBTNode *node);
|
||||||
|
|
||||||
|
BzAIBTNode *bzAIBTCompSelector(BzObjectPool *nodePool, BzAIBTNode *parent, bool parallel);
|
||||||
|
BzAIBTNode *bzAIBTCompSequence(BzObjectPool *nodePool, BzAIBTNode *parent, bool parallel);
|
||||||
|
|
||||||
|
BzAIBTNode *bzAIBTDecorDummy(BzObjectPool *nodePool, BzAIBTNode *parent);
|
||||||
|
BzAIBTNode *bzAIBTDecorSuccess(BzObjectPool *nodePool, BzAIBTNode *parent);
|
||||||
|
BzAIBTNode *bzAIBTDecorFail(BzObjectPool *nodePool, BzAIBTNode *parent);
|
||||||
|
BzAIBTNode *bzAIBTDecorInvert(BzObjectPool *nodePool, BzAIBTNode *parent);
|
||||||
|
BzAIBTNode *bzAIBTDecorUntilSuccess(BzObjectPool *nodePool, BzAIBTNode *parent);
|
||||||
|
BzAIBTNode *bzAIBTDecorUntilFail(BzObjectPool *nodePool, BzAIBTNode *parent);
|
||||||
|
BzAIBTNode *bzAIBTDecorRepeat(BzObjectPool *nodePool, BzAIBTNode *parent, i32 n);
|
||||||
|
BzAIBTNode *bzAIBTDecorDelay(BzObjectPool *nodePool, BzAIBTNode *parent, f32 ms);
|
||||||
|
|
||||||
|
BzAIBTNode *bzAIBTAction(BzObjectPool *nodePool, BzAIBTNode *parent, BzAIBTActionFn fn);
|
||||||
|
|
||||||
|
BzAIBTNodeType bzAIBTGetNodeType(BzAIBTNode *node);
|
||||||
|
|
||||||
|
BzAIBTState bzAIBTCreateState(const BzAIBTStateDesc *desc);
|
||||||
|
void bzAIBTDestroyState(BzAIBTState *state);
|
||||||
|
|
||||||
|
BzAIBTStatus bzAIBTExecute(BzAIBTState *state, f32 dt);
|
||||||
|
|
||||||
|
#endif //BREEZE_BEHAVIOUR_TREE_H
|
||||||
@@ -69,10 +69,11 @@ BzObjectPool *bzObjectPoolCreate(const BzObjectPoolDesc *desc) {
|
|||||||
if (stride < sizeof(i32)) {
|
if (stride < sizeof(i32)) {
|
||||||
stride = sizeof(i32);
|
stride = sizeof(i32);
|
||||||
}
|
}
|
||||||
BZ_ASSERT(desc->objectsPerPage > 0);
|
BZ_ASSERT(desc->objectsPerPage >= 0);
|
||||||
BZ_ASSERT(desc->objectsPerPage < (2 << 23));
|
BZ_ASSERT(desc->objectsPerPage < (2 << 23));
|
||||||
|
|
||||||
size_t objectsPerPage = desc->objectsPerPage;
|
size_t objectsPerPage = desc->objectsPerPage;
|
||||||
|
if (objectsPerPage == 0) objectsPerPage = 512;
|
||||||
|
|
||||||
size_t pageCapacity = 8;
|
size_t pageCapacity = 8;
|
||||||
void **pages = bzAlloc(sizeof(*pages) * pageCapacity);
|
void **pages = bzAlloc(sizeof(*pages) * pageCapacity);
|
||||||
@@ -100,6 +101,10 @@ void bzObjectPoolDestroy(BzObjectPool *pool) {
|
|||||||
bzFree(pool);
|
bzFree(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t bzObjectPoolGetObjectSize(BzObjectPool *pool) {
|
||||||
|
return pool->stride;
|
||||||
|
}
|
||||||
|
|
||||||
size_t bzObjectPoolGetNumFree(BzObjectPool *pool) {
|
size_t bzObjectPoolGetNumFree(BzObjectPool *pool) {
|
||||||
return pool->numFree;
|
return pool->numFree;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ typedef struct BzObjectPoolDesc {
|
|||||||
BzObjectPool *bzObjectPoolCreate(const BzObjectPoolDesc *desc);
|
BzObjectPool *bzObjectPoolCreate(const BzObjectPoolDesc *desc);
|
||||||
void bzObjectPoolDestroy(BzObjectPool *pool);
|
void bzObjectPoolDestroy(BzObjectPool *pool);
|
||||||
|
|
||||||
|
size_t bzObjectPoolGetObjectSize(BzObjectPool *pool);
|
||||||
|
|
||||||
size_t bzObjectPoolGetNumFree(BzObjectPool *pool);
|
size_t bzObjectPoolGetNumFree(BzObjectPool *pool);
|
||||||
void *bzObjectPool(BzObjectPool *pool);
|
void *bzObjectPool(BzObjectPool *pool);
|
||||||
void *bzObjectPoolGetObject(BzObjectPool *pool, u32 idx);
|
void *bzObjectPoolGetObject(BzObjectPool *pool, u32 idx);
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ project(BreezeTests)
|
|||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
|
add_executable(btree_test btree_test.c)
|
||||||
|
target_link_libraries(btree_test LINK_PRIVATE Breeze)
|
||||||
|
|
||||||
add_executable(window_test window_test.c)
|
add_executable(window_test window_test.c)
|
||||||
target_link_libraries(window_test LINK_PRIVATE Breeze)
|
target_link_libraries(window_test LINK_PRIVATE Breeze)
|
||||||
|
|
||||||
|
|||||||
63
engine/tests/btree_test.c
Normal file
63
engine/tests/btree_test.c
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#define BZ_ENTRYPOINT
|
||||||
|
#include <breeze.h>
|
||||||
|
|
||||||
|
BzObjectPool *nodePool = NULL;
|
||||||
|
BzObjectPool *nodeStatePool = NULL;
|
||||||
|
|
||||||
|
BzAIBTNode *printBT = NULL;
|
||||||
|
|
||||||
|
BzAIBTStatus printAction(void *data) {
|
||||||
|
bzLogInfo("Hello, world!");
|
||||||
|
return BZ_AIBT_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init(int *game) {
|
||||||
|
nodePool = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
||||||
|
.objectSize = bzAIBTGetNodeSize(),
|
||||||
|
});
|
||||||
|
nodeStatePool = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
||||||
|
.objectSize = bzAIBTGetNodeStateSize()
|
||||||
|
});
|
||||||
|
|
||||||
|
// for 1..5:
|
||||||
|
// delay 1s
|
||||||
|
// print "Hello, world!"
|
||||||
|
printBT = bzAIBTMakeRoot(nodePool);
|
||||||
|
BzAIBTNode *node = bzAIBTDecorRepeat(nodePool, printBT, 5);
|
||||||
|
node = bzAIBTDecorDelay(nodePool, node, 1.0f);
|
||||||
|
bzAIBTAction(nodePool, node, printAction);
|
||||||
|
|
||||||
|
BzAIBTState state = bzAIBTCreateState(&(BzAIBTStateDesc) {
|
||||||
|
.root = printBT,
|
||||||
|
.pool = nodeStatePool,
|
||||||
|
.userData = NULL
|
||||||
|
});
|
||||||
|
|
||||||
|
BzAIBTStatus status = BZ_AIBT_RUNNING;
|
||||||
|
|
||||||
|
i32 count = 0;
|
||||||
|
while (status == BZ_AIBT_RUNNING) {
|
||||||
|
status = bzAIBTExecute(&state, 0.2f);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
bzLogInfo("Iter: %d", count);
|
||||||
|
|
||||||
|
bzObjectPoolDestroy(nodePool);
|
||||||
|
bzObjectPoolDestroy(nodeStatePool);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(float dt, int *game) {
|
||||||
|
ClearBackground(WHITE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) {
|
||||||
|
appDesc->init = (BzAppInitFunc) init;
|
||||||
|
appDesc->render = (BzAppRenderFunc) render;
|
||||||
|
|
||||||
|
init(NULL);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user