162 lines
3.4 KiB
C#
162 lines
3.4 KiB
C#
using System;
|
|
using System.Collections;
|
|
using UnityEngine;
|
|
|
|
namespace RootMotion.FinalIK
|
|
{
|
|
public abstract class OffsetModifier : MonoBehaviour
|
|
{
|
|
[Serializable]
|
|
public class OffsetLimits
|
|
{
|
|
[Tooltip("The effector type (this is just an enum)")]
|
|
public FullBodyBipedEffector effector;
|
|
|
|
[Tooltip("Spring force, if zero then this is a hard limit, if not, offset can exceed the limit.")]
|
|
public float spring;
|
|
|
|
[Tooltip("Which axes to limit the offset on?")]
|
|
public bool x;
|
|
|
|
[Tooltip("Which axes to limit the offset on?")]
|
|
public bool y;
|
|
|
|
[Tooltip("Which axes to limit the offset on?")]
|
|
public bool z;
|
|
|
|
[Tooltip("The limits")]
|
|
public float minX;
|
|
|
|
[Tooltip("The limits")]
|
|
public float maxX;
|
|
|
|
[Tooltip("The limits")]
|
|
public float minY;
|
|
|
|
[Tooltip("The limits")]
|
|
public float maxY;
|
|
|
|
[Tooltip("The limits")]
|
|
public float minZ;
|
|
|
|
[Tooltip("The limits")]
|
|
public float maxZ;
|
|
|
|
public void Apply(IKEffector e, Quaternion rootRotation)
|
|
{
|
|
Vector3 vector = Quaternion.Inverse(rootRotation) * e.positionOffset;
|
|
if (spring <= 0f)
|
|
{
|
|
if (x)
|
|
{
|
|
vector.x = Mathf.Clamp(vector.x, minX, maxX);
|
|
}
|
|
if (y)
|
|
{
|
|
vector.y = Mathf.Clamp(vector.y, minY, maxY);
|
|
}
|
|
if (z)
|
|
{
|
|
vector.z = Mathf.Clamp(vector.z, minZ, maxZ);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (x)
|
|
{
|
|
vector.x = SpringAxis(vector.x, minX, maxX);
|
|
}
|
|
if (y)
|
|
{
|
|
vector.y = SpringAxis(vector.y, minY, maxY);
|
|
}
|
|
if (z)
|
|
{
|
|
vector.z = SpringAxis(vector.z, minZ, maxZ);
|
|
}
|
|
}
|
|
e.positionOffset = rootRotation * vector;
|
|
}
|
|
|
|
private float SpringAxis(float value, float min, float max)
|
|
{
|
|
if (value > min && value < max)
|
|
{
|
|
return value;
|
|
}
|
|
if (value < min)
|
|
{
|
|
return Spring(value, min, negative: true);
|
|
}
|
|
return Spring(value, max, negative: false);
|
|
}
|
|
|
|
private float Spring(float value, float limit, bool negative)
|
|
{
|
|
float num = value - limit;
|
|
float num2 = num * spring;
|
|
if (negative)
|
|
{
|
|
return value + Mathf.Clamp(0f - num2, 0f, 0f - num);
|
|
}
|
|
return value - Mathf.Clamp(num2, 0f, num);
|
|
}
|
|
}
|
|
|
|
[Tooltip("The master weight")]
|
|
public float weight = 1f;
|
|
|
|
[Tooltip("Reference to the FBBIK component")]
|
|
public FullBodyBipedIK ik;
|
|
|
|
protected float lastTime;
|
|
|
|
protected float deltaTime => Time.time - lastTime;
|
|
|
|
protected abstract void OnModifyOffset();
|
|
|
|
protected virtual void Start()
|
|
{
|
|
StartCoroutine(Initiate());
|
|
}
|
|
|
|
private IEnumerator Initiate()
|
|
{
|
|
while (ik == null)
|
|
{
|
|
yield return null;
|
|
}
|
|
IKSolverFullBodyBiped solver = ik.solver;
|
|
solver.OnPreUpdate = (IKSolver.UpdateDelegate)Delegate.Combine(solver.OnPreUpdate, new IKSolver.UpdateDelegate(ModifyOffset));
|
|
lastTime = Time.time;
|
|
}
|
|
|
|
private void ModifyOffset()
|
|
{
|
|
if (base.enabled && !(weight <= 0f) && !(deltaTime <= 0f) && !(ik == null))
|
|
{
|
|
weight = Mathf.Clamp(weight, 0f, 1f);
|
|
OnModifyOffset();
|
|
lastTime = Time.time;
|
|
}
|
|
}
|
|
|
|
protected void ApplyLimits(OffsetLimits[] limits)
|
|
{
|
|
foreach (OffsetLimits offsetLimits in limits)
|
|
{
|
|
offsetLimits.Apply(ik.solver.GetEffector(offsetLimits.effector), base.transform.rotation);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnDestroy()
|
|
{
|
|
if (ik != null)
|
|
{
|
|
IKSolverFullBodyBiped solver = ik.solver;
|
|
solver.OnPreUpdate = (IKSolver.UpdateDelegate)Delegate.Remove(solver.OnPreUpdate, new IKSolver.UpdateDelegate(ModifyOffset));
|
|
}
|
|
}
|
|
}
|
|
}
|