01 · Contribution
Random behavior becomes reproducible per agent.
For the Cornell University Game Library’s shared C++ behavior-tree framework, I added per-instance seeds and randomized selector / sequence behavior.
- Per agentTreeInstance seedExplicit or automatically generated
- GeneratorMersenne TwisterTracked random state
- Tree nodesRandom branchesSelectors + sequences
- DebuggingRepeat the traceSame tree, actions, and seed
Implementation details
The shared framework already separated a behavior tree definition from each agent's TreeInstance. My contribution extended that instance state with explicit random seeds and added creation paths that can accept a known seed or generate one automatically.
Random selectors and random sequences use a per-instance Mersenne Twister instead of fresh untracked randomness. A bug can therefore be reproduced with the same tree, action map, and seed.
02 · Execution state
A shuffled branch order survives across update steps.
A running random sequence retains its child order across frames, keeping long-running actions consistent.
- First entryShuffle childrenStore the order in NodeData
- Current frameTick an actionUse currentChildIndex
- Still runningKeep its placeRetain order + execution state
- Next frameResume the actionContinue the stored sequence
Technical details & source excerpt
A random sequence may remain running for many frames. Its shuffled child order is stored in that node's NodeData rather than recreated on every step, so the sequence advances consistently until success, failure, or reset.
- TreeManager exposes seeded and automatically seeded instances
- Random selector and sequence nodes share the instance generator state
- Seed progression supports repeatable traces without freezing every choice
if ((*data)[treeIndex].shuffledChildren.empty())
{
for (int i = 0; i < children.size(); i++)
{
(*data)[treeIndex].shuffledChildren.push_back(i);
}
const unsigned int seed = (*data)[0].seed;
std::mt19937 generator(seed);
std::shuffle(
(*data)[treeIndex].shuffledChildren.begin(),
(*data)[treeIndex].shuffledChildren.end(),
generator
);
}
const int childIndex =
(*data)[treeIndex].shuffledChildren[
(*data)[treeIndex].currentChildIndex
];
State childState = getChild(childIndex)->execute(data);The shuffled order is generated once from the tree instance seed and stored in per-node state, so a running sequence does not reshuffle between frames.
03 · Verification
Small demos make tree behavior visible.
JSON trees and dog-behavior scenarios exercise decorators and random branches. I also documented the boundary between shared tree logic and per-agent state.
Implementation details
I added multiple JSON tree definitions and dog-behavior scenarios to exercise decorators, random branches, and random sequences. I also expanded class and method documentation around Node, TreeInstance, and TreeManager so the boundary between shared logic and per-agent state is explicit.
This was a team repository. The case study focuses on the seeded-randomness implementation, demos, debugging fixes, and documentation visible in my authored commits rather than claiming ownership of the entire framework.
