Hi! I'm working on implementing a pair of state machines to help control ants in my game. The two state machines are AntBehaviorMachine, which models discrete behaviors for the ants (wandering, approaching, harvesting, etc), and PheromoneMachine, which models how an ant chooses behaviors (Scouting = wandering and approaching the colony, but Harvesting = approaching the target then approaching the colony). I've run into a small speed bump that I can't search engine my way out of. Ants have a Caste which is partially defined by the pheromone(s) that Caste obeys (do they Scout, do they Harvest, do they Fight, etc), and these pheromones should be chosen by the player (ie, the player can change the Pheromones a Caste obeys). The State Machine pattern has you initialize instances of the State interface (eg IPheromone or Scout) for each entity implementing the State Machine (eg PheromoneMachine). So an Ant has a PheromoneMachine which initializes instances of Scout, Harvest, etc. The problem I'm running into is: how do I define a Caste of Ants with its PheromoneSequence but also have the elements of each PheromoneSequence be instantiated for each ant? Is the best solution to have the Caste keep track of a List<PheromoneEnum> or something like that, and the Ant/PheromoneMachine "decodes" the enum into the proper instance of the IPheromone?
#Help with State Machines - Need to Pass Around Mutable Lists of States
1 messages · Page 1 of 1 (latest)
I know it's complicated. I can share all of my code but it's a lot of code right now. I'm trying to make a flexible system to model 1) different behaviors for the ants 2) different behavior patterns for ants. I settled (so far) on a sort of dual State Machine. Idk if that's the right move.
I actually just did something similar to this, maybe I can help but no promises.
wasn't for a game so dw, just a project.
so what is Caste? Having a hard time reading the big block of text.
ok let me try to describe it:
Ant: individual entities in the game that behave autonomously
Caste: data that a group of ants share, including a List<Pheromone> (<<< this is my problem right now), which defines the behavior pattern for the ants
AntBehaviorMachine / IAntBehavior: concrete behaviors for ants
PheromoneMachine / IPheromone: a behavior pattern for an ant (which can be strung together with other IPheromones to make a List<IPheromone> or a so-called PheromoneSequence
and your problem is that the ants are sharing the list?
The Caste's pheromone sequence should be mutable, defined by the player. But I can't store a List<IPheromone> on the Caste, because each ant should have its own instance of each IPheromone
No, the problem is really with types. Ideally, I could pass around something like List<Type(IPheromone)> which is like references to the different Pheromone objects, like Scout etc.
I think im starting to understand.
Like I don't want the Caste to store instances of the Pheromones, just references so that the ant can instantiate its own.
bc I think (??) ants need their own instances for the state machine to work. Or at least that's what archetypical State Machine pattern says.
I think I'll just hack it with enums and switches.
I believe if you use generics it may work
Say more
Perhaps make a new class, idk something like PheramoneReference<T> where T : IPheromone, and in that class have a method to instantiate a T?
Then when the ant needs to grab a pheramone, it grabs an instance of it without Caste storing instances?
if I'm understanding correctly that's what you want right?
Well, an instance of a pheromone needs the ant object that instantiates it.
so:
public class PheramoneReference<T> where T : Pheremone {
public T GetInstance(Ant instantiator) => new (instantiator);
}
```?
so in that case it'd be better to make a base class of pheromone where the constructor takes an ant
are your constructors of different signatures? or have to be instantiated at a certain time?
woof, we're beyond me now
I don't mess with this T stuff and idk anything about signatures. lol
Currently there's just IPheromone, an interface that specific pheromones inherit, like Scout
do all pheromones have the same constructor?
So that the AntBehaviorMachine and the PheromoneMachine can talk to each other and decide how to change behavior.
No
public interface IPheromone
{
public void Start();
public void Update();
public void Finish();
}
I haven't written an interface version of Scout yet
Why does the Scout pheromone need an ant reference? To move the ant?
Bc I'm converting things as we speak. Ran into the problem of defining the pheromone sequence for the caste
Yes, or for example, I want to store things like progress on an ant's specific Scout or Harvest pheromone
So like if an ant needs to circle a target for like 5 seconds, that's a pheromone-level behavior pattern.
So at the very least, an ant needs a unique instance of its own pheromones.
In your interface's Start method can you take an Ant parameter, that way you can get all the information you need from the ant when it calls start? That way the constructor can be parameterless?
You can also add a public bool Valid(Ant ant); and then do something like this:
Oh I misled you
public class PheromoneMachine
{
public IPheromone CurrentPheromone { get; private set; }
private List<IPheromone> _pheromoneSequence;
private int _currentPheromoneIndex;
private Scout _scout;
public Scout Scout => _scout;
private TendColony _tendColony;
public TendColony TendColony => _tendColony;
private Collect _collect;
public Collect Collect => _collect;
public event Action<IPheromone> PheromoneChanged;
public PheromoneMachine(Ant ant)
{
_scout = new Scout(ant);
_tendColony = new TendColony(ant);
_collect = new Collect(ant);
}
public void Initialize(List<IPheromone> pheromones)
{
_pheromoneSequence = pheromones;
CurrentPheromone = pheromones[0];
CurrentPheromone.Start();
PheromoneChanged?.Invoke(CurrentPheromone);
}
public void NextPheromone()
{
_currentPheromoneIndex++;
CurrentPheromone.Finish();
CurrentPheromone = _pheromoneSequence[_currentPheromoneIndex];
CurrentPheromone.Start();
PheromoneChanged?.Invoke(CurrentPheromone);
}
public void Update()
{
if (CurrentPheromone != null)
{
CurrentPheromone.Update();
}
}
That's the PheromoneMachine which is what actually needs the sequence and, as you can see, stores the specific instances of the pheromones.
some of your pheremones still needs an ant reference right?
Maybe. All I'm nearly sure of is that each ant needs it's own PheromoneMachine with its own instances of all the pheromones.
But simultaneously, an ant's PheromoneSequence should be mutable.
As written, this machine won't work since _pheromoneSequence is itself a list of IPheromones and the machine instantiates its own IPheromones
I think the easiest workaround is to give the machine a list of pheromone enums and have it decode those with a switch to decide IPheromone to instantiate.
But idk if that's good practice. I have to make sure that my pheromone enum is in agreement with the pheromones available.
Idk I'm so novice. lol
I don't think so. If you could store a list of all pheromones somewhere you could do this:
public class PheremoneStorer {
public List<IPheromone> all;
public T GetPheromone<T>(T pheromone, Ant ant) : where T IPheromone {
List<IPheromone> valids = all.FindAll(p => p is T && p.IsValid(ant)); // pseudo code, not sure if this exactly will work
// at this point this will give you all the pheramones that can be used with that ant
}
}
```Perhaps you could just get what pheromones of type T are good to be used by that ant?
Hm
or if you expect to only have 1 type of each pheremone in the all list
public class PheremoneStorer {
public List<IPheromone> all;
public T GetPheromone<T>(T pheromone, Ant ant) : where T IPheromone {
return all.Find(p => p is T && p.IsValid(ant)); // pseudo code, not sure if this exactly will work
}
}
so that way the pheremones are just spererate entirely? You could define a copy method in the pheromone and do this:
public class PheremoneStorer {
public List<IPheromone> all;
public T GetPheromone<T>(T pheromone, Ant ant) : where T IPheromone {
return all.Find(p => p is T && p.IsValid(ant)).ReturnCopy(ant); // pseudo code, not sure if this exactly will work
}
}
public interface IPheromone
{
public void Start();
public void Update();
public void Finish();
public bool IsValid(Ant ant);
public IPheromone ReturnCopy(Ant ant);
}
So a Caste has a list of the Pheromones the Caste will obey, and when the ant's PheromoneMachine wants to instantiate its own pheromones, it will just ask the Caste's list for a copy.
That's perfect!!
the Ant parameter in ReturnCopy so that it can assign any values it needs with the new ant, but also copy any already assigned values.
sounds like it could work.
real quick
if it doesn't and you want to go the enum route
something like this could work easily
I actually kind of need this. Because I want there to be flexibility for one Caste to have Harvest(Food) and another to have Harvest(Water) for example.
And the enum solution gets unwieldy under that constraint.
public interface IPheromone
{
public void Start();
public void Update();
public void Finish();
public PheromoneType { get; } // I think u can do properties here? If not, just make it a method.
}
```That way you can just require your pheremones to define what type it is.
well best of luck. I know this kind of stuff is really hard, I spent 2 months on something similar and had way less progress than I wanted haha.
tough stuff!!! but this is kind of perfectly on the edge of my ability, so I'm loving it.
It's almost out of my ability, and I wanted to give up earlier. But we push right through that!
good luck soldier 🫡