Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign feature request: Simplify transitions #58

Open
evilenzo opened this issue Dec 16, 2023 · 7 comments
Open

Redesign feature request: Simplify transitions #58

evilenzo opened this issue Dec 16, 2023 · 7 comments
Labels
feature-request Requested Features

Comments

@evilenzo
Copy link

Problem description

So I have a pretty simple FSM with 4 states: Idle, Walk, FollowUntil (follow enemy until it's not in attack range), Attack.

I want to have an opportunity to make transitions almost from every state to every other state. And sometimes I want to configure some transition using scripts. But it turns out I have to make 4 (states amount) * 3 (other states amount) = 12 transitions. Looks pretty bad... And I have to make even more when I make new states. And it turns out we have geometry progression of transitions...

изображение

Yes, I know we can call switch_state() on FSM to switch states. But it makes transitions uncustomizable. And mixing switch_state() and events are kinda bad decision

Possible solutions

Remove transitions

First thing that comes to mind is to remove transitions at all and make function like _handle_transition(to_state: String) in FSMState template. So you can process needed transitions using code

Smart solution - notify transitions during switch_state()

Ok. So the problem is "I want to change states from one to another and also have opportunity to customize some transitions". To solve this we can make switch_state() the desired way to change states instead of fire_event(). And in switch_state() function we will seek for child transition that satisfies our logic and call _on_transition() of this node if found

@ThePat02 ThePat02 added the feature-request Requested Features label Dec 17, 2023
@ThePat02
Copy link
Owner

Hey! I get what you are trying to say. Behaviours can become REALLY complex very fast, but there are some ways to optimize your stay machine.

  1. Reuse transition scripts: If you are not working that way already, you can reuse scripts again, if you need the same transition.
  2. Use more literal names. Instead of something like "toSprint", I'd suggest to use "onStartSprinting" to give more visual clarity. Name it after the event, rather than the state.
  3. Cut down on the transitions: If you draw your state machine as a chart on paper, you also get a huge mess. You can cut down on transitions by working with them in a smart way. For example: Do you really need a transition from ATTACK to MOVE? If there isn't anything special in this change of state in particular, ATTACK -> IDLE -> MOVE is more than enough. You can checkout the 2.0.0 branch, as I already added an example for a simple character controller there.

Regarding your possible solutions:

Remove transitions

I don't think this solutions fits into the whole node based approach of the plugin. Yes, trees will get messy and big, but that's just FSMs and BTs for you. For more complex behaviours, I always suggest keeping your machines in their own scene, so you can reuse them aswell. Something like _handle_transition(to_state) will only result in big match statements and confusing code.

notify transitions during switch_state()

I am not sure, if I am understanding this correctly? Right now you can trigger a transition in 3 ways.

  • change_statewithout any logic and hardcoded
  • fire_eventif you use any event on the transition
  • Basic transition logic in the ìs_validmethod

Could you maybe give an example on how your idea would work and what it would change?

@evilenzo
Copy link
Author

I am not sure, if I am understanding this correctly? Right now you can trigger a transition in 3 ways.

Exactly. The problem is you have to choose one of three ways. And each way has some limitations.

change_state without any logic and hardcoded

This way lacks customization

fire_event if you use any event on the transition

This way needs too much nodes in simple constructions. For example if you want to have basic transition from one state to another you must have state_count * (state_count - 1) transitions.

My idea here is to make transition nodes more "optional".
So we use first way with change_state function. But we also check state we are transitioning from for transition nodes. If we find transition node that refers to state passed to change_state function, we call its code.
Just for better understanding let me show what I mean in pseudocode:

## Changes the current state and calls the appropriate methods like _on_exit and _on_enter.
func change_state(state: FSMState) -> void:
	# Exit the current state
	active_state._on_exit(actor, blackboard)

+       for child in active_state.get_children():
+            if child.next_state == state:
+                 child._on_transition()
+                 break

	# Change the current state
	active_state = state

	# Enter the new state
	active_state._on_enter(actor, blackboard)

	# Emit the state changed signal
	emit_signal("state_changed", active_state)

@evilenzo
Copy link
Author

Idea here is to connect change_state and transition nodes functionality

@ThePat02
Copy link
Owner

I see what you mean. Let me think about these changes and I'll give you some feedback tomorrow. Generally I don't consider many nodes a problem, because the whole plugin is designed around the idea of state machines having actual componenst you can drag around instead of abstract transitions in code, but adding more functionality can't hurt. As said, I'll try some things out and get back to you!

@nickswebsite
Copy link

But it turns out I have to make 4 (states amount) * 3 (other states amount) = 12 transitions. Looks pretty bad... And I have to make even more when I make new states. And it turns out we have geometry progression of transitions...

I ended up writing a make shift plugin to edit the transitions as a table. Makes it easier to get a bird's eye view of the machine when you have a lot of states and events.

@ThePat02
Copy link
Owner

I ended up writing a make shift plugin to edit the transitions as a table. Makes it easier to get a bird's eye view of the machine when you have a lot of states and events.

If this is in a usable state (or even a good starting point), feel free to open a PR draft or something :)

@nickswebsite
Copy link

nickswebsite commented Mar 11, 2024

If this is in a usable state (or even a good starting point), feel free to open a PR draft or something :)

Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Requested Features
Projects
None yet
Development

No branches or pull requests

3 participants