using System; using System.Collections.Generic; using UnityEngine; [Serializable] public class IKMgrData { public TBody Body { get; private set; } public Transform KinematicTgt { get { return this.m_KinematicTgt; } } public IKMgrData.IKParam PointIK { get { return this.m_PointIK; } } public IKMgrData.IKParam RotateIK { get { return this.m_RotateIK; } } public TBody.IKCMO IKCmo { get { return this.m_IKCmo; } } public bool IsIkExec { get { return this.PointIK.IsIKExec || this.RotateIK.IsIKExec; } } private void IkCmoPorc(Vector3 tgt, Vector3 vechand_offset) { if (this.m_KinematicList.Count < 3) { return; } for (int i = 0; i < 3; i++) { this.IKCmo.Porc(this.m_KinematicList[2], this.m_KinematicList[1], this.m_KinematicList[0], tgt, vechand_offset); } } private void TransratePoint(Vector3 tgt_pos, Quaternion tgt_rot, Vector3 tgt_offset) { Vector3 vector = tgt_pos + tgt_rot * tgt_offset; Debug.DrawLine(tgt_pos, vector, Color.white); for (int i = 0; i < 5; i++) { Vector3 a = vector; if (this.m_AttachPointData != null) { Vector3 normalized = (this.KinematicTgt.position - this.KinematicTgt.parent.position).normalized; float d = Vector3.Dot(this.m_AttachPointData.AttachTrans.position - this.KinematicTgt.position, normalized); a += this.KinematicTgt.position + normalized * d - this.m_AttachPointData.AttachTrans.position; } for (int j = 1; j < this.m_KinematicList.Count; j++) { bool flag = j + 1 < this.m_KinematicList.Count; Vector3 vector2 = Vector3.zero; if (flag) { Quaternion rotation = Quaternion.FromToRotation(this.m_KinematicList[j - 1].position - this.m_KinematicList[j].position, a - this.m_KinematicList[j].position) * this.m_KinematicList[j].rotation; Vector3 point = this.m_KinematicList[j].InverseTransformPoint(this.m_KinematicList[j - 1].position); Vector3 b = this.m_KinematicList[j].position + rotation * point; vector2 = this.m_KinematicList[j].position + (a - b); this.m_KinematicList[j + 1].rotation = Quaternion.FromToRotation(this.m_KinematicList[j].position - this.m_KinematicList[j + 1].position, vector2 - this.m_KinematicList[j + 1].position) * this.m_KinematicList[j + 1].rotation; } this.m_KinematicList[j].rotation = Quaternion.FromToRotation(this.m_KinematicList[j - 1].position - this.m_KinematicList[j].position, a - this.m_KinematicList[j].position) * this.m_KinematicList[j].rotation; if (flag) { a = vector2; } } for (int k = this.m_KinematicList.Count - 1; k > 0; k--) { Debug.DrawLine(this.m_KinematicList[k].position, this.m_KinematicList[k - 1].position, Color.Lerp(Color.red, Color.yellow, (float)i / 4f)); } if (this.m_AttachPointData != null) { Debug.DrawLine(this.KinematicTgt.position, this.m_AttachPointData.AttachTrans.position, Color.Lerp(Color.red, Color.yellow, (float)i / 4f)); } } } private void TransratePoint(Transform tgt, Vector3 tgt_offset) { this.TransratePoint(tgt.position, tgt.rotation, tgt_offset); } private void ConstraintRot(Quaternion tgt_rot, Vector3 tgt_offset) { this.KinematicTgt.rotation = tgt_rot * Quaternion.Euler(tgt_offset); } private void ApplyIKSetting(IKMgrData.IKParam data) { if (this.IsExecLate) { return; } if (data.TgtMaid && data.TgtMaid != this.Body.maid && !data.TgtMaid.body0.LateUpdateEnd) { TBody body = data.TgtMaid.body0; body.OnLateUpdateEnd = (Action)Delegate.Combine(body.OnLateUpdateEnd, new Action(this.AfterExec)); data.IsIKExec = false; this.IsExecLate = true; return; } data.IsIKExec = true; if (data.Target != null) { Vector3 position = data.Target.position; Quaternion rotation = data.Target.rotation; switch (data.MyType) { case IKMgrData.IKAttachType.Point: Debug.DrawLine(position, position + rotation * Vector3.forward * 0.2f, Color.cyan); this.IkCmoPorc(position, data.TgtOffset); break; case IKMgrData.IKAttachType.Rotate: this.ConstraintRot(rotation, data.TgtOffset); break; case IKMgrData.IKAttachType.NewPoint: this.TransratePoint(data.Target, data.TgtOffset); break; } if (data.IsTgtAxis) { KasaiUtility.DrawAxis(position, rotation, 0.125f); } } else if (data.Tgt_AttachName != string.Empty) { if (this.Body.goSlot[data.Tgt_AttachSlot].morph != null) { if (data.TgtMaid != null && data.TgtMaid.body0 != null) { Vector3 vector; Quaternion rotation2; Vector3 vector2; data.TgtMaid.body0.goSlot[data.Tgt_AttachSlot].morph.GetAttachPoint(data.Tgt_AttachName, out vector, out rotation2, out vector2, false); switch (data.MyType) { case IKMgrData.IKAttachType.Point: Debug.DrawLine(vector, vector + rotation2 * Vector3.forward * 0.2f, Color.blue); this.IkCmoPorc(vector, data.TgtOffset); break; case IKMgrData.IKAttachType.Rotate: this.ConstraintRot(rotation2, data.TgtOffset); break; case IKMgrData.IKAttachType.NewPoint: if (data.AxisTgt) { rotation2 = data.AxisTgt.rotation; } this.TransratePoint(vector, rotation2, data.TgtOffset); break; } if (data.IsTgtAxis) { KasaiUtility.DrawAxis(vector, rotation2, 0.125f); } } else { data.IsIKExec = false; data.Tgt_AttachName = string.Empty; } } } else { data.IsIKExec = false; } } private void AfterExec() { this.IKExec(); if (!this.Body.IKExecLate) { this.Body.AutoTwist(); for (int i = 0; i < this.Body.goSlot.Count; i++) { if (this.Body.goSlot[i].obj != null) { this.Body.goSlot[i].CopyTrans(); } this.Body.goSlot[i].Update(); } } } public void SetKinematicTgt(Transform tgt, TBody body, int weight = 3) { this.m_KinematicTgt = tgt; this.Body = body; this.m_KinematicList.Clear(); int num = 0; Transform transform = tgt; while (num != weight) { this.m_KinematicList.Add(transform); Transform parent = transform.parent; if (!parent) { Debug.LogWarningFormat("IKのウェイトが大きすぎます:{0}", new object[] { weight }); break; } transform = parent; num++; } } public void IkCmoInit(TBody body) { if (this.m_KinematicList.Count < 3) { return; } this.IKCmo.Init(this.m_KinematicList[2], this.m_KinematicList[1], this.m_KinematicList[0], body); } public IKMgrData.IKParam GetIKParam(IKMgrData.IKAttachType attach_type) { if (attach_type == IKMgrData.IKAttachType.Rotate) { return this.RotateIK; } return this.PointIK; } public void IKExec() { this.IsExecLate = false; this.ApplyIKSetting(this.PointIK); this.ApplyIKSetting(this.RotateIK); if (this.IsIkExec && !this.IsExecLate) { if (this.m_AttachPointData != null) { KasaiUtility.DrawObjAxis(this.m_AttachPointData.AttachTrans, 0.0625f); } else { KasaiUtility.DrawObjAxis(this.KinematicTgt, 0.0625f); } if (!this.PointIK.IsIKExec) { for (int i = this.m_KinematicList.Count - 1; i > 0; i--) { Debug.DrawLine(this.m_KinematicList[i].position, this.m_KinematicList[i - 1].position, Color.cyan); } if (this.m_AttachPointData != null) { Debug.DrawLine(this.KinematicTgt.position, this.m_AttachPointData.AttachTrans.position, Color.cyan); } } } } public Transform CreateAttachPointObj(string obj_name, Transform parent, TBody body, string slot_name, string attach_name) { if (this.m_AttachPointData != null && this.m_AttachPointData.AttachTrans) { return this.m_AttachPointData.AttachTrans; } GameObject gameObject = new GameObject(obj_name); gameObject.transform.SetParent(parent, false); this.m_AttachPointData = new IKMgrData.AttachPointIKData(); this.m_AttachPointData.AttachTrans = gameObject.transform; this.m_AttachPointData.Tbody = body; this.m_AttachPointData.AttachName = attach_name; this.m_AttachPointData.SlotName = slot_name; return gameObject.transform; } public void SyncAttachPoint() { if (this.m_AttachPointData == null || !this.m_AttachPointData.AttachTrans) { return; } int slotNo = this.m_AttachPointData.Tbody.GetSlotNo(this.m_AttachPointData.SlotName); if (slotNo < 0 || slotNo >= this.m_AttachPointData.Tbody.goSlot.Count) { Debug.LogErrorFormat("スロット{0}は存在しません", new object[] { this.m_AttachPointData.SlotName }); return; } Vector3 position; Quaternion rotation; Vector3 localScale; this.m_AttachPointData.Tbody.goSlot[slotNo].morph.GetAttachPoint(this.m_AttachPointData.AttachName, out position, out rotation, out localScale, false); this.m_AttachPointData.AttachTrans.position = position; this.m_AttachPointData.AttachTrans.rotation = rotation; this.m_AttachPointData.AttachTrans.localScale = localScale; } private const int m_CorrectNum = 5; [SerializeField] private List m_KinematicList = new List(); [SerializeField] private Transform m_KinematicTgt; [SerializeField] private IKMgrData.IKParam m_PointIK = new IKMgrData.IKParam(IKMgrData.IKAttachType.NewPoint); [SerializeField] private IKMgrData.IKParam m_RotateIK = new IKMgrData.IKParam(IKMgrData.IKAttachType.Rotate); private TBody.IKCMO m_IKCmo = new TBody.IKCMO(); private IKMgrData.AttachPointIKData m_AttachPointData; public bool IsExecLate; public enum IKAttachType { Point, Rotate, NewPoint } [Serializable] public class IKParam { public IKParam(IKMgrData.IKAttachType type) { this.MyType = type; } public IKMgrData.IKAttachType MyType { get; private set; } public void ChangePointType(IKMgrData.IKAttachType type) { if (this.MyType == IKMgrData.IKAttachType.Rotate) { return; } this.MyType = type; } public bool IsPointAttach { get { return this.MyType != IKMgrData.IKAttachType.Rotate; } } public Transform Target; public Vector3 TgtOffset; public int Tgt_AttachSlot = -1; public string Tgt_AttachName = string.Empty; public Maid TgtMaid; public bool IsTgtAxis; public bool IsIKExec; public Transform AxisTgt; } private class AttachPointIKData { public Transform AttachTrans; public TBody Tbody; public string SlotName = string.Empty; public string AttachName = string.Empty; } }