Civilisation AI and Behaviour Trees Alexander Cetinski
Civilisation AI and Behaviour Trees
Alexander Cetinski
Project Rundown
Aim: Create a City/Nation simulator - with political leaders, and citizens as AI Entities. Try to make it as realistic as possible.
Method: The project underwent 2.5 implementations. ● One's AI was script based, in C# (XNA). ● The next was Behaviour Tree based in C# (XNA).● I threw the latter out, and decided to make it in Unity, along
with tools to make it easy to manage.
Result: The script based AI and first iteration of the Behaviour Trees became increasingly difficult to manage. The second iteration of the Behaviour Trees was a success in ease of use, but, due to time constraints - did not yield realistic AI.
Scripting vs. Behaviour TreesScripting:
+ Programmer friendly. + Link behaviours in directly (easy interface between AI and entity). + Easily Optimisable+ No tools required.+ Easy to test.
- Less Designer friendly.- Hard to represent graphically, tweak quickly. - Can get huge amounts of code.- Cannot be inherently dynamically changed during runtime.
BTs:
+ Designer friendly + Already graphically represented. + Easy to tweak, change, test. (even during run-time.)+ Easily Optimisable (Fast!)
- REQUIRE TOOLS. 100% needed.- Can require additional data and structures within entities using them. - Take up memory.- Can be hard to test if they go wrong.
Rebuttals? Scripting:
- Proper structure and clear formatting can make tweaking easier.
- Design patterns can be used to add functionality and clean structure.
- Strategies, for example can be used to add and subtract behaviours and change flow.
BTs
- Behaviour Tree Nodes don't take up much memory at all. Even if they did, memory can take work away from processing.
- Once the code is confirmed to be correct, testing is just a matter of following through the tree and finding the logic flaws.
- Additional tools could be created to help with testing
Winner?
I preferred using Behaviour Trees.
Once implemented, and tools are created, they are very easy to use.
They give designers full control when they need it - and if the designer can script, and understand how to extend behaviours on the entities - they can add to the system!
Can be easily customised and extended with more complex Node types, Node Wrappers - the best example being a Behaviour Tree that ensures that it is only run X times per frame (or second).
How it Works
The tools and interfaces
BTs need Tools
Sadly, they do :(
The biggest turning point in this assignment was when I thew out my old BT code, and used Unity's graphical interface, as well as its support for Editor extension.
Unity's Scene Editor allows for easy BT creation:
Tools 2
Unity's Editor Extension allows for easy designer-friendly nodes.
How did I set mine up?
First off, the standard BT structure.
BT > Root Node Node > Action, Sequence, Selector, Condition
Interfacing with AI Entities - Actions
Actions carry a string that corresponds to behaviours. These Actions are sent to the Entity as the tree is processed.
Interfacing with AI Entities - Conditions
Conditions compare 2 floats, with an Operator (==, !=, <, etc.)
When set up, they take either:
● Two AI Enities + 2 Variable Indexes ○ Comparing one Leader's Charisma to another's.
● An AI Enity + Variable Index, a Constant Variable ○ Checking if the Government Type is "Democratic"
Interfacing with BT DesignersActions, Selectors, Sequences pretty simple.
Conditions need to be able to compare a number of variables. You can either hand code every condition - or set up generic conditions (I did this). There are where those interfaces come in.
Inferfacing with BT Designers 2
Behind the Scenes:
"Enums" and "Variables" enums are fed into the Condition GUIs. When a Condition is set up, it polls the Entities to get their information, and carry out the condition.
Condition > Entity Interface #1:
AdditionsI made a few more Node Types.
● "Try All" Sequence -> Does not return false unless all children return false.
○ Allows you to make simple sequences of Actions that work regardless of each other.
● Meta-Action -> Actions that interface with the Behaviour Tree, not the Entity.
○ Adding Nodes ○ Deleting Nodes ○ Replacing Nodes.
● Meta-Condition -> Conditions that refer to the tree. ○ Is a Node an only child? ○ Does it have more than 1 child?○ Is X a child of Y?
How to Build a Tree
Consider: ● Optimising through processing more the likely outcomes
first. ● If Idle is the most likely action, check it first, right? ● Then idle may become too prominent?
CLEARLY DEFINE LOGIC. ● Check any reason to break out of idle before you act. ● Behaviour Trees are pretty quick anyway.● Effectiveness (realism/fun) generally > Tree Optimisation*
*(Obviously the BT system has to be well optimised, individual trees are less imp.)
Optimisation
Red goes faster. Unless it's a compile error.
Optimisation - Data Flow
There are a number of ways in which you can optimise your BTs.
In my example - the first implementation of the Condition interface is slow - every time the condition runs, it runs a switch statement.
Use pointers! (or, Reference types in Unity... >.> )
Optimisation - Reducing Workload
If you imagine your Behaviour Tree to be an implementation of a Strategy design pattern - you can reduce your processing by a lot.
Imagine 300 entities who when voting for a leader, all have to check the Government Type.If each citizen's Voting BT isa static variable shared between all Citizens, you can plug in a single BT when needed for Optimisation.
Optimisation - Reducing Workload 2
Similarly, having multiple entities making use of the same tree via proxies saves on memory usage - and you could have the tree control how often it is run to ensure fast processing.
This is a proxy:
It just pretends to be its target! Even in Condition Nodes!
Optimisation - Reducing Workload 3
Treat your nodes of the BT like a Strategy pattern.Rather than swapping out an entire BT depending on a variable, swap out sections of the BT.
For example - a citizen who was a laborer, becoming unemployed, and then becoming a chef! No profession checks needed!
How did it go?
The Voting System and Proxies worked great! ● 300 Entities showed no change in FPS ● 1000 halved it (still >30fps). ● 500 took it down to 50 FPS. ● So you get 300 entities for free!
The Profession system optimisation also worked tremendously. 300 Entities could run down a large tree, with no visible change in FPS! In fact, it takes 0.07 ms to process the entire 300 entities per update!
Cool Stuff
You have a basic BT - now what?
Behaviour Trees Can Build Themselves
Just as you can swap and change bits of BTs to reduce processing - you can make them build themselves!
This could be really useful in Genetic Algorithms - rather than your genetic sequence referringto simple actions such asMove Up, Move Down, etc. - it could refer to entire branches of logic!
Applications
Say you have an RPG, and you want a number of enemies all with different traits and inventories.
● Have a designer make a basic Tree skeleton● As the inventory is filled, it adds to the tree.
● Fill the level with enemies● Select their inventories● Generate their BTs.
Why AI based in Memory is GOOD.
Because Behaviour Trees are objects in your game - you can save their state along with your level. This might set off some alarm bells -
● It will make my level take longer to load! ● On Load, my AI will have to regenerate itself?
Nope. ● Individual nodes are tiny. I have 17000 of them in my demo
with no significant RAM usage.● If you generate the BT in development, and save it out with
the level - it's baked in! ● No generation is necessary unless you want the AI to
evolve during gameplay!
Results!
● Each AI Entity has their own tree.● The Tree perfectly reflects the AI's personality and abilities.● No two enemies need to have the same tree - you can have
as much diversity as you need to make great gameplay.● The Tree is optimised for the AI's personality and abilities to
reduce processing. ● The AI loads with the level (and is small!).
Recap
And conclusion
What I would have done differently:
Made "Placeholder" Node types. ● With MetaActions constantly changing trees (adding and
deleting nodes), nodes could become invalid. ● Node validation was actually far more costly in processing
than the actual AI.● Placeholder nodes can fix this.
Combining Node Types. ● Making a Condition + Sequence, and Condition + Selector
that runs its children if it succeeds.● Reduce nodes you need in a tree. ● Super useful.
Comparison
Without combined Condition Nodes - 57 Nodes.
With combined Condition Nodes - 39 Nodes
That's a third of them gone! Less nodes means more readability and ease of use.
Behaviour Trees
Pros:
+ Designer Friendly. + Flexible and Customisable+ Fast to Process+ Can be easily dynamically generated/altered for optimisation. + Easy to tweak.+ Can be "baked into" levels, to reduce processing. + Can theoretically 'learn' if designed as such.
Cons:
- REQUIRE CREATION TOOLS.- Can be hard to test. (Pen and paper works, but, additional tools are desirable)