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

Flowgraph Generation #53

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Conversation

sandsalamand
Copy link

This pull request adds an extension class which generates an AnimatorController graph from a given StateMachine.

For example, it converts code like this:

Into this:

The ChasingMacro StateMachine expands into this when double-clicked:

Usage:

fsm.Init();
#if UNITY_EDITOR
fsm.PrintToAnimator(animatorName: "EnemyHFSM");
#endif

Details:

The animator is placed in the Assets/DebugAnimators/ folder by default. This can be changed through an optional argument to PrintToAnimator().

The first time an AnimatorController graph is generated, the states will be in auto-generated positions. You will need to organize them manually. On subsequent calls to PrintToAnimator(), existing state positions will be respected and unchanged.

In order to access some important fields of StateMachine, I needed to change a few fields from private to internal. The alternative would be embedding the PrintToAnimator code directly inside StateMachine in a giant #if UNITY_EDITOR block.

…achine. Modified StateMachine.cs to expose a few private fields as internal
@sandsalamand
Copy link
Author

Addresses #52

@sandsalamand
Copy link
Author

You can also get some runtime debugging by assigning the auto-generated AnimatorController to an Animator component in your scene, and then calling this code after you call fsm.OnLogic()

string stateName = fsm.GetActiveNestedStateName();
int id = Animator.StringToHash(stateName);
if (stateMachineDebugAnimator.HasState(0, id))
	stateMachineDebugAnimator.Play(stateName);
/// <summary>
/// Gets the active state name, even if it's a nested state of the supplied root state machine
/// </summary>
public static string GetActiveNestedStateName<TOwnId, TStateId, TEvent>(this StateMachine<TOwnId, TStateId, TEvent> rootStateMachine)
{
	var nestedStateMachine = rootStateMachine.ActiveState as StateMachine<TOwnId, TStateId, TEvent>;
	int emergencyEscape = 100;
	while (nestedStateMachine is not null && emergencyEscape > 0)
	{
		var possibleNestedStateMachine = nestedStateMachine.ActiveState as StateMachine<TOwnId, TStateId, TEvent>;
		if (possibleNestedStateMachine is not null)
			nestedStateMachine = possibleNestedStateMachine;
		else
			return nestedStateMachine.ActiveStateName.ToString();

		emergencyEscape--;
	}

	return rootStateMachine.ActiveStateName.ToString();
}

… warnings about invalid transitions. Refactored to improve code readibility and improve performance. Added comments.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant