AIプログラムとかUnityゲーム開発について

探索や学習などを活用したAI系ゲームを作りたいと思います。

CharacterJointを設定して自分でRagDollを作ってみる

左がUnityのWizardで作った元々のRagDoll
右のポニーテールが自分でCharacterJointを設定して作ったRagDoll


【Unity】プログラムで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;
        }
    }
}