You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			114 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C#
		
	
using UnityEngine;
 | 
						|
using System.Collections;
 | 
						|
 | 
						|
namespace RootMotion.FinalIK {
 | 
						|
 | 
						|
	/// <summary>
 | 
						|
	/// Base class for all FBBIK effector positionOffset modifiers. Works with animatePhysics, safe delegates, offset limits.
 | 
						|
	/// </summary>
 | 
						|
	public abstract class OffsetModifier: MonoBehaviour {
 | 
						|
 | 
						|
		/// <summary>
 | 
						|
		/// Limiting effector position offsets
 | 
						|
		/// </summary>
 | 
						|
		[System.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 = 0f;
 | 
						|
			[Tooltip("Which axes to limit the offset on?")]
 | 
						|
			public bool x, y, z;
 | 
						|
			[Tooltip("The limits")]
 | 
						|
			public float minX, maxX, minY, maxY, minZ, maxZ;
 | 
						|
			
 | 
						|
			// Apply the limit to the effector
 | 
						|
			public void Apply(IKEffector e, Quaternion rootRotation) {
 | 
						|
				Vector3 offset = Quaternion.Inverse(rootRotation) * e.positionOffset;
 | 
						|
				
 | 
						|
				if (spring <= 0f) {
 | 
						|
					// Hard limits
 | 
						|
					if (x) offset.x = Mathf.Clamp(offset.x, minX, maxX);
 | 
						|
					if (y) offset.y = Mathf.Clamp(offset.y, minY, maxY);
 | 
						|
					if (z) offset.z = Mathf.Clamp(offset.z, minZ, maxZ);
 | 
						|
				} else {
 | 
						|
					// Soft limits
 | 
						|
					if (x) offset.x = SpringAxis(offset.x, minX, maxX);
 | 
						|
					if (y) offset.y = SpringAxis(offset.y, minY, maxY);
 | 
						|
					if (z) offset.z = SpringAxis(offset.z, minZ, maxZ);
 | 
						|
				}
 | 
						|
				
 | 
						|
				// Apply to the effector
 | 
						|
				e.positionOffset = rootRotation * offset;
 | 
						|
			}
 | 
						|
			
 | 
						|
			// Just math for limiting floats
 | 
						|
			private float SpringAxis(float value, float min, float max) {
 | 
						|
				if (value > min && value < max) return value;
 | 
						|
				if (value < min) return Spring(value, min, true);
 | 
						|
				return Spring(value, max, false);
 | 
						|
			}
 | 
						|
			
 | 
						|
			// Spring math
 | 
						|
			private float Spring(float value, float limit, bool negative) {
 | 
						|
				float illegal = value - limit;
 | 
						|
				float s = illegal * spring;
 | 
						|
				
 | 
						|
				if (negative) return value + Mathf.Clamp(-s, 0, -illegal);
 | 
						|
				return value - Mathf.Clamp(s, 0, illegal);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		[Tooltip("The master weight")]
 | 
						|
		public float weight = 1f;
 | 
						|
 | 
						|
		[Tooltip("Reference to the FBBIK component")]
 | 
						|
		public FullBodyBipedIK ik;
 | 
						|
 | 
						|
		// not using Time.deltaTime or Time.fixedDeltaTime here, because we don't know if animatePhysics is true or not on the character, so we have to keep track of time ourselves.
 | 
						|
		protected float deltaTime { get { return Time.time - lastTime; }}
 | 
						|
		protected abstract void OnModifyOffset();
 | 
						|
 | 
						|
		protected float lastTime;
 | 
						|
 | 
						|
		protected virtual void Start() {
 | 
						|
			StartCoroutine(Initiate());
 | 
						|
		}
 | 
						|
		
 | 
						|
		private IEnumerator Initiate() {
 | 
						|
			while (ik == null) yield return null;
 | 
						|
 | 
						|
			// You can use just LateUpdate, but note that it doesn't work when you have animatePhysics turned on for the character.
 | 
						|
			ik.solver.OnPreUpdate += ModifyOffset;
 | 
						|
			lastTime = Time.time;
 | 
						|
		}
 | 
						|
 | 
						|
		// The main function that checks for all conditions and calls OnModifyOffset if they are met
 | 
						|
		private void ModifyOffset() {
 | 
						|
			if (!enabled) return;
 | 
						|
			if (weight <= 0f) return;
 | 
						|
			if (ik == null) return;
 | 
						|
			weight = Mathf.Clamp(weight, 0f, 1f);
 | 
						|
			if (deltaTime <= 0f) return;
 | 
						|
 | 
						|
			OnModifyOffset();
 | 
						|
 | 
						|
			lastTime = Time.time;
 | 
						|
		}
 | 
						|
 | 
						|
		protected void ApplyLimits(OffsetLimits[] limits) {
 | 
						|
			// Apply the OffsetLimits
 | 
						|
			foreach (OffsetLimits limit in limits) {
 | 
						|
				limit.Apply(ik.solver.GetEffector(limit.effector), transform.rotation);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Remove the delegate when destroyed
 | 
						|
		protected virtual void OnDestroy() {
 | 
						|
			if (ik != null) ik.solver.OnPreUpdate -= ModifyOffset;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 |