using UnityEngine; using System.Collections; namespace UnityChan { public class SpringBone : MonoBehaviour { //次のボーン public Transform child; //ボーンの向き public Vector3 boneAxis = new Vector3 (-1.0f, 0.0f, 0.0f); private float _defaultRadius = 0; public float radius = 0.05f; public float scale = 1f; //各SpringBoneに設定されているstiffnessForceとdragForceを使用するか? public bool isUseEachBoneForceSettings = false; //バネが戻る力 public float stiffnessForce = 0.01f; //力の減衰力 public float dragForce = 0.4f; public Vector3 springForce = new Vector3 (0.0f, -0.0001f, 0.0f); public SpringCollider[] colliders; public bool debug = true; //Kobayashi:Thredshold Starting to activate activeRatio public float threshold = 0.01f; private float springLength; private Quaternion localRotation; private Transform trs; private Vector3 currTipPos; private Vector3 prevTipPos; //Kobayashi private Transform org; //Kobayashi:Reference for "SpringManager" component with unitychan private SpringManager managerRef; private void Awake () { trs = transform; localRotation = transform.localRotation; //Kobayashi:Reference for "SpringManager" component with unitychan // GameObject.Find("unitychan_dynamic").GetComponent(); managerRef = GetParentSpringManager (transform); } private SpringManager GetParentSpringManager (Transform t) { var springManager = t.GetComponent (); if (springManager != null) return springManager; if (t.parent != null) { return GetParentSpringManager (t.parent); } return null; } private void Start () { springLength = Vector3.Distance (trs.position, child.position); currTipPos = child.position; prevTipPos = child.position; } public void UpdateSpring () { //Kobayashi org = trs; //回転をリセット trs.localRotation = Quaternion.identity * localRotation; float sqrDt = Time.deltaTime * Time.deltaTime; //stiffness Vector3 force = trs.rotation * (boneAxis * stiffnessForce) / sqrDt; //drag //Log("force :x = {0}, y = {1} z = {2}", force); //Log("prevTipPos :x = {0}, y = {1} z = {2}", prevTipPos); //Log("currTipPos :x = {0}, y = {1} z = {2}", currTipPos); force += (prevTipPos - currTipPos)* 2.3f / managerRef.transform.lossyScale.x * dragForce / sqrDt; force += springForce / sqrDt; //Log("force :x = {0}, y = {1} z = {2}", force); //前フレームと値が同じにならないように Vector3 temp = currTipPos; //verlet currTipPos = (currTipPos - prevTipPos) + currTipPos + (force * sqrDt); //長さを元に戻す currTipPos = ((currTipPos - trs.position).normalized * springLength) + trs.position; //衝突判定 for (int i = 0; i < colliders.Length; i++) { float dis = Vector3.Distance(currTipPos, colliders[i].transform.position); float radiusDis = radius + colliders[i].radius; if (dis <= radiusDis) { Vector3 normal = (currTipPos - colliders [i].transform.position).normalized; currTipPos = colliders [i].transform.position + (normal * (radius + colliders [i].radius)); currTipPos = ((currTipPos - trs.position).normalized * springLength) + trs.position; } } prevTipPos = temp; //回転を適用; Vector3 aimVector = trs.TransformDirection (boneAxis); Quaternion aimRotation = Quaternion.FromToRotation (aimVector, currTipPos - trs.position); //original //trs.rotation = aimRotation * trs.rotation; //Kobayahsi:Lerp with mixWeight Quaternion secondaryRotation = aimRotation * trs.rotation; trs.rotation = Quaternion.Lerp (org.rotation, secondaryRotation, managerRef.dynamicRatio); } private void Log(string str, Vector3 vect) { if (trs.name == "Bone003" && prevTipPos != currTipPos) { UnityEngine.Debug.LogError(string.Format(str, vect.x, vect.y, vect.z)); //UnityEngine.Debug.LogError(string.Format("dragForce = {0} stiness = {1}", dragForce, stiffnessForce)); } } public void SetRedius() { scale = 1; if (_defaultRadius == 0) { _defaultRadius = radius; } else { radius = _defaultRadius; } if (transform.parent) { SetScale(transform.parent); } radius = scale * radius; } private void SetScale(Transform trans) { scale *= trans.localScale.x; if (trans.parent) { SetScale(trans.parent); } } private void OnDrawGizmos () { currTipPos = child.position; Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(currTipPos, radius); } } }