Search Unity

Created an Editor to adjust Ragdoll Mass

Discussion in 'Scripting' started by lpye, Apr 27, 2019.

  1. lpye

    lpye

    Joined:
    Aug 2, 2012
    Posts:
    30
    I've recently run into a situation where I needed to alter the mass for each part of a humanoid ragdoll in my Unity game. I had blindly accepted the default mass of '20' in the ragdoll wizard and Unity happily apportioned that 20 mass units across the various parts of the ragdoll. I'm not sure what unit of measure we should pretend Unity uses that makes sense to apply 20 of to represent an adult humanoid, but here we are.

    Anyway, I wrote the following script to create an editor that would allow you to choose an object representing the highest level ancestor of your ragdoll, then choose a new mass. It then collects the current mass total, creates a ratio, then applies that ratio to each of the child rigidbodies.

    Code (CSharp):
    1. /*
    2. * Permission is hereby granted, free of charge, to any person obtaining
    3. * a copy of this software and associated documentation files (the
    4. * "Software"), to deal in the Software without restriction, including
    5. * without limitation the rights to use, copy, modify, merge, publish,
    6. * distribute, sublicense, and/or sell copies of the Software, and to
    7. * permit persons to whom the Software is furnished to do so, subject to
    8. * the following conditions:
    9. *
    10. * The above copyright notice and this permission notice shall be
    11. * included in all copies or substantial portions of the Software.
    12. *
    13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    14. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    15. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    16. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    17. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    18. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    19. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    20. *
    21. */
    22. using UnityEngine;
    23. using UnityEditor;
    24.  
    25. namespace Pyehouse.Editors
    26. {
    27.     public class RagdollMassAdjuster : EditorWindow
    28.     {
    29.         // Can be anything, make it smaller if you like...
    30.         // just preventing divide by zero
    31.         private const float SMALL_MASS_EPSILON = 0.00001f;
    32.  
    33.         private static bool TooSmall(float m)
    34.         {
    35.             return System.Math.Abs(m) < SMALL_MASS_EPSILON;
    36.         }
    37.  
    38.         private static RagdollMassAdjuster editor;
    39.         private static int width = 350;
    40.         private static int height = 300;
    41.         private static int x = 0;
    42.         private static int y = 0;
    43.  
    44.         private bool noRigidbodies = false;
    45.         private bool currentMassTooSmall = false;
    46.         private float newMass = 20f;
    47.         private GameObject ragdollParent;
    48.  
    49.         private void Awake()
    50.         {
    51.             ragdollParent = Selection.activeGameObject;
    52.             Rigidbody[] rigidbodies = ragdollParent.GetComponentsInChildren<Rigidbody>();
    53.             if (rigidbodies != null && rigidbodies.Length > 0)
    54.             {
    55.                 float mass = 0f;
    56.                 foreach (Rigidbody rigidbody in rigidbodies)
    57.                 {
    58.                     mass += rigidbody.mass;
    59.                 }
    60.  
    61.                 currentMassTooSmall = TooSmall(mass);
    62.  
    63.                 newMass = mass;
    64.                 noRigidbodies = false;
    65.             }
    66.             else
    67.             {
    68.                 newMass = 20f;
    69.                 noRigidbodies = true;
    70.             }
    71.         }
    72.  
    73.         [MenuItem("Window/Pyehouse/Ragdoll Mass Adjuster")]
    74.         static void ShowEditor()
    75.         {
    76.             CenterWindow();
    77.         }
    78.  
    79.         private static void CenterWindow()
    80.         {
    81.             editor = EditorWindow.GetWindow<RagdollMassAdjuster>();
    82.             x = (Screen.currentResolution.width - width) / 2;
    83.             y = (Screen.currentResolution.height - height) / 2;
    84.             editor.position = new Rect(x, y, width, height);
    85.             editor.maxSize = new Vector2(width, height);
    86.             editor.minSize = editor.maxSize;
    87.         }
    88.  
    89.         private void OnGUI()
    90.         {
    91.             if (currentMassTooSmall)
    92.             {
    93.                 EditorGUILayout.HelpBox(string.Format("Current mass of selected ragdoll is too small: {0}", newMass), MessageType.Error);
    94.             }
    95.             else if (noRigidbodies)
    96.             {
    97.                 EditorGUILayout.HelpBox("No rigidbodies present in selected GameObject or children.", MessageType.Error);
    98.             }
    99.             else
    100.             {
    101.                 EditorStyles.label.wordWrap = true;
    102.                 EditorGUILayout.HelpBox("The new mass will be applied, maintaining the same per-object ratio as currently exists.", MessageType.Info);
    103.                 EditorGUILayout.HelpBox("So if your head is currently 3 out of a total 20 and you want a total mass of 100, your head will become 15.", MessageType.Info);
    104.  
    105.                 newMass = EditorGUILayout.FloatField("New Mass for Ragdoll:", newMass);
    106.  
    107.                 if (GUILayout.Button("Update Mass"))
    108.                 {
    109.                     UpdateMass(newMass);
    110.                 }
    111.             }
    112.         }
    113.  
    114.         private void UpdateMass(float toMass)
    115.         {
    116.             if (ragdollParent == null) return;
    117.  
    118.             Rigidbody[] rigidbodies = ragdollParent.GetComponentsInChildren<Rigidbody>();
    119.             if (rigidbodies == null || rigidbodies.Length < 1)
    120.             {
    121.                 Debug.LogErrorFormat("No rigidbodies found on selected object.");
    122.                 return;
    123.             }
    124.  
    125.             float fromMass = 0f;
    126.             foreach (Rigidbody rigidbody in rigidbodies)
    127.             {
    128.                 fromMass += rigidbody.mass;
    129.             }
    130.  
    131.             if (TooSmall(fromMass))
    132.             {
    133.                 Debug.LogErrorFormat("Current mass too small: {0}", fromMass);
    134.                 return;
    135.             }
    136.  
    137.             float ratio = toMass / fromMass;
    138.             foreach (Rigidbody rigidbody in rigidbodies)
    139.             {
    140.                 rigidbody.mass *= ratio;
    141.  
    142.                 EditorUtility.SetDirty(rigidbody);
    143.                 EditorSceneManager.MarkSceneDirty(rigidbody.transform.gameObject.scene);
    144.             }
    145.         }
    146.     }
    147. }
    https://www.pyehouse.com/2019/04/27/ragdoll-mass-editor-for-unity/
     
    Last edited: Apr 27, 2019
    webik150, TheHammer1 and SparrowGS like this.
  2. lpye

    lpye

    Joined:
    Aug 2, 2012
    Posts:
    30
    Added the following at lines 142/143 to handle prefab mode:

    EditorUtility.SetDirty(rigidbody);
    EditorSceneManager.MarkSceneDirty(rigidbody.transform.gameObject.scene);
     
  3. aidangig56

    aidangig56

    Joined:
    Aug 10, 2012
    Posts:
    105
    Also add
    Code (CSharp):
    1. using UnityEditor.SceneManagement;
    to top to fix
    Code (CSharp):
    1. EditorSceneManager.MarkSceneDirty(rigidbody.transform.gameObject.scene);