[Zay-ES] Question about AI implementation

Hi everybody !

I’m currently creating a little game with the fantastic @pspeed’s Zay-ES framework. I’ve an interrogation about the implementation of an AI.

I plan to use a basic finite state machine, and I have two options : Create one component for each state, or create one componant storing the current stack of states.

First solution lead to massive attaching/detaching of components on entities. I’ve been told it could cause performance issues.

Second solution is less elegant because it demands to have a parallel and redundant componant/processor mechanism dedicated to the finite state machine.

A third solution could be to let all states attached and add sort of an “active” flag… seems heavy.

Note that in both ways, I imagine states as pure data objects.

Do you have opinions? or exemple of implementation to present me?

Thanks a lot in advance

Ben

Personally, I wouldn’t necessarily store the state machines in the ES at all. It’s more data that will be used internally by the AI system. You need to think about what the inputs and outputs to such a system might be and that’s what the components are. The data that is private for doing the AI’s job doesn’t get exposed as components.

So in the end it just depends on how you plan to split the AI up. If you will have the steering system separate from the decision making piece then you might have some steering goal components or something. Maybe also (and a big maybe) the AI will set the current state node ID as a component just in case other things want to know (for debugging maybe).

Hi,

I’m also working with AI in Zay-ES. My direction is to “Make Data (generic data) for each AI layer and add/remove them as component when AI processing”. I build up the AI framework from Agent concepts mixed in ES concepts:

  • Agent as Entity component.
  • Layer as Entity component.
  • AI Layer controller as “Processer” and be decorated with Event messaging framework and others. Note those piece out of ES.

