namespace TurnTheGameOn.IKDriver { using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; [System.Serializable, RequireComponent(typeof(Animator))] public class IKD_IKDriver : MonoBehaviour { public Animator animator; // animator for calling IK functions public Transform lhswt_W, lhswt_NW, lhswt_N, lhswt_NE, lhswt_E, lhswt_SE, lhswt_S, lhswt_SW; // left hand steering wheel IK targets public Transform rhswt_W, rhswt_NW, rhswt_N, rhswt_NE, rhswt_E, rhswt_SE, rhswt_S, rhswt_SW; // right hand steering wheel IK targets public Transform leftFootIdle, rightFootIdle, footClutch, footBrake, footGas, handShift; // public Transform leftHandObj, rightHandObj, leftFootObj, rightFootObj; // current IK targets public Transform headLookIKCP, targetLeftHandIK, targetRightHandIK, targetRightFootIK, targetLeftFootIK; // Avatar IK control points public bool controlSteeringWheel = true; public Transform readOnlySteeringWheel; public Transform steeringWheel; public SpeedType speedType; public Rigidbody vehicleRigidbody; // for calculating steering wheel shake value public Text gearText; //assign the gear UI text component, when this components text changes a shift will be triggered public enum TargetSide { Left, Right, None } public TargetSide shiftHand = TargetSide.Right, clutchFoot = TargetSide.Left, brakeFoot = TargetSide.Right, gasFoot = TargetSide.Right; // avatar options public enum SteeringTargets { Two, All } public SteeringTargets steeringTargets; public Vector3 avatarPosition, lookPosition, defaultSteering; public IKD_RCC_CarControllerReference rccReference; public bool useRCCInput; [Range (0,1)] public float wheelShake = 1; [Range (0,360)] public float steeringWheelRotation; //maximum rotation of steering wheel transform on x axis [Range (0,90)] public float steeringWheelRotationTwoTargets = 85f; public float lookTargetPosX; //the look target transform position.x value public float rotationSpeed; public float steeringRotationSpeed = 0.07f; public float defaultLookXPos, maxLookRight, maxLookLeft; //the maximum distance the look target can move left or right of the default position public float minLookSpeed, maxLookSpeed; //use min speed when steering, max to snap back speed the look object will use when not steering public bool ikActive = false; //enable/disable IK control of the avatar public bool shift; //set this bool to true to trigger a shift public bool enableShifting = true; public bool mobile; public string steeringAxis = "Horizontal", throttleAxis = "Vertical"; public string editorView = "avatar"; private float lookObjMoveSpeed; //the speed at which the look target object will move private float horizontalInput, verticalInput; private float tempShake; private float targetY; private float zAngle; private float yVelocity; private float rotationLimit; private string gearString; private bool shifting; //used to determine when the right hand should target a steering wheel target or shift target void Start () { if(TurnTheGameOn.IKDriver.IKD_StaticUtility.m_IKD_UtilitySettings.useMobileController) mobile = true; if (useRCCInput && !rccReference) rccReference = GetComponent <IKD_RCC_CarControllerReference> (); transform.localPosition = avatarPosition; lookTargetPosX = defaultLookXPos; TargetShifter (); rotationLimit = steeringTargets == SteeringTargets.Two ? steeringWheelRotationTwoTargets : steeringWheelRotation; wheelCP = shiftHand == TargetSide.Left ? targetLeftHandIK : shiftHand == TargetSide.Right ? targetRightHandIK : null; } void OnAnimatorIK () { if (animator && ikActive && rightHandObj != null) { SetShiftState (); SetSteeringWheelRotation (); SetIKValues (AvatarIKGoal.LeftHand, 1, 1, targetLeftHandIK.position, targetLeftHandIK.rotation); SetIKValues (AvatarIKGoal.RightHand, 1, 1, targetRightHandIK.position, targetRightHandIK.rotation); SetIKValues (AvatarIKGoal.LeftFoot, 1, 1, targetLeftFootIK.position, targetLeftFootIK.rotation); SetIKValues (AvatarIKGoal.RightFoot, 1, 1, targetRightFootIK.position, targetRightFootIK.rotation); GetInput (); UpdateHandTransforms (); UpdateFootTransforms (); UpdateIKTargetTransforms (); UpdateIKLook (); } else { ZeroIKWeight (AvatarIKGoal.LeftHand); ZeroIKWeight (AvatarIKGoal.RightHand); ZeroIKWeight (AvatarIKGoal.LeftFoot); ZeroIKWeight (AvatarIKGoal.RightFoot); animator.SetLookAtWeight (0); } } void SetShiftState () { if (gearText.text != gearString) { gearString = gearText.text; if (enableShifting) TargetShifter (); } if (shift) { shift = false; if (enableShifting) TargetShifter (); } } void SetSteeringWheelRotation () { if (controlSteeringWheel) { if (steeringWheel != null) { tempShake = Random.Range (1.0f, 2.0f); float speedometerMultiplier = speedType == SpeedType.MPH ? 2.23693629f : speedType == SpeedType.KPH ? 3.6f : 0f; tempShake = tempShake * wheelShake * 50 * LinearDistance (0, 150, vehicleRigidbody.velocity.magnitude * speedometerMultiplier); tempShake = Random.Range (-tempShake, tempShake); targetY = Mathf.SmoothDamp (targetY, (-(horizontalInput * rotationLimit) - tempShake), ref yVelocity, rotationSpeed); zAngle = Mathf.SmoothDampAngle (steeringWheel.localEulerAngles.z, targetY, ref yVelocity, steeringRotationSpeed); steeringWheel.localEulerAngles = new Vector3 (defaultSteering.x, defaultSteering.y, zAngle); } } else { if (readOnlySteeringWheel != null) { targetY = readOnlySteeringWheel.localEulerAngles.z; } } } void SetIKValues (AvatarIKGoal goal, float positionWeight, float rotationWeight, Vector3 position, Quaternion rotation) { animator.SetIKPositionWeight (goal, positionWeight); animator.SetIKRotationWeight (goal, rotationWeight); animator.SetIKPosition (goal, position); animator.SetIKRotation (goal, rotation); } void ZeroIKWeight (AvatarIKGoal goal) { animator.SetIKPositionWeight (goal, 0); animator.SetIKRotationWeight (goal, 0); } void UpdateIKLook () { if (headLookIKCP != null) { animator.SetLookAtWeight (1); animator.SetLookAtPosition (headLookIKCP.position); } } void GetInput () { if (useRCCInput) { horizontalInput = rccReference.rcc_Horizontal; verticalInput = rccReference.rcc_Vertical; } else { horizontalInput = mobile ? TurnTheGameOn.IKDriver.IKD_CrossPlatformInputManager.GetAxis (steeringAxis) : Input.GetAxis (steeringAxis); verticalInput = mobile ? TurnTheGameOn.IKDriver.IKD_CrossPlatformInputManager.GetAxis (throttleAxis) : Input.GetAxis (throttleAxis); } } void UpdateHandTransforms () { if (steeringTargets == SteeringTargets.Two) { rightHandObj = rhswt_E; leftHandObj = lhswt_W; } else if (steeringTargets == SteeringTargets.All) { if (targetY >= 0.0f && targetY <= 90.0f) { leftHandObj = lhswt_W; rightHandObj = rhswt_E; } else if (targetY >= 90.0f && targetY <= 180.0f) { leftHandObj = lhswt_N; rightHandObj = rhswt_SW; } else if (targetY >= 180.0f && targetY <= 270.0f) { leftHandObj = lhswt_E; rightHandObj = rhswt_NW; } else if (targetY >=270f && targetY <=370f) { leftHandObj = lhswt_S; rightHandObj = rhswt_N; } else if (targetY >= -90.0f && targetY <= 0.0f) { leftHandObj = lhswt_W; rightHandObj = rhswt_E; } else if (targetY >= -180.0f && targetY <= -90.0f) { leftHandObj = lhswt_S; rightHandObj = rhswt_N; } else if (targetY >= -270.0f && targetY <= -180.0f) { leftHandObj = lhswt_E; rightHandObj = rhswt_W; } else if (targetY >= -370.0f && targetY <= -270.0f) { leftHandObj = lhswt_N; rightHandObj = rhswt_S; } } lookTargetPosX = horizontalInput > 0 ? defaultLookXPos + maxLookRight : horizontalInput < 0 ? defaultLookXPos + maxLookLeft : defaultLookXPos; lookObjMoveSpeed = horizontalInput > 0 || horizontalInput < 0 ? minLookSpeed : Mathf.Approximately (lookPosition.x, lookTargetPosX) ? minLookSpeed : Mathf.Lerp (lookObjMoveSpeed, maxLookSpeed, 1 * Time.deltaTime); } void UpdateFootTransforms () { if (verticalInput > 0) { if (gasFoot == TargetSide.Right) { rightFootObj = footGas; } else if (gasFoot == TargetSide.Left) { rightFootObj = rightFootIdle; leftFootObj = footGas; } } else if (verticalInput < 0) { if (gearString == "R") { //Reversing //Set Foot Gas if (gasFoot == TargetSide.Right) { rightFootObj = footGas; } else if (gasFoot == TargetSide.Left) { rightFootObj = rightFootIdle; leftFootObj = footGas; } } else { //Braking //Set Foot Brake if (brakeFoot == TargetSide.Right) { rightFootObj = footBrake; } else if (brakeFoot == TargetSide.Left) { leftFootObj = footBrake; } } } else { rightFootObj = rightFootIdle; } } float shiftLerp; Vector3 shitStartPosition; Quaternion shiftStartRotation; float holdShiftTimer; float shiftBackTimer; public float holdShiftTime = 0.25f; public float shiftBackTime = 0.75f; public float shiftAnimSpeed = 30.0f; public float IKSpeed = 8.0f; Vector3 pastFollowerPosition, pastTargetPosition; public AnimationCurve shiftCurve; public Transform wheelCP; public Transform returnShiftTarget; bool targetingWheel; void UpdateIKTargetTransforms () { targetRightFootIK.localPosition = Vector3.Lerp (targetRightFootIK.localPosition, rightFootObj.localPosition, 8 * Time.deltaTime); targetRightFootIK.localRotation = Quaternion.Lerp (targetRightFootIK.localRotation, rightFootObj.localRotation, 8 * Time.deltaTime); targetLeftFootIK.localPosition = Vector3.Lerp (targetLeftFootIK.localPosition, leftFootObj.localPosition, 8 * Time.deltaTime); targetLeftFootIK.localRotation = Quaternion.Lerp (targetLeftFootIK.localRotation, leftFootObj.localRotation, 8 * Time.deltaTime); if (shiftHand == TargetSide.Right) { if (shifting){ shiftLerp += shiftAnimSpeed * Time.deltaTime; if (shiftLerp <= 0.4f) { targetRightHandIK.position = Vector3.Lerp (targetRightHandIK.position, returnShiftTarget.position, LinearDistance(0.0f, 0.4f, shiftLerp)); targetRightHandIK.rotation = Quaternion.Lerp (shiftStartRotation, returnShiftTarget.rotation, LinearDistance(0.0f, 0.4f, shiftLerp)); } else if (shiftLerp >= 0.85f) { targetRightHandIK = handShift; holdShiftTimer += 1 * Time.deltaTime; if (holdShiftTimer >= holdShiftTime) { shifting = false; shiftBackTimer = 0.0f; shiftLerp = 0.0f; } } else { targetRightHandIK.position = Vector3.Lerp (returnShiftTarget.position, handShift.position, shiftCurve.Evaluate(shiftLerp)); targetRightHandIK.rotation = Quaternion.Lerp (shiftStartRotation, handShift.rotation, shiftCurve.Evaluate(shiftLerp)); } } else { if (shiftBackTimer <= shiftBackTime) { targetRightHandIK = wheelCP; shiftLerp += shiftAnimSpeed * Time.deltaTime; shiftBackTimer += 1 * Time.deltaTime; targetRightHandIK.position = Vector3.Lerp (handShift.position, returnShiftTarget.position, LinearDistance(0.0f, shiftBackTime, shiftBackTimer)); targetRightHandIK.rotation = Quaternion.Lerp (handShift.rotation, returnShiftTarget.rotation, LinearDistance(0.0f, shiftBackTime, shiftBackTimer)); } else { targetingWheel = true; targetRightHandIK.localPosition = Vector3.Lerp (targetRightHandIK.localPosition, rightHandObj.localPosition, IKSpeed); targetRightHandIK.localRotation = Quaternion.Lerp (targetRightHandIK.localRotation, rightHandObj.localRotation, 1); } } targetLeftHandIK.localPosition = Vector3.Slerp (targetLeftHandIK.localPosition, leftHandObj.localPosition, IKSpeed * Time.deltaTime); targetLeftHandIK.localRotation = Quaternion.Lerp (targetLeftHandIK.localRotation, leftHandObj.localRotation, 1); } else if (shiftHand == TargetSide.Left) { if (shifting){ shiftLerp += shiftAnimSpeed * Time.deltaTime; if (shiftLerp <= 0.4f) { targetLeftHandIK.position = Vector3.Lerp (targetLeftHandIK.position, returnShiftTarget.position, LinearDistance(0.0f, 0.4f, shiftLerp)); targetLeftHandIK.rotation = Quaternion.Lerp (shiftStartRotation, returnShiftTarget.rotation, LinearDistance(0.0f, 0.4f, shiftLerp)); } else if (shiftLerp >= 0.85f) { targetLeftHandIK = handShift; holdShiftTimer += 1 * Time.deltaTime; if (holdShiftTimer >= holdShiftTime) { shifting = false; shiftBackTimer = 0.0f; shiftLerp = 0.0f; } } else { targetLeftHandIK.position = Vector3.Lerp (returnShiftTarget.position, handShift.position, shiftCurve.Evaluate(shiftLerp)); targetLeftHandIK.rotation = Quaternion.Lerp (shiftStartRotation, handShift.rotation, shiftCurve.Evaluate(shiftLerp)); } } else { if (shiftBackTimer <= shiftBackTime) { targetLeftHandIK = wheelCP; shiftLerp += shiftAnimSpeed * Time.deltaTime; shiftBackTimer += 1 * Time.deltaTime; targetLeftHandIK.position = Vector3.Lerp (handShift.position, returnShiftTarget.position, LinearDistance(0.0f, shiftBackTime, shiftBackTimer)); targetLeftHandIK.rotation = Quaternion.Lerp (handShift.rotation, returnShiftTarget.rotation, LinearDistance(0.0f, shiftBackTime, shiftBackTimer)); } else { targetingWheel = true; targetLeftHandIK.localPosition = Vector3.Lerp (targetLeftHandIK.localPosition, leftHandObj.localPosition, IKSpeed); targetLeftHandIK.localRotation = Quaternion.Lerp (targetLeftHandIK.localRotation, leftHandObj.localRotation, 1); } } targetRightHandIK.localPosition = Vector3.Slerp (targetRightHandIK.localPosition, rightHandObj.localPosition, IKSpeed); targetRightHandIK.localRotation = Quaternion.Lerp (targetRightHandIK.localRotation, rightHandObj.localRotation, 1); } lookPosition = headLookIKCP.localPosition; lookPosition.x = Mathf.Lerp (lookPosition.x, lookTargetPosX, lookObjMoveSpeed * Time.deltaTime); headLookIKCP.localPosition = lookPosition; } public void TargetShifter () { if (!shifting && targetingWheel) { targetingWheel = false; shifting = true; shiftLerp = 0.0f; holdShiftTimer = 0.0f; if (shiftHand == TargetSide.Left) { shiftStartRotation = targetLeftHandIK.rotation; } else if (shiftHand == TargetSide.Right) { shiftStartRotation = targetRightHandIK.rotation; } if (clutchFoot == TargetSide.Left) leftFootObj = footClutch; else if (clutchFoot == TargetSide.Right) rightFootObj = footClutch; Invoke ("SetClutchFootIdle", 0.5f); } } public void SetClutchFootIdle () { if (clutchFoot == TargetSide.Left) leftFootObj = leftFootIdle; else if (clutchFoot == TargetSide.Right) rightFootObj = rightFootIdle; } float LinearDistance (float _start, float _end, float _position) { return Mathf.InverseLerp (_start, _end, _position); } } }