0
\$\begingroup\$

So, I'm working on a FSM that ticks on every frame. The inner workings can be simplified to this:

  1. The user (me) creates the States:
IdleState idle;
ChaseState chase;
DeadState dead;
// And so on...
  1. The user (me) creates the Conditions for the upcoming Transitions:
Func<bool> TargetOnSight() => () => onSight == true;
Func<bool> TargetOutOfSight() => () => onSight == false;

// This can also be written as:
bool targetOutOfSight => onSight == false;
bool targetOnSight => onSight == true;
// And so on...
  1. The user (me) creates the Transitions:
// Go from *idle* to *chase* based on the next *conditions*
AddTransition(idle, chase, TargetOnSight());
AddTransition(idle, chase, TargetOutOfSight());
// And so on...

Is quite simple to some extend, honestly.

The FSM works flawlessly. However, I've stumbled across a complicated issue (at least to me). There's a State that I need to trigger on a call. Basically, this State needs to be triggered by a variable that only changes for a frame. In other words, I'm looking to emulate the Animator's SetTrigger() behavior. We could also say that I am looking to set a State based on the change of a variable.

bool hasBeenHit;

Func<bool> ShouldRetreat() => () => hasBeenHit == true;

AddTransition(blahblah, retreat, ShouldRetreat());

The first thing that comes to my mind, are events. However, this approach would require me to literally rewrite the entire system from tick/update-driven to event-driven, isn't it?

I've found this and this. They both mention the usage of Properties (get; set;), though I couldn't find a proper way to implement them into my code. I think both of them uses some kind of event-driven approach (via Actions<>, for example).

How would I implement the behavior I'm looking for without using events?

I have nothing against events but there must be a way to do it without them. If there is definitely no way, I guess I'll have to go with events.

Thanks!

\$\endgroup\$
5
  • \$\begingroup\$ Can you clarify why the technique you're using for onSight wouldn't work for hasBeenHit? What's different about the activation pattern here? Walk us through what your state machine should do when this variable changes in various ways, contrasted against what it does with your current method, so we can clearly see the difference you want to fix. \$\endgroup\$ Commented Apr 13, 2022 at 11:59
  • \$\begingroup\$ Ahh sure: so, onSight becomes true every frame, and returns to false every frame. Same thing applies to every other condition. hasBeenHit would work the same way, however that's not what I need; hasBeenHit needs to be true on one frame and return to false on the next one. This means that hasBeenHit would have to reset to its original value once we have entered the desired state. However, the States are completely independent from the State Machine itself, so they can't hold a reference to hasBeenHit. \$\endgroup\$ Commented Apr 13, 2022 at 22:00
  • \$\begingroup\$ "Becomes true every frame and returns to false every frame" sounds like sometime during every single frame the variable becomes true, and then becomes false again before the end of each frame. But from your contrast, what I think you mean to say is that onSight stays true over multiple frames. ie. once it's set to true, that value is stable for a period of time, so if you don't react to it in the frame it happens, you have a chance to catch it later. But for hasBeenHit, the process that tries to react to it might not run in the single frame it's true, and so might miss it? Is that right? \$\endgroup\$ Commented Apr 14, 2022 at 12:35
  • \$\begingroup\$ Something like that. Effectively, onSight stays true over a certain period of time. We have to look at it this way: an NPC is idling, waiting for someone to approach it. When someone is near, onSight becomes true, and since the State Machine runs on Update, onSight stays true, until that someone is too far from the NPC; That's when onSight becomes false, and stays false until the process repeats itself. hasBeenHit is a reaction. \$\endgroup\$ Commented Apr 14, 2022 at 21:54
  • \$\begingroup\$ If someone attacks the NPC at any moment, the NPC reacts, so hasBeenHit becomes true only for a brief period of time, and then hasBeenHit retuns to false. hasBeenHit cannot stay true the same as onSight because it's only a quick reaction, it needs to immediately return to false. \$\endgroup\$ Commented Apr 14, 2022 at 21:54

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.