SCIO Development Blog
iPhone game development with Unity3D, Blender and XCode by Kay Bothfeld
C# Code Generator As Add-on for Unity3D Ragdoll Wizard
- Hits: 2113
- 5 Comments
- Subscribe to updates
![]()
Using Unity's ragdoll wizard leads to the problem that the prefab connection to the character model is broken. That means after a change of the model in your 3D software yo have to perform the whole procedure again. To avoid this I wrote an open source code generator that saves all ragdoll components in a C# factory class which you can invoke at runtime.
Introduction
Within games most often a character is moving without control of the physics engine (i.e. kinematic) as long as it is alive. Then when it comes to a crash you want to behave it like a rag doll under full control of the physics engine. You can easily build all joints, colliders and rigid bodies of your rigged model with Unity's Ragdoll wizard.The result is not too bad and with a little tweaking of angles, limits, masses and whatsoever you will have a spectacular show down.
The price you pay is that your game object is disconnected from the original model as FBX import. Applying changes to your model (in my case a .blend file) will have no effect on the game object until you do a revert of it and execute the ragdoll wizard again. It appears like there is no simple solution - at least I never got an answer to my question.
So I decided to write a little code generator based on Unity's editor classes' interface that creates the code of a C# code as factory class containing everything to assign the components at runtime. The basic idea is to traverse all character joints from a selected bone and generate the code for creating the joints themselves as well as the colliders and rigid bodies with all their properties. The generated class (looks similar to this sample code) is then included in the project and will be compiled like every other class. It offers a public method to be called at runtime to create the ragdoll components on the fly.
Quick Start
I assume that you have a model prefab imported as FBX from Blender, Maya, ... let's called it PlayerModel. It consists of a hierarchy of bones. The left thigh is for example PlayerModel/Armature/Hips/Thighs_L
- Initial setup
- Make a backup of your project / perform a commit to your repository
- Optionally make a copy of your model, rename it and disable it. This is just for convenience especially if you are modifying the generator itself
- Apply the ragdoll wizard to create all components - the model's prefab connection will be broken
- Download RagdollCodeGenerator.cs
- Place it in a folder MyProject/Assets/Editor/ and switch back to Unity
After a few seconds there should be a new menu item Tools/Generate Ragdoll Code. If not, restart Unity (if ever, this will be needed only the very first time) - Code generation
- Select the root bone Hips
- Execute Tools/Generate Ragdoll Code and select folder and file name (will be used as class name automatically), e.g Assets/Scripts/Player/RagdollFactoryGenerated.cs.
The newly created file (RagdollFactoryGenerated.cs) can be found at the specified place - Select the model and click revert at the top of the inspector tab. This will restore the model's prefab connection to the .FBX file
- Code for runtime
- In your existing source code look for an appropriate place where the collision is detected and add:
RagdollFactoryGenerated factory = new RagdollFactoryGenerated ();
factory.CreateRagdollComponents (gameObject);
foreach (Rigidbody rigidbody in factory.allRigidbodies) {
rigidbody.isKinematic = false;
rigidbody.useGravity = true;
if (rigidbody.collider != null) {
rigidbody.collider.isTrigger = false;
}
}
Fine-Tuning
Generation
If you don't want to use the complete rig you can alternatively select the bones for which you like to generate code. But anyway all children are considered too. If something goes wrong, check the Unity editor log.
If you want a specific physic material to be assigned to the colliders you can put it to folder Assets/Resources. The default name is RuntimeMaterials/Physic/PlayerPhysicMaterial but can you use an arbitrary material and edit the following line inRagdollCodeGenerator.cs :
private static string physicMaterialPath = "RuntimeMaterials/Physic/PlayerPhysicMaterial";
At Runtime
Whenever I integrate generated code to my projects, I use a facade for encapsulating calls to it to get more control. So I told the generator to create a class RagdollFactoryGenerated and I created a RagdollFactory manually for exclusive access to RagdollFactoryGenerated. Additionally I prefer a singleton pattern. Here is the code:
public class RagdollFactory {
private static RagdollFactoryGenerated instance = null;
internal static RagdollFactoryGenerated SharedInstance {
get {
if (instance == null) {
instance = new RagdollFactoryGenerated ();
}
return instance;
}
}
public static void CreateRagdollComponents (GameObject gameObject) {
SharedInstance.CreateRagdollComponents (gameObject);
}
}
In the initialisation phase of your application just call
RagdollFactory.CreateRagdollComponents (gameObject);
If you need explicit access to the generated Collider, Rigidbody or CharacrerJoint objects, this is provided by public member RagdollFactoryGenerated.allColliders, ... The main use case is setting all rigid bodies' IsKinematic flag. Another cool scenario is adding script components to your bone objects to set up a fine grained compound collider with its own collision detection.
Additionally every created bone has a member variable assigned. Again all access to these members should be limited to the encapsulating RagdollFactory class and in this case I'd suggest giving it a more comprehensible name like PlayRagdollHandler because its responsibility is not limited to creation process.
All generated methods are marked as virtual to enable overriding by subclasses. This is an option for further fine tuning but may be the second best choice. Always take into consideration the possibilities offered by the code generator. If something needs to be improved it might be easier to change the generator's code and perform regeneration.
Tweaking Parameters in Editor Mode
In order to do some fine-tuning on the ragdoll components in editor mode you need to go the other way round: create all the components from source code in editor mode and apply them again to your original model. To accomplish this you find another menu item Tools/Assign Ragdoll Components. Select the model, execute and your model will have all components in editor mode (obviously this enforces losing the prefab connection temporarily).
Now you can tweak the parameters or add new ragdoll components manually. To test your changes at runtime, you should disable the call to CreateRagdollComponents. If everything works fine, perform a Tools/Generate Ragdoll Code to "bake" your changes to RagdollFactoryGenerated.cs again and do a revert on your model to re-enable prefab connection.
Summary And Outlook
This was a quick hack. Although I think it's not too hard to understand, it has at least the following design flaws:
- Blob class anti pattern: One class with 450 lines of code is too huge.
- No split of responsibility. Utility functions for formatting should be put in their own class. Creation of colliders, ... and should rather be done in own classes.
- Class methods only. To get a class hierarchy like in (2), static methods need to be converted to instance member functions.
Another open issue deals with the javascript community. While the editor class might stay in C#, mixing the languages at runtime sounds like a bad idea so a 2nd interface for javascript output is needed to fit their needs.
In general code generators are powerful tools. If you are new to this topic and feel inspired to use them in your project, yes they are cool and provide sometimes elegant solutions. But I recommend alway to investigate alternative ways that are easier to go and less complex. As a rule of thumb I use them when I have no control over the source and there is a need to reflect changes. Their use is not limited to your favourite programming language. You can write SQL statements accessing DDL tables to generate other (DML) statements or you can use XSLT to generate a java class from an XML file.
If you are interested to enhance the above ragdoll code generator please drop a comment or contact me.
Kay
Comments
Pain Relief with Unity3D v3.5
Starting with the new version you now don't loose prefab connection automatically, which was the number one reason for me to implement this little code generator. Nevertheless I stay with it because it gives me maximum freedom even in case of reverting the model.
Great information
Hello,
Thanks for sharing such wonderful information. I wasn't aware of this before.