See the forum thread for more information https://forum.unity.com/threads/sources-included-polymorphism-in-dots-now-with-source-generators.1264616/
- Import the
PolymorphicStructs.unitypackageinto your project (find it in the Releases section) - Make sure all of the code that's going to use PolymorphicStructs is under an .asmdef and references the PolymorphicStructs.asmdef
- Create an interface that will represent the various functions your polymorphic structs will share. This interface must have the
[PolymorphicStruct]attribute on it
[PolymorphicStruct]
public interface IMyState
{
public void OnStateEnter(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData);
public void OnStateExit(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData);
public void OnStateUpdate(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData);
}- Create the structs that implement that interface, representing all the different forms that the polymorphic stuct can assume. Make sure these structs are
partial
[Serializable]
public partial struct StateA : IMyState
{
public float Duration;
public float3 MovementSpeed;
private float _durationCounter;
public void OnStateEnter(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData)
{
_durationCounter = Duration;
}
public void OnStateExit(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData)
{
refData.Translation = refData.StateMachine.StartTranslation;
}
public void OnStateUpdate(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData)
{
refData.Translation += MovementSpeed * inData.DeltaTime;
_durationCounter -= inData.DeltaTime;
if (_durationCounter <= 0f)
{
refData.StateMachine.CurrentStateIndex = refData.StateMachine.StateBIndex;
}
}
}
[Serializable]
public partial struct StateB : IMyState
{
public float Duration;
public float3 RotationSpeed;
private float _durationCounter;
public void OnStateEnter(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData)
{
_durationCounter = Duration;
}
public void OnStateExit(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData)
{
refData.Rotation = quaternion.identity;
}
public void OnStateUpdate(ref StateUpdateData_ReadWrite refData, in StateUpdateData_ReadOnly inData)
{
refData.Rotation = math.mul(quaternion.Euler(RotationSpeed * inData.DeltaTime), refData.Rotation);
_durationCounter -= inData.DeltaTime;
if (_durationCounter <= 0f)
{
refData.StateMachine.CurrentStateIndex = refData.StateMachine.StateCIndex;
}
}
}- This will generate a
MyStatestruct (takes the name of the interface, minus the first character "I") that will have all the functions of theIMyStateinterface. You can now call polymorphic functions on MyState like this and it will call the implementation of whichever version of the struct was assigned toMyState:
myState.OnStateUpdate(...)- You can also create a
MyStatefrom the various specific structs and vice-versa like this:
// Creating a MyState from a StateA
StateA stateA = new StateA();
MyState state = stateA.ToMyState();
// Creating a StateA from a MyState
StateA stateA = new StateA(state);TestSceneis the sample sceneCubeSpawnerSysteminitializes the scene by spawning thousands of cube prefabs (Cube)- The
Cubeprefab has aStateMachineAuthoringcomponent - The
StateMachineAuthoringcomponent adds aMyStateMachineas well as aDynamicBuffer<MyState>. This buffer is the place where we store all of our polymorphic states. You can see how we create a polymorphicMyStatefrom individual state structs in theStateMachineAuthoring.AddStateToStatesBuffer()method MyStateMachineSystemiterates over all state machine entities, and for each one, handles callingOnStateUpdate()on whichever state is set as theCurrentState. It also handles transitions