9
\$\begingroup\$

For my current project I implemented a component/entity-based system, basically following most of the best-practice there is in this rather undefined area.

So I got (slightly extended) Entities, which are basically an int ID, a human-readable Name, a std::map of components and a long "type indicator" which is used to show what components are present (I have an power of two enum for all the components types and whenever a component is added to the Entity, I automatically alter that long via bitwise operations, compare this answer).

Then there are the Components, also rather simple: int ID, enum as component type, parent Entity pointer and a std::map of all properties this component holds.

Lastly some Systems/Managers that handle the actual logic processing. They first check if the currently processed Entity has a matching long "type indicator" = all necessary components for that system are present. It then accesses some properties if needed and either directly calls some functions in the respective component or send some messages (via a message dispatcher).

Bottom-line: Until here, a rather standard event-driven component/entity-based system combined with a data-driven approach (compare, components do not have hard-coded data variables, but instead a generic map, as (some) components/archetypes of components will later be read from files with the option to add additional data, that is not part of the actual component code.

Now I would like to also introduce Behavior Trees (based on AiGameDev BTSK) into that project, but I am not sure if and how they should be linked to the already existing components or how to integrate those design in general.

Several related ideas/points/questions come to mind:

  1. My BTs will be read from files (again). I currently have a hard time seeing how I would however best make the connection between an BT Action in that tree and the actual coding in my application. Should I build up some sort of map between the action names used in the BT files and a function pointer to the actual logic implementation? What is the usual approach to solve that?

  2. I assume that I will have to create BTs for all my different Entity types (so for each game-logic/AI-relevant combination of components as indicated by my multiple times mentioned long "type indicator"). As a result it doesn't make sense to put the BT Action implementations in the components as most likely many components will be involved per action, does it?

  3. So should the BT Action logic sit in a/multiple separate systems (to whose methods the map from idea #1 points to)? The system would then check per my long "type indicator" whether the Entity for which the BT is currently checked and that was told to execute a certain action (= method in the system) is actually allowed to do so (= has the necessary components). But then, if not (because for example the BT creator did overlook a specific situation, where a necessary component might not be attached to the Entity at runtime anymore), nothing would happen.

Questions:

  • Are there proven concepts for that kind of integration?
  • What is your take on my 3 points above?
  • Any other things that come to mind, also regarding my component/entity-based design in general?
\$\endgroup\$
5
  • \$\begingroup\$ Re point 1: Behavior trees are nothing more than a visual DSL used mostly for creating character behaviour. A BehaviorTree component should not do anything more or anything less than a Script component would do. Re point 3: What's the reason for using a map over regular fields? \$\endgroup\$
    – Eric
    Commented Jan 6, 2013 at 14:22
  • \$\begingroup\$ #1: What does "DSL" stand for in this context? #3: Sorry, but I cannot follow you on this one. Care to explain please what you mean? \$\endgroup\$ Commented Jan 6, 2013 at 15:15
  • 1
    \$\begingroup\$ probably Domain Specific Language, ie. a custom syntax to work with a very specific problem. \$\endgroup\$ Commented Jan 6, 2013 at 16:54
  • \$\begingroup\$ Patrick is correct, although a semantics is also part of it and "very" may be dropped from this definition. - Re 3: My apologies, it should read: "What's the reason for using a map over regular fields in components?" \$\endgroup\$
    – Eric
    Commented Jan 7, 2013 at 11:29
  • \$\begingroup\$ Re 3: I want the ability to later dynamically specify additional properties outside the C++ code (buzzword: data-driven). For the sake of simplicity I (at least for now) put all properties in this generic framework (using maps), even those that are fix in code and hence could be real C++ fields. Might have to revisit that at a later point, if it becomes a performance issue... \$\endgroup\$ Commented Jan 7, 2013 at 12:12

1 Answer 1

2
\$\begingroup\$

I currently have a hard time seeing how I would however best make the connection between an BT Action in that tree and the actual coding in my application. Should I build up some sort of map between the action names used in the BT files and a function pointer to the actual logic implementation? What is the usual approach to solve that?

Forget about function pointers and think about objects. Each node in the behavior tree (BT from this point on) would ideally correspond to one object in your code. Those objects will have a standard interface to let you arrange them as a tree and for traversing them. A set of function pointers is fine for the behaviour but it doesn't capture the structure of your tree at all.

As a result it doesn't make sense to put the BT Action implementations in the components as most likely many components will be involved per action, does it?

I would expect entities to have a single BehaviorTree component which stores the relevant data for that entity's BT. Execution of the BT is either done by the BT Component or the BT Subsystem depending on how you handle components in your system. As with pretty much anything using components, they will have to refer to other components to get the job done, but those other components won't have to know anything about BTs.

The different actions available would, at the simplest level, be encoded into the various BT node objects. They should be able to make the relevant entity act by manipulating the components as necessary, eg. accessing the movement component to move.

\$\endgroup\$
3
  • \$\begingroup\$ Paragraph #1: Yes, the BT itself will be an object (as I said like the version from AiGameDev). I was just thinking about functors for the actions themselves, but your Paragraph #2 changed that. For some reason this really simple approach never occurred to me (Entity having its own BT member instance). Probably due to the whole new component thing, I did not think straight and simple anymore, so I was looking for a way to mix components with the BT stuff, but that is not needed indeed. \$\endgroup\$ Commented Jan 6, 2013 at 15:13
  • \$\begingroup\$ The main thing that I was lost on previously, was how to connect the action with the entity. Now it is clear: The actions knows which entity via its tree which in return knows the entity it belongs to. \$\endgroup\$ Commented Jan 6, 2013 at 15:13
  • \$\begingroup\$ @Philip Allgaier I am curious, how did you end up creating BT node? Did you create it as 1 behavior node = 1 entity (that would be a lot of entities per 1 game object), or create node as a normal class (not ECS related), or use other approaches? Thank! \$\endgroup\$ Commented Jul 5, 2018 at 4:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .