using UnityEngine; using System.Collections; using System; namespace RootMotion.Dynamics { public partial class PuppetMaster : MonoBehaviour { #if UNITY_EDITOR [ContextMenu("Save Settings As Humanoid Config")] private void SaveToHumanoidConfig() { var path = "Assets/Saved Humanoid Config.asset"; if (targetRoot == null) { Debug.LogWarning("Please assign 'Target Root' for PuppetMaster using a Humanoid Config.", transform); return; } if (targetAnimator == null) { Debug.LogError("PuppetMaster 'Target Root' does not have an Animator component. Can not use Humanoid Config.", transform); return; } if (!targetAnimator.isHuman) { Debug.LogError("PuppetMaster target is not a Humanoid. Can not use Humanoid Config.", transform); return; } var p = ScriptableObject.CreateInstance(); p.state = state; p.stateSettings = stateSettings; p.mode = mode; p.blendTime = blendTime; p.fixTargetTransforms = fixTargetTransforms; p.solverIterationCount = solverIterationCount; p.visualizeTargetPose = visualizeTargetPose; p.mappingWeight = mappingWeight; p.pinWeight = pinWeight; p.muscleWeight = muscleWeight; p.muscleSpring = muscleSpring; p.muscleDamper = muscleDamper; p.pinPow = pinPow; p.pinDistanceFalloff = pinDistanceFalloff; p.angularPinning = angularPinning; p.updateJointAnchors = updateJointAnchors; p.supportTranslationAnimation = supportTranslationAnimation; p.angularLimits = angularLimits; p.internalCollisions = internalCollisions; p.muscles = new PuppetMasterHumanoidConfig.HumanoidMuscle[muscles.Length]; var allHumanBodyBones = (HumanBodyBones[])System.Enum.GetValues(typeof(HumanBodyBones)); for (int i = 0; i < muscles.Length; i++) { var m = muscles[i]; var h = new PuppetMasterHumanoidConfig.HumanoidMuscle(); h.props = new Muscle.Props(); h.bone = GetHumanBodyBone(m.target, allHumanBodyBones); h.props.group = m.props.group; h.props.mappingWeight = m.props.mappingWeight; h.props.muscleDamper = m.props.muscleDamper; h.props.muscleWeight = m.props.muscleWeight; h.props.pinWeight = m.props.pinWeight; p.muscles[i] = h; } UnityEditor.AssetDatabase.CreateAsset(p, path); UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.Refresh(); var saved = UnityEditor.AssetDatabase.LoadAssetAtPath(path, typeof(PuppetMasterHumanoidConfig)) as PuppetMasterHumanoidConfig; if (saved != null) { Debug.Log("PuppetMasterHumanoidConfig successfully created at " + path); UnityEditor.Selection.activeObject = saved; } } private HumanBodyBones GetHumanBodyBone(Transform t, HumanBodyBones[] allBones) { for (int i = 0; i < allBones.Length - 1; i++) { var bone = allBones[i]; if (targetAnimator.GetBoneTransform(bone) == t) return bone; } //Debug.LogError("Unable to find HumanBodyBone of Transform " + t.name, transform); return HumanBodyBones.LastBone; } #endif } [CreateAssetMenu(fileName = "PuppetMaster Humanoid Config", menuName = "PuppetMaster/Humanoid Config", order = 1)] public class PuppetMasterHumanoidConfig : ScriptableObject { [System.Serializable] public class HumanoidMuscle { [HideInInspector] public string name; public HumanBodyBones bone; public Muscle.Props props; } [LargeHeader("Simulation")] public PuppetMaster.State state; public PuppetMaster.StateSettings stateSettings = PuppetMaster.StateSettings.Default; public PuppetMaster.Mode mode; public float blendTime = 0.1f; public bool fixTargetTransforms = true; public int solverIterationCount = 6; public bool visualizeTargetPose = true; [LargeHeader("Master Weights")] [Range(0f, 1f)] public float mappingWeight = 1f; [Range(0f, 1f)] public float pinWeight = 1f; [Range(0f, 1f)] public float muscleWeight = 1f; [LargeHeader("Joint and Muscle Settings")] public float muscleSpring = 100f; public float muscleDamper = 0f; [Range(1f, 8f)] public float pinPow = 4f; [Range(0f, 100f)] public float pinDistanceFalloff = 5; public bool angularPinning; public bool updateJointAnchors = true; public bool supportTranslationAnimation; public bool angularLimits; public bool internalCollisions; [LargeHeader("Individual Muscle Settings")] public HumanoidMuscle[] muscles = new HumanoidMuscle[0]; /// /// Applies this config to the specified PuppetMaster. /// /// P. public void ApplyTo(PuppetMaster p) { if (p.targetRoot == null) { Debug.LogWarning("Please assign 'Target Root' for PuppetMaster using a Humanoid Config.", p.transform); return; } if (p.targetAnimator == null) { Debug.LogError("PuppetMaster 'Target Root' does not have an Animator component. Can not use Humanoid Config.", p.transform); return; } if (!p.targetAnimator.isHuman) { Debug.LogError("PuppetMaster target is not a Humanoid. Can not use Humanoid Config.", p.transform); return; } p.state = state; p.stateSettings = stateSettings; p.mode = mode; p.blendTime = blendTime; p.fixTargetTransforms = fixTargetTransforms; p.solverIterationCount = solverIterationCount; p.visualizeTargetPose = visualizeTargetPose; p.mappingWeight = mappingWeight; p.pinWeight = pinWeight; p.muscleWeight = muscleWeight; p.muscleSpring = muscleSpring; p.muscleDamper = muscleDamper; p.pinPow = pinPow; p.pinDistanceFalloff = pinDistanceFalloff; p.angularPinning = angularPinning; p.updateJointAnchors = updateJointAnchors; p.supportTranslationAnimation = supportTranslationAnimation; p.angularLimits = angularLimits; p.internalCollisions = internalCollisions; for (int i = 0; i < muscles.Length; i++) { var m = GetMuscle(muscles[i].bone, p.targetAnimator, p); if (m == null && i < p.muscles.Length) { m = p.muscles[i]; } if (m != null) { var h = muscles[i]; m.props.group = h.props.group; m.props.mappingWeight = h.props.mappingWeight; //m.props.mapPosition = h.props.mapPosition; m.props.muscleDamper = h.props.muscleDamper; m.props.muscleWeight = h.props.muscleWeight; m.props.pinWeight = h.props.pinWeight; } } } private Muscle GetMuscle(HumanBodyBones boneId, Animator animator, PuppetMaster puppetMaster) { if (boneId == HumanBodyBones.LastBone) return null; Transform bone = animator.GetBoneTransform(boneId); if (bone == null) return null; foreach (Muscle m in puppetMaster.muscles) { if (m.target == bone) return m; } return null; } } }