123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- using UnityEngine;
- using System.Collections;
- namespace RootMotion.FinalIK {
-
-
-
- public class AimController : MonoBehaviour {
- [Tooltip("Reference to the AimIK component.")]
-
-
-
- public AimIK ik;
- [Tooltip("Master weight of the IK solver.")]
-
-
-
- [Range(0f, 1f)] public float weight = 1f;
- [Header("Target Smoothing")]
- [Tooltip("The target to aim at. Do not use the Target transform that is assigned to AimIK. Set to null if you wish to stop aiming.")]
-
-
-
- public Transform target;
- [Tooltip("The time it takes to switch targets.")]
-
-
-
- public float targetSwitchSmoothTime = 0.3f;
- [Tooltip("The time it takes to blend in/out of AimIK weight.")]
-
-
-
- public float weightSmoothTime = 0.3f;
- [Header("Turning Towards The Target")]
- [Tooltip("Enables smooth turning towards the target according to the parameters under this header.")]
-
-
-
- public bool smoothTurnTowardsTarget = true;
- [Tooltip("Speed of turning towards the target using Vector3.RotateTowards.")]
-
-
-
- public float maxRadiansDelta = 3f;
- [Tooltip("Speed of moving towards the target using Vector3.RotateTowards.")]
-
-
-
- public float maxMagnitudeDelta = 3f;
- [Tooltip("Speed of slerping towards the target.")]
-
-
-
- public float slerpSpeed = 3f;
- [Tooltip("Smoothing time for turning towards the yaw and pitch of the target using Mathf.SmoothDampAngle. Value of 0 means smooth damping is disabled." )]
-
-
-
- public float smoothDampTime = 0f;
- [Tooltip("The position of the pivot that the aim target is rotated around relative to the root of the character.")]
-
-
-
- public Vector3 pivotOffsetFromRoot = Vector3.up;
- [Tooltip("Minimum distance of aiming from the first bone. Keeps the solver from failing if the target is too close.")]
-
-
-
- public float minDistance = 1f;
- [Tooltip("Offset applied to the target in world space. Convenient for scripting aiming inaccuracy.")]
-
-
-
- public Vector3 offset;
- [Header("RootRotation")]
- [Tooltip("Character root will be rotate around the Y axis to keep root forward within this angle from the aiming direction.")]
-
-
-
- [Range(0f, 180f)] public float maxRootAngle = 45f;
- [Tooltip("If enabled, aligns the root forward to target direction after 'Max Root Angle' has been exceeded.")]
-
-
-
- public bool turnToTarget;
- [Tooltip("The time of turning towards the target direction if 'Max Root Angle has been exceeded and 'Turn To Target' is enabled.")]
-
-
-
- public float turnToTargetTime = 0.2f;
- [Header("Mode")]
- [Tooltip("If true, AimIK will consider whatever the current direction of the weapon to be the forward aiming direction and work additively on top of that. This enables you to use recoil and reloading animations seamlessly with AimIK. Adjust the Vector3 value below if the weapon is not aiming perfectly forward in the aiming animation clip.")]
-
-
-
- public bool useAnimatedAimDirection;
- [Tooltip("The direction of the animated weapon aiming in character space. Tweak this value to adjust the aiming. 'Use Animated Aim Direction' must be enabled for this property to work.")]
-
-
-
- public Vector3 animatedAimDirection = Vector3.forward;
- private Transform lastTarget;
- private float switchWeight, switchWeightV;
- private float weightV;
- private Vector3 lastPosition;
- private Vector3 dir;
- private bool lastSmoothTowardsTarget;
- private bool turningToTarget;
- private float turnToTargetMlp = 1f;
- private float turnToTargetMlpV;
- void Start() {
- lastPosition = ik.solver.IKPosition;
- dir = ik.solver.IKPosition - pivot;
- ik.solver.target = null;
- }
- void LateUpdate () {
-
- if (target != lastTarget) {
- if (lastTarget == null && target != null && ik.solver.IKPositionWeight <= 0f)
- {
- lastPosition = target.position;
- dir = target.position - pivot;
- ik.solver.IKPosition = target.position + offset;
- }
- else
- {
- lastPosition = ik.solver.IKPosition;
- dir = ik.solver.IKPosition - pivot;
- }
- switchWeight = 0f;
- lastTarget = target;
- }
-
- float targetWeight = target != null ? weight : 0f;
- ik.solver.IKPositionWeight = Mathf.SmoothDamp(ik.solver.IKPositionWeight, targetWeight, ref weightV, weightSmoothTime);
- if (ik.solver.IKPositionWeight >= 0.999f && targetWeight > ik.solver.IKPositionWeight) ik.solver.IKPositionWeight = 1f;
- if (ik.solver.IKPositionWeight <= 0.001f && targetWeight < ik.solver.IKPositionWeight) ik.solver.IKPositionWeight = 0f;
- if (ik.solver.IKPositionWeight <= 0f) return;
-
- switchWeight = Mathf.SmoothDamp(switchWeight, 1f, ref switchWeightV, targetSwitchSmoothTime);
- if (switchWeight >= 0.999f) switchWeight = 1f;
- if (target != null) {
- ik.solver.IKPosition = Vector3.Lerp(lastPosition, target.position + offset, switchWeight);
- }
-
- if (smoothTurnTowardsTarget != lastSmoothTowardsTarget) {
- dir = ik.solver.IKPosition - pivot;
- lastSmoothTowardsTarget = smoothTurnTowardsTarget;
- }
- if (smoothTurnTowardsTarget) {
- Vector3 targetDir = ik.solver.IKPosition - pivot;
-
- if (slerpSpeed > 0f) dir = Vector3.Slerp(dir, targetDir, Time.deltaTime * slerpSpeed);
-
- if (maxRadiansDelta > 0 || maxMagnitudeDelta > 0f) dir = Vector3.RotateTowards(dir, targetDir, Time.deltaTime * maxRadiansDelta, maxMagnitudeDelta);
-
- if (smoothDampTime > 0f)
- {
- float yaw = V3Tools.GetYaw(dir);
- float targetYaw = V3Tools.GetYaw(targetDir);
- float y = Mathf.SmoothDampAngle(yaw, targetYaw, ref yawV, smoothDampTime);
- float pitch = V3Tools.GetPitch(dir);
- float targetPitch = V3Tools.GetPitch(targetDir);
- float p = Mathf.SmoothDampAngle(pitch, targetPitch, ref pitchV, smoothDampTime);
- float dirMag = Mathf.SmoothDamp(dir.magnitude, targetDir.magnitude, ref dirMagV, smoothDampTime);
- dir = Quaternion.Euler(p, y, 0f) * Vector3.forward * dirMag;
- }
- ik.solver.IKPosition = pivot + dir;
- }
-
- ApplyMinDistance();
-
- RootRotation();
-
- if (useAnimatedAimDirection) {
- ik.solver.axis = ik.solver.transform.InverseTransformVector(ik.transform.rotation * animatedAimDirection);
- }
- }
- private float yawV, pitchV, dirMagV;
-
- private Vector3 pivot {
- get {
- return ik.transform.position + ik.transform.rotation * pivotOffsetFromRoot;
- }
- }
-
- void ApplyMinDistance() {
- Vector3 aimFrom = pivot;
- Vector3 direction = (ik.solver.IKPosition - aimFrom);
- direction = direction.normalized * Mathf.Max(direction.magnitude, minDistance);
-
- ik.solver.IKPosition = aimFrom + direction;
- }
-
- private void RootRotation() {
- float max = Mathf.Lerp(180f, maxRootAngle * turnToTargetMlp, ik.solver.IKPositionWeight);
- if (max < 180f) {
- Vector3 faceDirLocal = Quaternion.Inverse(ik.transform.rotation) * (ik.solver.IKPosition - pivot);
- float angle = Mathf.Atan2(faceDirLocal.x, faceDirLocal.z) * Mathf.Rad2Deg;
- float rotation = 0f;
- if (angle > max) {
- rotation = angle - max;
- if (!turningToTarget && turnToTarget) StartCoroutine(TurnToTarget());
- }
- if (angle < -max) {
- rotation = angle + max;
- if (!turningToTarget && turnToTarget) StartCoroutine(TurnToTarget());
- }
- ik.transform.rotation = Quaternion.AngleAxis(rotation, ik.transform.up) * ik.transform.rotation;
- }
- }
-
- private IEnumerator TurnToTarget()
- {
- turningToTarget = true;
-
- while (turnToTargetMlp > 0f)
- {
- turnToTargetMlp = Mathf.SmoothDamp(turnToTargetMlp, 0f, ref turnToTargetMlpV, turnToTargetTime);
- if (turnToTargetMlp < 0.01f) turnToTargetMlp = 0f;
-
- yield return null;
- }
- turnToTargetMlp = 1f;
- turningToTarget = false;
- }
- }
- }
|