using RootMotion.FinalIK; using UnityEngine; namespace RootMotion.Demos { public class FPSAiming : MonoBehaviour { [Range(0f, 1f)] public float aimWeight = 1f; [Range(0f, 1f)] public float sightWeight = 1f; [Range(0f, 180f)] public float maxAngle = 80f; public Vector3 aimOffset; public bool animatePhysics; public Transform gun; public Transform gunTarget; public FullBodyBipedIK ik; public AimIK gunAim; public CameraControllerFPS cam; public Recoil recoil; [Range(0f, 1f)] public float cameraRecoilWeight = 0.5f; public Vector3 gunTargetDefaultLocalPosition; public Vector3 gunTargetDefaultLocalRotation; private Vector3 camDefaultLocalPosition; private Vector3 camRelativeToGunTarget; private bool updateFrame; private void Start() { gunTargetDefaultLocalPosition = gunTarget.localPosition; gunTargetDefaultLocalRotation = gunTarget.localEulerAngles; camDefaultLocalPosition = cam.transform.localPosition; cam.enabled = false; gunAim.enabled = false; ik.enabled = false; if (recoil != null && ik.solver.iterations == 0) { Debug.LogWarning("FPSAiming with Recoil needs FBBIK solver iteration count to be at least 1 to maintain accuracy."); } } private void FixedUpdate() { updateFrame = true; } private void LateUpdate() { if (!animatePhysics) { updateFrame = true; } if (updateFrame) { updateFrame = false; cam.transform.localPosition = camDefaultLocalPosition; camRelativeToGunTarget = gunTarget.InverseTransformPoint(cam.transform.position); cam.LateUpdate(); RotateCharacter(); Aiming(); LookDownTheSight(); } } private void Aiming() { if (!(aimWeight <= 0f)) { Quaternion rotation = cam.transform.rotation; gunAim.solver.IKPosition = cam.transform.position + cam.transform.forward * 10f + cam.transform.rotation * aimOffset; gunAim.solver.IKPositionWeight = aimWeight; gunAim.solver.Update(); cam.transform.rotation = rotation; } } private void LookDownTheSight() { float t = aimWeight * sightWeight; gunTarget.position = Vector3.Lerp(gun.position, gunTarget.parent.TransformPoint(gunTargetDefaultLocalPosition), t); gunTarget.rotation = Quaternion.Lerp(gun.rotation, gunTarget.parent.rotation * Quaternion.Euler(gunTargetDefaultLocalRotation), t); Vector3 position = gun.InverseTransformPoint(ik.solver.leftHandEffector.bone.position); Vector3 position2 = gun.InverseTransformPoint(ik.solver.rightHandEffector.bone.position); Quaternion quaternion = Quaternion.Inverse(gun.rotation) * ik.solver.leftHandEffector.bone.rotation; Quaternion quaternion2 = Quaternion.Inverse(gun.rotation) * ik.solver.rightHandEffector.bone.rotation; float num = 1f; ik.solver.leftHandEffector.positionOffset += (gunTarget.TransformPoint(position) - (ik.solver.leftHandEffector.bone.position + ik.solver.leftHandEffector.positionOffset)) * num; ik.solver.rightHandEffector.positionOffset += (gunTarget.TransformPoint(position2) - (ik.solver.rightHandEffector.bone.position + ik.solver.rightHandEffector.positionOffset)) * num; ik.solver.headMapping.maintainRotationWeight = 1f; if (recoil != null) { recoil.SetHandRotations(gunTarget.rotation * quaternion, gunTarget.rotation * quaternion2); } ik.solver.Update(); if (recoil != null) { ik.references.leftHand.rotation = recoil.rotationOffset * (gunTarget.rotation * quaternion); ik.references.rightHand.rotation = recoil.rotationOffset * (gunTarget.rotation * quaternion2); } else { ik.references.leftHand.rotation = gunTarget.rotation * quaternion; ik.references.rightHand.rotation = gunTarget.rotation * quaternion2; } cam.transform.position = Vector3.Lerp(cam.transform.position, Vector3.Lerp(gunTarget.TransformPoint(camRelativeToGunTarget), gun.transform.TransformPoint(camRelativeToGunTarget), cameraRecoilWeight), t); } private void RotateCharacter() { if (maxAngle >= 180f) { return; } if (maxAngle <= 0f) { base.transform.rotation = Quaternion.LookRotation(new Vector3(cam.transform.forward.x, 0f, cam.transform.forward.z)); return; } Vector3 vector = base.transform.InverseTransformDirection(cam.transform.forward); float num = Mathf.Atan2(vector.x, vector.z) * 57.29578f; if (Mathf.Abs(num) > Mathf.Abs(maxAngle)) { float angle = num - maxAngle; if (num < 0f) { angle = num + maxAngle; } base.transform.rotation = Quaternion.AngleAxis(angle, base.transform.up) * base.transform.rotation; } } } }