左がUnityのWizardで作った元々のRagDoll
右のポニーテールが自分でCharacterJointを設定して作ったRagDoll
ボーン構造として
Head ↑ Torso → Arm → Elbow ↑ HipMaster → Hip → Kneee
それぞれにRigidBodyを設定して、
TorsoとHipMasterはBoxColliderで、HeadはSphereCollider。あとはCapsuleCollider
CharacterColliderの親は、矢印の逆向きのRigidBodyに対して設定。
具体的には、
階層サーチして目的のボーンを見つけて、そこにRigidBodyとCharacterJointとColliderをAddする
GameObject bb = FindDeep(ob, name); bb.AddComponent(typeof(Rigidbody)); bb.GetComponent<Rigidbody>().useGravity = true; bb.GetComponent<Rigidbody>().mass = 1; bb.AddComponent(typeof(CharacterJoint)); bb.GetComponent<CharacterJoint>().connectedBody = parent; bb.GetComponent<CharacterJoint>().enablePreprocessing = false;
CharcaterJointの関節可動域を設定する
CharacterJoint cj = bb.GetComponent<CharacterJoint>(); cj.lowTwistLimit = setJointLimit(cj.lowTwistLimit, -40); cj.highTwistLimit = setJointLimit(cj.highTwistLimit, 0); cj.swing1Limit = setJointLimit(cj.swing1Limit, 0); cj.swing2Limit = setJointLimit(cj.swing2Limit, 0);
これは関節ごとに値が違うので、元のRagDollを参考に設定していく。
bb.GetComponent<CharacterJoint>().axis = new Vector3(0, 1, 0); bb.GetComponent<CharacterJoint>().swingAxis = new Vector3(0, 0, 1);
軸の向きも関節ごとに違う
重さも、腕とか頭はmass=1ぐらいで、hipMaster、torso、hipやKneeは3ぐらいが設定されていた。
ただ、このボーンの名称もキャラごとに違うので、なかなか汎用性のあるものは作りにくいかも。
ボーン番号が変わってもいいように検索で判定する版
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Research { public class Main : MonoBehaviour { public GameObject aa; public GameObject cc; public GameObject ob; public GameObject ob2; public float timer=3f; void Start() { ob = GameObject.Find("LongPonny"); ob2 = GameObject.Find("halfup_sailor_Ragdoll"); cc = FindDeep(ob,"joint_HipMaster"); cc.AddComponent(typeof(Rigidbody)); cc.GetComponent<Rigidbody>().useGravity = true; cc.GetComponent<Rigidbody>().mass = 3; cc.AddComponent(typeof(BoxCollider)); cc.GetComponent<BoxCollider>().size = new Vector3(0.2f, 0.2f, 0.2f); aa = FindDeep(ob, "joint_Torso"); aa.AddComponent(typeof(Rigidbody)); aa.GetComponent<Rigidbody>().useGravity = true; aa.GetComponent<Rigidbody>().mass=3; aa.AddComponent(typeof(CharacterJoint)); aa.GetComponent<CharacterJoint>().connectedBody = FindDeep(ob, "joint_HipMaster").GetComponent<Rigidbody>(); aa.GetComponent<CharacterJoint>().axis = new Vector3(1, 0, 0); aa.GetComponent<CharacterJoint>().swingAxis = new Vector3(0, 0, 1); CharacterJoint cj = aa.GetComponent<CharacterJoint>(); cj.lowTwistLimit= setJointLimit(cj.lowTwistLimit, -20); cj.highTwistLimit = setJointLimit(cj.highTwistLimit, 20); cj.swing1Limit = setJointLimit(cj.swing1Limit, 10); cj.swing2Limit = setJointLimit(cj.swing2Limit, 0); aa.AddComponent(typeof(BoxCollider)); aa.GetComponent<BoxCollider>().size = new Vector3(0.2f, 0.2f, 0.2f); SetSpring("joint_LeftHip", FindDeep(ob, "joint_HipMaster").GetComponent<Rigidbody>()); SetSpring("joint_LeftKnee", FindDeep(ob, "joint_LeftHip").GetComponent<Rigidbody>()); SetSpring("joint_RightHip", FindDeep(ob, "joint_HipMaster").GetComponent<Rigidbody>()); SetSpring("joint_RightKnee", FindDeep(ob, "joint_RightHip").GetComponent<Rigidbody>()); SetSpring("joint_LeftArm", FindDeep(ob, "joint_Torso").GetComponent<Rigidbody>()); SetSpring("joint_LeftElbow", FindDeep(ob,"joint_LeftArm").GetComponent<Rigidbody>()); SetSpring("joint_RightArm", FindDeep(ob, "joint_Torso").GetComponent<Rigidbody>()); SetSpring("joint_RightElbow", FindDeep(ob, "joint_RightArm").GetComponent<Rigidbody>()); SetSpring("joint_Head", FindDeep(ob, "joint_Torso").GetComponent<Rigidbody>()); return; } void Update() { timer -= Time.deltaTime; if(timer<=0) { GameObject cc = FindDeep(ob, "joint_HipMaster"); cc.GetComponent<Rigidbody>().AddForce(80*Vector3.up,ForceMode.Impulse); cc = FindDeep(ob2, "joint_HipMaster"); cc.GetComponent<Rigidbody>().AddForce(80 * Vector3.up, ForceMode.Impulse); timer = 3; } } void SetSpring(string name,Rigidbody parent) { GameObject bb = FindDeep(ob, name); bb.AddComponent(typeof(Rigidbody)); bb.GetComponent<Rigidbody>().useGravity = true; bb.GetComponent<Rigidbody>().mass = 1; bb.AddComponent(typeof(CharacterJoint)); bb.GetComponent<CharacterJoint>().connectedBody = parent; bb.GetComponent<CharacterJoint>().enablePreprocessing = false; CharacterJoint cj = bb.GetComponent<CharacterJoint>(); cj.swing1Limit = setJointLimit(cj.swing1Limit, 0); cj.swing2Limit = setJointLimit(cj.swing2Limit, 0); if (name.IndexOf("Head") >= 0) { bb.AddComponent(typeof(SphereCollider)); bb.GetComponent<SphereCollider>().center = new Vector3(0,0.04f,0); bb.GetComponent<SphereCollider>().radius = 0.045f; bb.GetComponent<CharacterJoint>().axis = new Vector3(1, 0, 0); bb.GetComponent<CharacterJoint>().swingAxis = new Vector3(0, 0, 1); cj.lowTwistLimit = setJointLimit(cj.lowTwistLimit, -40); cj.highTwistLimit = setJointLimit(cj.highTwistLimit, 0); cj.swing1Limit = setJointLimit(cj.swing1Limit, 25); } else { bb.AddComponent(typeof(CapsuleCollider)); bb.GetComponent<CapsuleCollider>().direction = 0; bb.GetComponent<CapsuleCollider>().height = 0.2f; bb.GetComponent<CapsuleCollider>().radius = 0.1f; } if ( name.IndexOf("Arm")>=0) { bb.GetComponent<CharacterJoint>().axis = new Vector3(0, 1, 0); bb.GetComponent<CharacterJoint>().swingAxis = new Vector3(0, 0, 1); cj.swing1Limit = setJointLimit(cj.swing1Limit, 50); bb.GetComponent<CapsuleCollider>().height = 0.16f; bb.GetComponent<CapsuleCollider>().radius = 0.04f; } if (name.IndexOf("Elbow") >= 0) { bb.GetComponent<CapsuleCollider>().height = 0.3f; bb.GetComponent<CapsuleCollider>().radius = 0.058f; bb.GetComponent<CharacterJoint>().axis = new Vector3(0, 0, 1); bb.GetComponent<CharacterJoint>().swingAxis = new Vector3(0, 1, 0); cj.lowTwistLimit = setJointLimit(cj.lowTwistLimit, -90); cj.highTwistLimit = setJointLimit(cj.highTwistLimit, 0); } if ( name.IndexOf("Hip") >= 0) { bb.GetComponent<Rigidbody>().mass = 2; bb.GetComponent<CapsuleCollider>().direction = 1; bb.GetComponent<CharacterJoint>().axis = new Vector3(1,0, 0); bb.GetComponent<CharacterJoint>().swingAxis = new Vector3(0, 0, 1); bb.GetComponent<CapsuleCollider>().center = new Vector3(0,-0.159f,0); bb.GetComponent<CapsuleCollider>().height = 0.318f; bb.GetComponent<CapsuleCollider>().radius = 0.095f; cj.lowTwistLimit = setJointLimit(cj.lowTwistLimit, -20); cj.highTwistLimit = setJointLimit(cj.highTwistLimit, 70); cj.swing1Limit = setJointLimit(cj.swing1Limit, 30); } if (name.IndexOf("Knee") >= 0) { bb.GetComponent<Rigidbody>().mass = 2; bb.GetComponent<CapsuleCollider>().direction = 1; bb.GetComponent<CapsuleCollider>().height = 0.4f; bb.GetComponent<CapsuleCollider>().radius = 0.1f; bb.GetComponent<CharacterJoint>().axis = new Vector3(1, 0, 0); bb.GetComponent<CharacterJoint>().swingAxis = new Vector3(0, 0, 1); cj.lowTwistLimit = setJointLimit(cj.lowTwistLimit, -80); cj.highTwistLimit = setJointLimit(cj.highTwistLimit, 0); } } SoftJointLimit setJointLimit(SoftJointLimit a,int b) { a.limit = b; return a; } GameObject FindDeep(GameObject self, string name) { Transform[] children = self.GetComponentsInChildren<Transform>(); foreach (Transform t in children) { if (t.name.IndexOf(name)>=0) return t.gameObject; } return null; } } }