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]publicinterfaceIMyState{publicvoidOnStateEnter(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData);publicvoidOnStateExit(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData);publicvoidOnStateUpdate(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData);}- 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]publicpartialstructStateA:IMyState{publicfloatDuration;publicfloat3MovementSpeed;privatefloat_durationCounter;publicvoidOnStateEnter(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData){_durationCounter=Duration;}publicvoidOnStateExit(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData){refData.Translation=refData.StateMachine.StartTranslation;}publicvoidOnStateUpdate(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData){refData.Translation+=MovementSpeed*inData.DeltaTime;_durationCounter-=inData.DeltaTime;if(_durationCounter<=0f){refData.StateMachine.CurrentStateIndex=refData.StateMachine.StateBIndex;}}}[Serializable]publicpartialstructStateB:IMyState{publicfloatDuration;publicfloat3RotationSpeed;privatefloat_durationCounter;publicvoidOnStateEnter(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData){_durationCounter=Duration;}publicvoidOnStateExit(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData){refData.Rotation=quaternion.identity;}publicvoidOnStateUpdate(refStateUpdateData_ReadWriterefData,inStateUpdateData_ReadOnlyinData){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 StateAStateAstateA=newStateA();MyStatestate=stateA.ToMyState();// Creating a StateA from a MyStateStateAstateA=newStateA(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