Example #1
0
        private void LateUpdate()
        {
            // Aim adjustments.
            if (controller.Aiming)
            {
                // Calculate desired rotation.
                Quaternion targetRotation = Quaternion.LookRotation(controller.personalTarget - spine.position);
                // Apply parent bones initial rotation offsets
                targetRotation *= Quaternion.Euler(initialRootRotation);
                targetRotation *= Quaternion.Euler(initialHipsRotation);
                targetRotation *= Quaternion.Euler(initialSpineRotation);
                // Apply extra rotation offsets (depends on the NPC avatar).
                targetRotation *= Quaternion.Euler(controller.classStats.aimOffset);
                // Set rotation for the frame.
                Quaternion frameRotation = Quaternion.Slerp(lastRotation, targetRotation, timeCountAim);

                // Simulate a simple bone constraint on upper body rotation.
                // Is spine rotation relative to the hips is less than 60 degrees?
                if (Quaternion.Angle(frameRotation, hips.rotation) <= 60f)
                {
                    // Set desired rotation.
                    spine.rotation = frameRotation;
                    timeCountAim  += Time.deltaTime;
                }
                // Avoid unrealistic rotation, related to hips and spine.
                else
                {
                    // Deal with over twist stuck situation, due to async rotation of spine and hips.
                    if (timeCountAim == 0 && Quaternion.Angle(frameRotation, hips.rotation) > 70f)
                    {
                        // Stop aiming and aim again after body realignment (1 second interval).
                        StartCoroutine(controller.UnstuckAim(1f));
                    }
                    // No over twist, freeze spine rotation until the desired one is 60 degrees or less, relative to hips.
                    spine.rotation = lastRotation;
                    timeCountAim   = 0;
                }
                // Grab rotation for next frame.
                lastRotation = spine.rotation;

                // Measure remain angle gap to desired aim orientation.
                Vector3 target = controller.personalTarget - gunMuzzle.position;
                Vector3 fwd    = -gunMuzzle.right;
                currentAimAngleGap = Vector3.Angle(target, fwd);

                timeCountGuard = 0;
            }
            // Guard position adjustments.
            else
            {
                lastRotation = spine.rotation;
                // Slowly reduce aim offset when exiting aim position.
                spine.rotation *= Quaternion.Slerp(Quaternion.Euler(controller.classStats.aimOffset), Quaternion.identity, timeCountGuard);
                timeCountGuard += Time.deltaTime;
            }
        }