So I don’t know if you want to build such complex system, but some things that can be used in general cases:

  • First, you should think of AI in layers, for ex each layer can become a piece of component.

  • The very top layer is Agent (or Actor, or just and ID your choice). In such Agent component, other AI related components are organized, for ex: processing order and piority, timestamp…

  • Other components can be: Location, Movement, Animation, Locomotion, Formation, Behavior, Signal, State… (I suppose you are making RTS, i’m I right? :smile: ) … In general, those components should be interplotable. That mean you can compute an “in-between” value in your processor or in case you want to make a new component.

  • Processor can be decorated with messaging framework, I recomend using RxJava for this, but you can use any EventBus or Fiber (Guava or Jetlang).

  • Regards FSM, our statemachine component is just an Array of StateInterval.

    class StateInterval{ //Interpolatable interval for real time processing
    int stateIndex; //Which State
    float duration; //Time that State are actived
    }

    class StateMachine{
    int type;
    ValueList states; //States are in this state machine
    int currentState;
    }

    class StateMachineProcessor{
    List transitions;
    void process(StateMachine stateMachine){
    transitions.get(stateMachine.type).apply(stateMachine);
    }

P/s: I’m also studying Open-RTS and our company are interested in contributing an open-source project for RTS. So I’m revising my HeavenRTS with Zay-ES and the terrain of Open-RTS. Don’t know if we can corporate?

I’m not familiar with this type of AI. Could you explain a little more what agents and layers are?

For my first implementation, I’ve followed pspeed direction, using a single processor called BrainProc. It stores a FSM for each “brained” entity. At each frame, it only update the corresponding FSM.

FSM is a simple and generic stack of Actors. At update, it takes the top actor and call its execute() method.

Actors are constructed with EntityData and entity Id. They do their task in execute() method and decide themselves to pop out of the FSM, create and push new actors, or both. There is one actor for each behavior like :

  • PursueTargetActor
  • IdleActor
  • FleeActor

This is the mechanism used in OpenRTS (minus the Zay-ES).

It is very limited because you can only launch one behavior at a time (while I would like to dodge and fire at the same time, without having three different behaviors).

It’s also hard to expand, since actors are created by other actors. So If I could get a better design, well plugged into ES, it could be great !

If you find something usefull in OpenRTS, I would be glad to help you using it, of course. The transition to Zay-ES is a heavy task and the map system will certainly be concerned, though. Can’t tell it what troubles we are going in ^^

Seems like this is not directly an ES issue but maybe a limitation in your AI?

For example, behavior trees would seem to handle this case. It can be done with state machines also but I guess it feels less natural? Not sure.

Anyway, the ES interaction becomes attaching the “I’m firing” component and the “dodge” component. One is picked up by the weapon system and the other by the steering system. (I’d expect some basic steering ‘goals’ like explained in most of the books. move to loc, intercept entity, avoid entity, follow entity, etc… and these goals might be expressed as components since they tend to be mutually exclusive.)

Edit: the bottom line is that the ES doesn’t care at all about your state machine because that’s AI details that don’t get exposed.

@methusalah:
I think the answer of pspeed tell the right direction you should do in general. As my opinion in ES for AI and RTS game AI to be specific, which genre that entities move a lot in the screen, which will require to use a lot transient Components - the Components type that usually be attach/ detached a lot in progress… And that’s no problem for an ES system as far as you still using the correct mechanism, yes the standard way!

What is Layer? Serveral component that be processed by a Processor, for example: Steering processor will scan though Position, Locomotion, CachedCollisionState of one Entity to get effect of that Agent are moving coordinated with others.

Now take a look at the two ways:

  1. Immutable (recommended in Zay-ES)
    By the result of processing, after one tick, the postion may be replaced by a new one, locomotion and cachedCollisionState may be the same. After few more ticks, all of them are changed. Let say you have 200 running entities in the map at once, you can have 20 thread running at the same time for that Layer processing… But be prepared that the Position components will be instantiated milions of times per minute.
  2. Mutable (like in other framework)
    By the result of processing, after one tick, the postion may be replaced by a new one. You have to schedule the thead of one Processor and the order of Processors so it work correctly. A simple way it’s to organize entities into tree of batchs (hierachical structure) and use an event framework to let one execute after other (Look rxJava).

That’s very abstract, but hope it help somehow.

Absolutly. My goal is to find a good pattern for AI, suitable to the component-driven pattern of the ES. I’ve already peeked into Behavior Trees without diving into any implementation but I will spend time on this. Is this what is used for Mythruna?

I have an immutable approach, to simplify multithreading, processor ordering and networking.

In RTS games there are two levels of AI : tactical and strategic. The tactical AI makes units autonomous while the strategic manage the whole army. Most of the time, the tactical AI is basic because we wish to avoid unpredictable behaviors. An FSM is therefore sufficiant.

For OpenRTS, I would like to have a more expandable tactical AI, with possibilites of units fleeing, regrouping, taking cover, searching for a spoted hidden ennemy… that sort of things, By assembling components and describing behaviors in scripts, ideally.

Do you have such feature with your agent distributed AI?

Thanks a lot for your time guys.

Ben

For OpenRTS, I would like to have a more expandable tactical AI, with
possibilites of units fleeing, regrouping, taking cover, searching for a
spoted hidden ennemy… that sort of things, By assembling components
and describing behaviors in scripts, ideally.

In ES, You only have ID - Entity and Data - Component, So what ever you want to do make them that way: new Entity or new Component.

  • You can group entities into groups. Group can be represent as Collection out side of ES or a Entity with a Group Component. They are references!
  • Search result: more Entity with a Timestamp, and a Hash of Query.
  • Influence spot, Danger spot, Tatical spot: new Entity has Position and Spot Component.
  • Formation slots: Entity with Slot and reference to other Entity which are inside.

You have to carefully to not let modification in entity’s reference link affect the concurency contract of standard ES, beside of that, you are free to do what ever you like.
In general, there are two way to build your structure with Entity (yes, they are Ids) with ES : nested up or flatten down. Nested may raise more question about concurency, flatten are easier for concurency but harder for linking entities. That’s trade off require your skill and knowledge. What I point out above, (RxJava if I’m not very obvious) is a solution to solve scheduling in various situations. It’s a tool may help you if you can not flatten your system enough…

Regards FSM or HFSM is a very abstract thing to me, it’s a datastructure only. I use it in overall beheviors switching, animation switching, stragegy switching… ect if I need them. If you separate FSM into 2 parts : the statemachine’s prototype (transistions, state definitions, guards) and the currentState; you can make your Processor run though all them without knowing what the FSM is for.
With thing that not really stateful like the fuzzy logic or tactical analysis, I usually try to make “Sample” of them, which is a type of Data that can be interpreted as Scalar field. The processor take a snapshot of range of that Scalar field and try to interpolate to get an acceptable result. So yes, you can make them Data. You just have to image how :smile:

Mythruna doesn’t have AI yet except in prototype form and I’ve prototyped it a few different ways over the years. I’m fond of GOAP but I’m still finding a ‘perception’ structure I like… either way I will probably use behavior trees on some level because they are simple, flexible, and pretty expressive. My experience to date is with FSMs.

Since we’re talking about behavior tree, you might want to check out my lib
ReMonkey Tutorial #2: Ninja & Pirates!

I admit that’s fairly limited, but it’s a start and is backed by libGDX-ai.

Some feedback from the AI problem.

First of all thanks for you answers. I’ve looked at GDX-AI from @Pesegato and I’ve added it to my code. The tree is ran each frame into a processor, and the AI data are, for the moment, stored outside the components.

Behavior tree are very powerfull and all works very well.

Thanks !

By the way, another little question about ES : How do you manage relations between entities ?

Imagine a weapon entity in the hand of a character entity. I guess it’s the weapon that know the character and not the inverse, because a weapon can only have one holder at a time, while the character can hold many weapons.

In my current implementation, the weapon update its position from it’s holder position with a holding mechanism. Easy. But the weapon also observe another component of the holder, quickly called WeaponHolding, to check the trigger.

Now I want to hold a second weapon, a spell book, a submachine gun ON a turret ON a car UNDER my holder control, etc. I’ve thought about creating dedicated components like SecondaryWeaponHolding, SpellBookHolding… to store all the triggers needed but it doesn’t seem very flexible.

I’ve also imagined to create a unique component AbilityTriggering containing a list of flags and boolean, but I have to clone the whole list at each updates (because imutability) and seems heavy…

Any suggestion?

1 Like

In general, you should NOT “store” or “handle” entities relationship by Component, or should NOT use default processing mechanism over them. That’s said, if you have a Component named EntityReference that from EntityA point to another EntityB, then you should not use Default processing method that run over that EntityReference and then process both EntityA and EntityB…

Remember that if you get a view of Components snapshot in an Entity by the system, is good for you to go and use those infos; but if you have to fire another request in the middle, those infos may be inconsistent between views. So, at that moment, if you just interact with the EntityB (not its components), you are good to go further. In many usercases you may need to modify EntityB 's components and consider" breaking default ES concurrency contract". So you should make it outside of ES (or use Processors … but outside of ES, see below)

There are serveral tricks to solve this. My favourite is to sacrifice a bit concurrent speed to retain an orders of processing, this is a heavy task that build up serveral Tree of Entities. Let’s say I always perform my RelationalProcessor after some hundred of frame. This processor will organize Entity which Has other Entity into a Tree. Another tree call SpatialTree organize Entity’s Spatial which Nest in other Entity’s Spatial. The tasks build up tree, propagate the Added or Remove of those Entities’ component into global Data acording to order in the tree. You can see this as another way of running processors. Keep in mind that this task consider heavy, it can be a hiccup that frezee all the processors a bit. But because “it is not flat”, as long as you have an efficient Tree datastructure, the smaller amount of Entities you have to run through in said custom cycles and … hopefully you are fast enough to continue.

For writting this, likely you want to replace the default EntitySet with a DefaultEntityTree (EntityRTree, EntityKDTree,… whatever)

https://code.google.com/p/jmonkeyplatform-contributions/source/browse/trunk/zay-es/src/com/simsilica/es/base/DefaultEntitySet.java

The idea of having sereval Holders are completely valid, as I said in a infamous thread about ES of this forum in the past:
It’s completely depends on your game to determinate how to “split” Components and there is NO such generic Component that generic enough to use in ALL game? If you can REUSE serveral of them, you split them well enough (and try to maximize the reuse of course)

A plus about the naming convention:

  • FirstWeaponHolderComponent make apprarently no sense without specific context (Hey what is your first if this is your second?) . How about PrimaryWeaponHolder, SecondaryWeaponHolder, UltimateMagicBookHolder …:smile:

I’ve often made this for know, always with the feeling of doing wrong.

PresumedExistingComponent comp = entityData.getComponent(relatedEntityId, PresumedExistingComponent.class);

It’s not natual, it’s not respectfull of the “Contract”, however I can’t tell why it is bad. At worst, you have an crash in the processor because the presumed component is null, which lead to a “be careflul what you do guys” exception.

It seems also possible to check the nullity of the gotten component, and switch the logic in that case, with or without warning.

Do you see other problems that i’ve not anticipated?

Very interesting observation, I will try to do this as often as possible.

I’ve read a lot about the trees of entities, with tons of pros and cons. I will try to avoid that for the moment but I note your advises.

I will give a try to the triggering component. It will contain a list of pair entityId/trigger

If you set a trigger on the list, the processor will add a trigger component on the related entity. It doesn’t brake the ES contract, and allow any trigger of any kind being added to any related entity. on the side of the “client” entity, we only have to make processors trigger sensitive.

I’ll tell you

It’s ok to have components that point from child to parent… that’s what I’d call the ‘right way’. Your approach going the other way is not invalid though in every scenario I’ve done on paper, it was unnecessary.

For example, if you have 500 entities that need to know what their best firing solution is then this is really a weapons problem and not an actor problem. You iterate over the “weapons” with a “MyOwner” component or whatever and collect some per owner stats as part of the system (not a component) and then at the end of the loop you know the best firing solution for every owner.

Hard to say if that’s valid here but that’s the situation I think of when I think of armies of entities trying to kill something.

This is also my approach for the child placing, relative to its parent. The problem I have is to get and manage all children of a parent.

Imagine that you have 15 spells entities “attached” to your actor. How do you retrieve the spell list for the AI or the player to cast it?

With a field filter… but it implies that something is executing per entity that might be better written to deal with all of the instances of that component in the ES way.

As in my description/example above, you can do it the ‘classic’ way of going to each entity and searching one at a time for what weapon it should fire or you can do it the more ES way and go through all of the weapons.

Sometimes the brain has to bend too far to come up with an ES way to do thing but I find it’s always a fruitful exercise to try because sometimes interesting solutions arise. We tend to think of AI as actor-centric but many of the operations don’t have to be.

Hi there,

Just recall I’ve read this a while ago, quite valuable for one who in the middle of ES- Event base dilemma. :smile: and thinking course for who don’t :slight_smile:

http://michaelshaw.github.io/game_talk/game.html#/

“Run all your entities independently in a functionally pure way, pass in
a static copy of the world (from last frame) and themselves, and they
return a new version of themselves at the end”

“You create events that get communicated to the target entities”

John Carmack - QuakeCon 2013

In the slide there are sample scala code also for sake of understanding phrases and terms.

Imagine that you have 15 spells entities “attached” to your actor. How
do you retrieve the spell list for the AI or the player to cast it?

Ok, this is the question I did answer a few times for my collages and others. This is an typical “split the list” problem for Component. A general sollution for this problem and every problem that require “dynamic content” - “dynamic order” - “dynamic whatever” is to make the “static” immutable and the “dynamic” replacable. Don’t know if where should start a best practice thread of ES tips and tricks?

For this specific situation:

  • You have a Component named SpellList with an Immutable List of 15 Spell-Id in it.
  • You then have a Component named SpellState with 40 slot of Float (say max spell you can have), determinate the usage of that spell.

When the Actor cast a spell you replace SpellState component by a new one (effectively 40 more Floats). When you want to get the list of Spells you can get them by reference by Id from the SpellProcessor or whatever Controller you design. When the actor learn another spell, let Replace the Entire SpellList to determinate changes.

Another example if “Split the list” (not the best demonstration i know) is A Replicated Component spead in serveral of Entities: A Formation of a Group with 4 Slot, each Entity has to move acordingly by a Slot.

This can translate to a simplest form of ES A new Entity with GroupFormation Component which has 4 Slot references to 4 other Entities (Id). The processor than modify Positions of those entities acordingly. Another valid translation which not introduce the FormationEntity is each Entity has a FormationId Component. The Processor save that FormationId else where and the oporate privately. These two scenario should be chosen by each gameplay of course, however the first one has good intergration with overall ES, like you can use that new Entity to indicate other things also and spread them over network.

repeat, How about a best practice for ES and Zay-ES topic?

1 Like

I’m so agree that I will do that immediatly :smile:

Thanks for john’s carmack link, and other explanation.

For the records, i’ve tried to create the spell book as you said, containing the spell entities’ ID. This way it was easy to trigger spells from the caster agent.

But I encounter something that I believe to become, later, an issue : the spell entity itself has a component holding a link to the caster, to move in stace at the good location.

So the spell know the caster and the caster know the spell. That kind of pairing seems dangerous to me, from my experience.

In my last implementation, the spell know the caster for motion, and also for triggering. It observe each frame the caster triggers and act accordingly.

I will give feed back on that solution after I have tested it more consequently

Thanks again for the advises :smile: