コード例 #1
0
        /// <summary>
        /// Determines if we'll treat input as if we're strafing
        /// </summary>
        protected void SimulateStrafeInput()
        {
            // Direction we need to travel in
            Vector3 lDirection = mWaypointVector;

            lDirection.y = lDirection.y - _PathHeight;
            lDirection.Normalize();

            // Determine our view
            Vector3 lVerticalDirection = Vector3.Project(lDirection, _Transform.up);
            Vector3 lLateralDirection  = (lDirection - lVerticalDirection).normalized;

            mInputFromAvatarAngle = Vector3Ext.SignedAngle(_Transform.forward, lLateralDirection);

            // Determine our movement
            if (mTargetDistance > _StopDistance)
            {
                // Calculate our own slowing
                float lRelativeMoveSpeed = 1f;
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    float lSlowPercent = (mTargetDistance - _StopDistance) / (_SlowDistance - _StopDistance);
                    lRelativeMoveSpeed = ((1f - _SlowFactor) * lSlowPercent) + _SlowFactor;
                }

                // TRT 4/5/2016: Force the slow distance as an absolute value
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    lRelativeMoveSpeed = _SlowFactor;
                }

                lLateralDirection = _Transform.InverseTransformDirection(lLateralDirection);
                mMovementX        = lLateralDirection.x * lRelativeMoveSpeed;
                mMovementY        = lLateralDirection.z * lRelativeMoveSpeed;
            }

            // Grab extra input information if we can
            if (mMotionController._CameraTransform == null)
            {
                mInputFromCameraAngle = mInputFromAvatarAngle;
            }
            else
            {
                Vector3 lInputForward = new Vector3(mMovementX, 0f, mMovementY);

                // We do the inverse tilt so we calculate the rotation in "natural up" space vs. "actor up" space.
                Quaternion lInvTilt = QuaternionExt.FromToRotation(_Transform.up, Vector3.up);

                // Camera forward in "natural up"
                Vector3 lCameraForward = lInvTilt * mMotionController._CameraTransform.forward;

                // Create a quaternion that gets us from our world-forward to our camera direction.
                Quaternion lToCamera = Quaternion.LookRotation(lCameraForward, lInvTilt * _Transform.up);

                // Transform joystick from world space to camera space. Now the input is relative
                // to how the camera is facing.
                Vector3 lMoveDirection = lToCamera * lInputForward;
                mInputFromCameraAngle = NumberHelper.GetHorizontalAngle(lCameraForward, lMoveDirection);
            }
        }
コード例 #2
0
        public static Vector3 CalculateShotingDir(int seed, float yaw, float pitch, float spreadX, float spreadY)
        {
            Quaternion q       = Quaternion.Euler(pitch, yaw, 0);
            Vector3    forward = q.Forward();
            Vector3    right   = q.Right();
            Vector3    up      = q.Up();

            float x;
            float y;

            //,z;
            x = (float)UniformRandom.RandomFloat(seed + 0, -0.5, 0.5) +
                (float)UniformRandom.RandomFloat(seed + 1, -0.5, 0.5);
            y = (float)UniformRandom.RandomFloat(seed + 2, -0.5, 0.5) +
                (float)UniformRandom.RandomFloat(seed + 3, -0.5, 0.5);
            //z = x * x + y * y;
            float res1 = spreadX * x;
            float res2 = spreadY * y;

            right = Vector3Ext.Scale(right, res1);
            up    = Vector3Ext.Scale(up, res2);
            var newForward = Vector3Ext.Add(forward, right);

            newForward = Vector3Ext.Add(newForward, up);
            //_logger.InfoFormat("spreadX {0}, spreadY {1}, x {2} y {3}, right{4}, up{5}", spreadX, spreadY, x, y, right, up);
            return(newForward);
        }
コード例 #3
0
        /// <summary>
        /// Allows the motor to process after the camera and controller have completed
        /// </summary>
        public override void PostRigLateUpdate()
        {
            base.PostRigLateUpdate();

            // Determine if we rotate the anchor to match our rotation
            if (_RotateAnchor && Anchor != null)
            {
                if (_RotateAnchorAlias.Length == 0 || RigController.InputSource == null || RigController.InputSource.IsPressed(_RotateAnchorAlias))
                {
                    if (mCharacterController != null)
                    {
                        float lToCameraAngle = Vector3Ext.HorizontalAngleTo(Anchor.forward, RigController.Transform.forward, Anchor.up);

                        Quaternion lRotation = Quaternion.AngleAxis(lToCameraAngle, Vector3.up);
                        mCharacterController.Yaw = mCharacterController.Yaw * lRotation;
                        Anchor.rotation          = mCharacterController.Tilt * mCharacterController.Yaw;
                    }
                    else
                    {
                        float lToCameraAngle = Vector3Ext.HorizontalAngleTo(Anchor.forward, RigController.Transform.forward, Anchor.up);

                        Quaternion lRotation = Quaternion.AngleAxis(lToCameraAngle, Vector3.up);
                        Anchor.rotation = Anchor.rotation * lRotation;
                    }
                }
            }
        }
コード例 #4
0
        /// <summary>
        /// Calculate how much to move an rotate by
        /// </summary>
        /// <param name="rMove"></param>
        /// <param name="rRotate"></param>
        protected virtual void CalculateMove(Vector3 rWaypoint, ref Vector3 rMove, ref Quaternion rRotate)
        {
            float lDeltaTime = TimeManager.SmoothedDeltaTime;

            // Direction we need to travel in
            Vector3 lDirection = rWaypoint - transform.position;

            lDirection.y = lDirection.y - _PathHeight;
            lDirection.Normalize();

            // Determine our rotation
            Vector3 lVerticalDirection = Vector3.Project(lDirection, transform.up);
            Vector3 lLateralDirection  = lDirection - lVerticalDirection;

            float lYawAngle = Vector3Ext.SignedAngle(transform.forward, lLateralDirection);

            if (_RotationSpeed == 0f)
            {
                rRotate = Quaternion.AngleAxis(lYawAngle, transform.up);
            }
            else
            {
                rRotate = Quaternion.AngleAxis(Mathf.Sign(lYawAngle) * Mathf.Min(Mathf.Abs(lYawAngle), _RotationSpeed * lDeltaTime), transform.up);
            }

            // Determine the movement
            if (_UseNavMeshPosition)
            {
                rMove = mNavMeshAgent.nextPosition - transform.position;
            }
            // In this case, we'll calculate movement ourselves
            else
            {
                // Grab the base movement speed
                float lMoveSpeed = mRootMotionMovement.magnitude / lDeltaTime;
                if (lMoveSpeed == 0f)
                {
                    lMoveSpeed = _MovementSpeed;
                }

                // Calculate our own slowing
                float lRelativeMoveSpeed = 1f;
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    float lSlowPercent = (mTargetDistance - _StopDistance) / (_SlowDistance - _StopDistance);
                    lRelativeMoveSpeed = ((1f - _SlowFactor) * lSlowPercent) + _SlowFactor;
                }

                // TRT 4/5/2016: Force the slow distance as an absolute value
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    lMoveSpeed         = _SlowFactor;
                    lRelativeMoveSpeed = 1f;
                }

                // Set the final velocity based on the future rotation
                Quaternion lFutureRotation = transform.rotation * rRotate;
                rMove = lFutureRotation.Forward() * (lMoveSpeed * lRelativeMoveSpeed * lDeltaTime);
            }
        }
コード例 #5
0
        /// <summary>
        /// Allows the motor to process after the camera and controller have completed
        /// </summary>
        public override void PostRigLateUpdate()
        {
            base.PostRigLateUpdate();

            Transform lAnchorTransform = Anchor;

            // If the anchor updates its rotation based on the rig, we need to get the final position of the rig
            if (_IsActorMatchingRotation && (RigController.ActiveMotor == this))
            {
                RigController._Transform.position = lAnchorTransform.position + (lAnchorTransform.rotation * AnchorOffset) + (lAnchorTransform.rotation * _Offset);
                RigController._Transform.rotation = Quaternion.Euler(RigController._Transform.rotation.eulerAngles.x, lAnchorTransform.rotation.eulerAngles.y, 0f);
            }

            if (_RotateAnchor && lAnchorTransform != null)
            {
                bool lIsRotatingAnchor = _RotateAnchorAlias.Length == 0 || RigController.InputSource == null || RigController.InputSource.IsPressed(_RotateAnchorAlias);

                if (lIsRotatingAnchor || mWasRotatingAnchor)
                {
                    if (mCharacterController != null)
                    {
                        float lToCameraAngle = Vector3Ext.HorizontalAngleTo(lAnchorTransform.forward, RigController.Transform.forward, lAnchorTransform.up);

                        Quaternion lRotation = Quaternion.AngleAxis(lToCameraAngle, Vector3.up);
                        mCharacterController.Yaw  = mCharacterController.Yaw * lRotation;
                        lAnchorTransform.rotation = mCharacterController.Tilt * mCharacterController.Yaw;
                    }
                    else
                    {
                        float lToCameraAngle = Vector3Ext.HorizontalAngleTo(lAnchorTransform.forward, RigController.Transform.forward, lAnchorTransform.up);

                        Quaternion lRotation = Quaternion.AngleAxis(lToCameraAngle, Vector3.up);
                        lAnchorTransform.rotation = lAnchorTransform.rotation * lRotation;
                    }

                    mAnchorLastRotation = lAnchorTransform.rotation;

                    // Since we are no longer rotating, we need to clear our out values
                    if (!lIsRotatingAnchor)
                    {
                        _Euler.y     = LocalYaw;
                        _Euler.x     = LocalPitch;
                        _EulerTarget = _Euler;

                        mViewVelocityY = 0f;
                        mViewVelocityX = 0f;

                        mWasRotatingAnchor = false;
                    }
                }
            }
            else
            {
                mWasRotatingAnchor = false;
            }

            //Debug.Log("Char Yaw:" + RigController.Anchor.rotation.eulerAngles.y.ToString("f5") + " Anchor Yaw:" + Anchor.rotation.eulerAngles.y.ToString("f5") + " Cam Yaw:" + RigController._Transform.eulerAngles.y.ToString("f5"));
        }
コード例 #6
0
ファイル: BasicDamaged.cs プロジェクト: cjpxyz/redpanda-game
        /// <summary>
        /// Look at the incoming message to determine if it means we should react
        /// </summary>
        /// <param name="rMessage"></param>
        public override void OnMessageReceived(IMessage rMessage)
        {
            if (rMessage == null)
            {
                return;
            }
            if (rMessage.IsHandled)
            {
                return;
            }
            if (mActorController.State.Stance != EnumControllerStance.TRAVERSAL)
            {
                return;
            }

            if (rMessage is CombatMessage)
            {
                CombatMessage lCombatMessage = rMessage as CombatMessage;

                // Attack messages
                if (lCombatMessage.Attacker == mMotionController.gameObject)
                {
                }
                // Defender messages
                else if (lCombatMessage.Defender == mMotionController.gameObject)
                {
                    if (rMessage.ID == CombatMessage.MSG_DEFENDER_DAMAGED)
                    {
                        if (!mIsActive)
                        {
                            Vector3 lLocalPosition  = mMotionController._Transform.InverseTransformPoint(lCombatMessage.HitPoint);
                            Vector3 lLocalDirection = (lLocalPosition - Vector3.zero).normalized;
                            float   lAttackAngle    = Vector3Ext.HorizontalAngleTo(Vector3.forward, lLocalDirection, Vector3.up);

                            mMotionController.ActivateMotion(this, (int)lAttackAngle);
                        }
                        else
                        {
                            mMotionController.SetAnimatorMotionPhase(mMotionLayer._AnimatorLayerIndex, PHASE_START, Parameter, true);
                        }

                        rMessage.IsHandled = true;
                    }
                }
            }
            else if (rMessage is DamageMessage)
            {
                if (rMessage.ID == CombatMessage.MSG_DEFENDER_DAMAGED)
                {
                    mMotionController.ActivateMotion(this, 0);
                    rMessage.IsHandled = true;
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Rotate to the specified target's position over time
        /// </summary>
        /// <param name="rTarget">Transform we are rotating to</param>
        /// <param name="rSpeed">Degrees per second to rotate</param>
        /// <param name="rDeltaTime">Current delta time</param>
        /// <param name="rRotation">Resulting delta rotation needed to get to the target</param>
        protected void RotateToTarget(Transform rTarget, float rSpeed, float rDeltaTime, ref Quaternion rRotation)
        {
            Vector3 lNewPosition = mMotionController._Transform.position + (mMotionController._Transform.rotation * mMotionController.RootMotionMovement);
            Vector3 lToTarget    = rTarget.position - lNewPosition;

            float lSpeed = (rSpeed > 0f ? rSpeed : _ToTargetRotationSpeed);

            float lToAnchorAngle = Vector3Ext.HorizontalAngleTo(mMotionController._Transform.forward, lToTarget.normalized, mMotionController._Transform.up);

            lToAnchorAngle = Mathf.Sign(lToAnchorAngle) * Mathf.Min(lSpeed * rDeltaTime, Mathf.Abs(lToAnchorAngle));

            rRotation = Quaternion.AngleAxis(lToAnchorAngle, Vector3.up);
        }
コード例 #8
0
        // ************************************** EDITOR SUPPORT **************************************

        /// <summary>
        /// Allow the constraint to render it's own GUI
        /// </summary>
        /// <returns>Reports if the object's value was changed</returns>
        public override bool OnInspectorConstraintGUI(bool rIsSelected)
        {
            bool lIsDirty = false;

#if UNITY_EDITOR
            GUILayout.Space(5);

            // Determine if the swing is changing
            if (mBone != null)
            {
                Vector3 lSwing    = _Swing.eulerAngles;
                Vector3 lNewSwing = InspectorHelper.Vector3Fields("Swing", "Euler angles to swing the bone.", lSwing, true, true, false);
                if (lNewSwing != lSwing)
                {
                    lIsDirty = true;

                    // Grab the amount that was just rotated by based on the current rotation.
                    // We do this so the change is relative to the current swing rotation
                    Vector3 lDeltaRotations = lNewSwing - lSwing;
                    _Swing = _Swing * Quaternion.Euler(lDeltaRotations);
                }

                // Determine if the twist is changing
                float lTwist    = Vector3Ext.SignedAngle(Vector3.up, _Twist * Vector3.up, Vector3.forward);
                float lNewTwist = EditorGUILayout.FloatField("Twist", lTwist);
                if (lNewTwist != lTwist)
                {
                    lIsDirty = true;
                    _Twist   = Quaternion.AngleAxis(lNewTwist, Vector3.forward);
                }

                // Reset the values if needed
                if (GUILayout.Button("reset rotation", EditorStyles.miniButton))
                {
                    _Swing   = Quaternion.identity;
                    _Twist   = Quaternion.identity;
                    lIsDirty = true;
                }

                if (lIsDirty)
                {
                    mBone.SetLocalRotation(_Swing, _Twist, 1f);
                }
            }
#endif

            return(lIsDirty);
        }
コード例 #9
0
        /// <summary>
        /// This function renders out the handles that allow us to edit the twist limits. It
        /// isn't actually meant to change the twist itself
        /// </summary>
        /// <param name="rBone"></param>
        /// <param name="rMinAngle"></param>
        /// <param name="rMaxAngle"></param>
        /// <returns></returns>
        public static bool JointTwistLimitsHandle(BoneControllerBone rBone, ref float rMinAngle, ref float rMaxAngle)
        {
            bool lIsDirty = false;

#if UNITY_EDITOR

            Vector3 lWorldPosition = rBone._Transform.position;
            Quaternion lWorldSwingRotation = rBone.WorldBindRotation * rBone._Swing;

            Color lGUIColor = GUI.color;
            Color lHandleColor = Handles.color;

            float lHandleScale = 0.2f;
            if (rBone.Skeleton.EditorAutoScaleHandles) { lHandleScale = HandleUtility.GetHandleSize(rBone.Transform.position) * HandlesHelper.HandleScale; }

            // Render the border of the angles
            float lTwistAngle = Vector3Ext.SignedAngle(Vector3.up, rBone._Twist * Vector3.up, Vector3.forward);

            Quaternion lActualRotation = Quaternion.AngleAxis(lTwistAngle, Vector3.forward);
            Quaternion lMinRotation = Quaternion.AngleAxis(rMinAngle, Vector3.forward);
            Quaternion lMaxRotation = Quaternion.AngleAxis(rMaxAngle, Vector3.forward);

            Vector3 lMinOffset = lWorldSwingRotation * lMinRotation * Vector3.up * lHandleScale;
            Vector3 lMaxOffset = lWorldSwingRotation * lMaxRotation * Vector3.up * lHandleScale;

            Handles.color = new Color(0.1f, 0.1f, 0.6f, 1f);
            Handles.DrawLine(lWorldPosition, lWorldPosition + lMinOffset);
            Handles.DrawLine(lWorldPosition, lWorldPosition + lMaxOffset);
            //Handles.DrawLine(lWorldPosition, lWorldPosition + (lWorldSwingRotation * rBone.Twist * Vector3.up * (lHandleScale * 1.1f)));

            // Render the solid of the angles
            Handles.color = new Color(0.25f, 0.60f, 0.95f, 0.1f);
            Handles.DrawSolidArc(lWorldPosition, rBone.Transform.rotation * rBone._BoneForward, lWorldSwingRotation * lMinRotation * Vector3.up, Mathf.Abs(rMinAngle) + rMaxAngle, lHandleScale);

            // Render text
            GUI.color = new Color(0.05f, 0.05f, 0.5f, 1f);
            Handles.Label(lWorldPosition + lMinOffset, "min:\r\n" + rMinAngle.ToString("0.00"));
            Handles.Label(lWorldPosition + lMaxOffset, "max:\r\n" + rMaxAngle.ToString("0.00"));
            Handles.Label(lWorldPosition + (lWorldSwingRotation * lActualRotation * Vector3.up * (lHandleScale * 1.3f)), " " + lTwistAngle.ToString("0.00"));

            // Reset
            GUI.color = lGUIColor;
            Handles.color = lHandleColor;
#endif

            return lIsDirty;
        }
コード例 #10
0
        /// <summary>
        /// This function renders out the handles that allow us to edit the twist limits. It
        /// isn't actually meant to change the twist itself
        /// </summary>
        /// <param name="rBone"></param>
        /// <param name="rMinAngle"></param>
        /// <param name="rMaxAngle"></param>
        /// <returns></returns>
        public static bool JointSwingAxisLimitsHandle(BoneControllerBone rBone, Vector3 rAxis, float rMinAngle, float rMaxAngle)
        {
            bool lIsDirty = false;

#if UNITY_EDITOR

            Vector3 lWorldPosition = rBone._Transform.position;
            Quaternion lWorldSwing = rBone.WorldBindRotation * rBone.Swing;

            Color lGUIColor = GUI.color;
            Color lHandleColor = Handles.color;

            float lHandleScale = 0.2f;
            if (rBone.Skeleton.EditorAutoScaleHandles) { lHandleScale = HandleUtility.GetHandleSize(rBone.Transform.position) * HandlesHelper.HandleScale; }

            // Render the border of the angles
            Quaternion lMinRotation = Quaternion.AngleAxis(rMinAngle, rAxis);
            Quaternion lMaxRotation = Quaternion.AngleAxis(rMaxAngle, rAxis);

            // We don't use the world swing since we want the rotation based on the bind position
            Vector3 lMinOffset = rBone.WorldBindRotation * lMinRotation * Vector3.forward * lHandleScale;
            Vector3 lMaxOffset = rBone.WorldBindRotation * lMaxRotation * Vector3.forward * lHandleScale;

            Handles.color = new Color(0.94118f, 0.39608f, 0.13333f, 1f);
            Handles.DrawLine(lWorldPosition, lWorldPosition + lMinOffset);
            Handles.DrawLine(lWorldPosition, lWorldPosition + lMaxOffset);

            // Render the solid of the angles
            Handles.color = new Color(0.94118f, 0.39608f, 0.13333f, 0.1f);
            Handles.DrawSolidArc(lWorldPosition, rBone.WorldBindRotation * rAxis, (rBone.WorldBindRotation * lMinRotation * Vector3.forward), Mathf.Abs(rMinAngle) + rMaxAngle, lHandleScale);

            // Draw text
            GUI.color = new Color(0.72549f, 0.30588f, 0.10588f, 1f);
            Handles.Label(lWorldPosition + lMinOffset, "min:\r\n" + rMinAngle.ToString("0.00"));
            Handles.Label(lWorldPosition + lMaxOffset, "max:\r\n" + rMaxAngle.ToString("0.00"));

            Vector3 lDirectionAxis = Vector3.Cross(rAxis, rBone._BindRotation * rBone._BoneForward);
            float lSwingAngle = Vector3Ext.SignedAngle(lDirectionAxis, rBone.Swing * lDirectionAxis, rAxis);
            Handles.Label(lWorldPosition + (lWorldSwing * (Vector3.forward * (lHandleScale * 1.3f))), "  " + lSwingAngle.ToString("0.00"));

            // Reset
            GUI.color = lGUIColor;
            Handles.color = lHandleColor;
#endif

            return lIsDirty;
        }
コード例 #11
0
    public bool Find(GameObject target, bool showLines = false)
    {
        if (target == null || owner == null)
        {
            return(false);
        }

        bool result = false;

        Vector3 origin = owner.position;
        float   angle  = SetAimDirection(-owner.right);

        for (int i = 0; i <= rayCount; i++)
        {
            RaycastHit2D[] hits = Physics2D.RaycastAll(origin, Vector3Ext.GetVectorFromAngle(angle), viewDistance, mask);
            if (hits.Any())
            {
                foreach (RaycastHit2D hit in hits)
                {
                    if (hit.collider.gameObject == self)
                    {
                        continue;
                    }
                    Color c = Color.green;

                    if (target != null && hit.collider.gameObject == target)
                    {
                        c      = Color.red;
                        result = true;
                    }

                    if (showLines)
                    {
                        Debug.DrawLine(origin, hit.point, c, Time.deltaTime);
                    }
                    break;
                }
            }
            else if (showLines)
            {
                Debug.DrawLine(origin, origin + Vector3Ext.GetVectorFromAngle(angle) * viewDistance, Color.green, Time.deltaTime);
            }
            angle -= angleIncrease;
        }
        return(result);
    }
コード例 #12
0
        /// <summary>
        /// Allow the joint to render it's own GUI. This GUI is used
        /// for displaying and manipulating the joint itself.
        /// </summary>
        /// <returns>Reports if the object's value was changed</returns>
        public override bool OnInspectorManipulatorGUI(IKBoneModifier rModifier)
        {
#if UNITY_EDITOR
            // Determine if the swing is changing
            if (mBone != null)
            {
                // Determine if the swing is changing
                Vector3 lSwing    = rModifier.Swing.eulerAngles;
                Vector3 lNewSwing = InspectorHelper.Vector3Fields("Swing", "Euler angles to swing the bone.", lSwing, true, true, false); //lBoneForward.x == 0f, lBoneForward.y == 0f, lBoneForward.z == 0f);
                if (lNewSwing != lSwing)
                {
                    // Grab the amount that was just rotated by based on the current rotation.
                    // We do this so the change is relative to the current swing rotation
                    Vector3 lDeltaRotations = lNewSwing - lSwing;
                    rModifier.Swing = rModifier.Swing * Quaternion.Euler(lDeltaRotations);

                    rModifier.IsDirty = true;
                }

                float lTwist    = Vector3Ext.SignedAngle(Vector3.up, rModifier.Twist * Vector3.up, Vector3.forward);
                float lNewTwist = EditorGUILayout.FloatField("Twist", lTwist);
                if (lNewTwist != lTwist)
                {
                    rModifier.Twist   = Quaternion.AngleAxis(lNewTwist, Vector3.forward);
                    rModifier.IsDirty = true;
                }

                // Reset the values if needed
                if (GUILayout.Button("reset rotation", EditorStyles.miniButton))
                {
                    rModifier.Swing   = Quaternion.identity;
                    rModifier.Twist   = Quaternion.identity;
                    rModifier.IsDirty = true;

                    mBone._Transform.localRotation = mBone._BindRotation;
                }

                if (rModifier.IsDirty)
                {
                    ApplyLimits(ref rModifier.Swing, ref rModifier.Twist);
                }
            }
#endif

            return(rModifier.IsDirty);
        }
コード例 #13
0
        /// <summary>
        /// Rotates the body to point towards the cross hairs
        /// </summary>
        protected void RotateChestToTargetForward(Vector3 rTarget, float rWeight)
        {
            if (rWeight == 0f)
            {
                return;
            }

            float lHAngle = 0f;
            float lVAngle = 0f;

            Transform lBody   = mMotionController._Transform;
            Transform lCamera = mMotionController._CameraTransform;
            Transform lSpine  = mMotionController.Animator.GetBoneTransform(HumanBodyBones.Spine);
            Transform lChest  = mMotionController.Animator.GetBoneTransform(HumanBodyBones.Chest);

            // The target direction helps determine how we'll rotate the arm
            Vector3 lTargetDirection = (lCamera != null ? lCamera.forward : rTarget);

            lHAngle = _HorizontalAimAngle * rWeight;
            lVAngle = (_VerticalAimAngle + Vector3Ext.HorizontalAngleTo(lBody.forward, lTargetDirection, lBody.right)) * rWeight;
            lVAngle = Mathf.Clamp(lVAngle, -65f, 65f);

            if (lSpine != null && lChest != null)
            {
                lHAngle = lHAngle * 0.5f;
            }
            if (lSpine != null && lChest != null)
            {
                lVAngle = lVAngle * 0.5f;
            }

            if (lSpine != null)
            {
                lSpine.rotation = Quaternion.AngleAxis(lHAngle, lBody.up) * Quaternion.AngleAxis(lVAngle, lBody.right) * lSpine.rotation;
            }

            if (lChest != null)
            {
                lChest.rotation = Quaternion.AngleAxis(lHAngle, lBody.up) * Quaternion.AngleAxis(lVAngle, lBody.right) * lChest.rotation;
            }
        }
コード例 #14
0
        /// <summary>
        /// Calculate how much to move an rotate by
        /// </summary>
        /// <param name="rMove"></param>
        /// <param name="rRotate"></param>
        protected virtual void CalculateMove(Vector3 rWaypoint, ref Vector3 rMove, ref Quaternion rRotate)
        {
            float lDeltaTime = TimeManager.SmoothedDeltaTime;

            // Direction we need to travel in
            Vector3 lDirection = rWaypoint - transform.position;

            lDirection.Normalize();

            // Determine our rotation
            Vector3 lVerticalDirection = Vector3.Project(lDirection, transform.up);
            Vector3 lLateralDirection  = lDirection - lVerticalDirection;

            float lYawAngle = Vector3Ext.SignedAngle(transform.forward, lLateralDirection);

            if (_RotationSpeed == 0f)
            {
                rRotate = Quaternion.AngleAxis(lYawAngle, transform.up);
            }
            else
            {
                rRotate = Quaternion.AngleAxis(Mathf.Sign(lYawAngle) * Mathf.Min(Mathf.Abs(lYawAngle), _RotationSpeed * lDeltaTime), transform.up);
            }

            // Determine the movement
            float lMoveSpeed = _FastSpeed;

            if (mIsInSlowDistance && _SlowSpeed > 0f)
            {
                lMoveSpeed = _SlowSpeed;
            }

            // Set the final velocity based on the future rotation
            Quaternion lFutureRotation = transform.rotation * rRotate;

            rMove = lFutureRotation.Forward() * (lMoveSpeed * lDeltaTime);
        }
コード例 #15
0
 public float SetAimDirection(Vector3 dir)
 {
     return(Vector3Ext.GetAngleFromVector(dir) - fov / 2f);
 }
コード例 #16
0
        /// <summary>
        /// Converts the nav mesh agent data into psuedo-input that the motion controller
        /// will use to drive animations.
        /// </summary>
        protected void SimulateInput()
        {
            float lDeltaTime = TimeManager.SmoothedDeltaTime;

            // Direction we need to travel in
            Vector3 lDirection = mWaypointVector;

            lDirection.y = lDirection.y - _PathHeight;
            lDirection.Normalize();

            // Determine our view
            Vector3 lVerticalDirection = Vector3.Project(lDirection, _Transform.up);
            Vector3 lLateralDirection  = lDirection - lVerticalDirection;

            mInputFromAvatarAngle = Vector3Ext.SignedAngle(_Transform.forward, lLateralDirection);

            // Determine how much we simulate the view x. We temper it to make it smooth
            float lYawAngleAbs = Mathf.Min(Mathf.Abs(mInputFromAvatarAngle * lDeltaTime), mViewSpeedPer60FPSTick * lDeltaTime);

            if (lYawAngleAbs < EPSILON)
            {
                lYawAngleAbs = 0f;
            }

            mViewX = Mathf.Sign(mInputFromAvatarAngle) * lYawAngleAbs;

            // Determine our movement
            if (mTargetDistance > _StopDistance)
            {
                // Calculate our own slowing
                float lRelativeMoveSpeed = _NormalizedSpeed;
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    float lSlowPercent = (mTargetDistance - _StopDistance) / (_SlowDistance - _StopDistance);
                    lRelativeMoveSpeed = ((1f - _SlowFactor) * lSlowPercent) + _SlowFactor;
                }

                // TRT 4/5/2016: Force the slow distance as an absolute value
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    lRelativeMoveSpeed = _SlowFactor;
                }

                mMovementY = 1f * lRelativeMoveSpeed;

                mMotionController.TargetNormalizedSpeed = lRelativeMoveSpeed;
            }

            // Grab extra input information if we can
            if (mMotionController._CameraTransform == null)
            {
                mInputFromCameraAngle = mInputFromAvatarAngle;
            }
            else
            {
                Vector3 lInputForward = new Vector3(mMovementX, 0f, mMovementY);

                // We do the inverse tilt so we calculate the rotation in "natural up" space vs. "actor up" space.
                Quaternion lInvTilt = QuaternionExt.FromToRotation(_Transform.up, Vector3.up);

                // Camera forward in "natural up"
                Vector3 lCameraForward = lInvTilt * mMotionController._CameraTransform.forward;

                // Create a quaternion that gets us from our world-forward to our camera direction.
                Quaternion lToCamera = Quaternion.LookRotation(lCameraForward, lInvTilt * _Transform.up);

                // Transform joystick from world space to camera space. Now the input is relative
                // to how the camera is facing.
                Vector3 lMoveDirection = lToCamera * lInputForward;
                mInputFromCameraAngle = NumberHelper.GetHorizontalAngle(lCameraForward, lMoveDirection);
            }
        }
コード例 #17
0
        /// <summary>
        /// Core function that relies on the law of cosines in order to
        /// determine the angles between two bones.
        /// </summary>
        /// <param name="rState">State object containing information about what is to be solved and the results</param>
        public static void SolveIK(ref IKSolverState rState, float rBone2Extension = 0f)
        {
            if (rState.Bones == null || rState.Bones.Count != 2)
            {
                return;
            }

            // Extract out the data
            BoneControllerBone lBone1 = rState.Bones[0];
            BoneControllerBone lBone2 = rState.Bones[1];

            // Grab basic bone info. We need the end's bind rotation so that it will keep the cosine equations
            // on a single plane after limits are processed.
            float      lBone1Length   = Vector3.Distance(lBone1.Transform.position, lBone2.Transform.position);
            Vector3    lBone1Position = lBone1.Transform.position;
            Quaternion lBone1Rotation = lBone1.Transform.rotation;
            Vector3    lBone1BendAxis = rState.BoneBendAxes[0];

            float      lBone2Length   = lBone2.Length + rBone2Extension;
            Vector3    lBone2Position = lBone2.Transform.position;
            Quaternion lBone2Rotation = lBone2.Transform.rotation;
            Vector3    lBone2BendAxis = rState.BoneBendAxes[1];

            Vector3 lBone3Position = lBone2Position + (lBone2Rotation * lBone2.BindRotation * lBone2.ToBoneForward * (Vector3.forward * lBone2Length));

            // Check if our final position is too far. If so, we need to bring it in
            Vector3 lTargetPosition      = rState.TargetPosition;
            float   lBone1ToTargetLength = Vector3.Distance(lBone1Position, lTargetPosition);

            if (lBone1ToTargetLength > lBone1Length + lBone2Length)
            {
                // We remove a tiny bit of length so we never end up with a
                // bone angle of 0. This allows us to account for the bend axis.
                lBone1ToTargetLength = lBone1Length + lBone2Length;// -0.0000f;

                Vector3 lDirection = (lTargetPosition - lBone1Position).normalized;
                lTargetPosition = lBone1Position + (lDirection * lBone1ToTargetLength);
            }

            // Grab the angle between the target vector and the mid bone. Then, create the final rotation vector for the first bone
            float lAngle      = (-(lBone2Length * lBone2Length) + (lBone1Length * lBone1Length) + (lBone1ToTargetLength * lBone1ToTargetLength)) / (2f * lBone1Length * lBone1ToTargetLength);
            float lBone1Angle = Mathf.Acos(Mathf.Clamp(lAngle, -1f, 1f)) * Mathf.Rad2Deg;

            // The bind rotation in world coordinates
            Quaternion lBaseRootRotation = (rState.UseBindRotation ? lBone1.WorldBindRotation : lBone1.Transform.rotation * lBone1.ToBoneForward);

            // Grab the rotation that gets us from the base vector to the target vector. This is the hypotenuse.
            Quaternion lToTargetRotation = Quaternion.FromToRotation(lBaseRootRotation * Vector3.forward, lTargetPosition - lBone1Position);

            // Determine the axis we'll rotate the root bone around
            Vector3 lRootBendAxis = Vector3.zero;

            if (rState.UsePlaneNormal)
            {
                lRootBendAxis = Vector3Ext.PlaneNormal(lBone1Position, lBone2Position, lBone3Position);
            }
            else
            {
                lRootBendAxis = lToTargetRotation * lBaseRootRotation * lBone1BendAxis;
            }

            // Rotate from the base rotation to the target rotation and finally to the correct rotation (based on the angle)
            lBone1Rotation = Quaternion.AngleAxis(lBone1Angle, lRootBendAxis) * lToTargetRotation * lBaseRootRotation;

            // Now we can determine the position of the second bone
            lBone2Position = lBone1Position + (lBone1Rotation * (Vector3.forward * lBone1Length));

            // Want to ensure we don't end up with a '0' look direction. Otherwise, we'll get infinite errors.
            if (Vector3.SqrMagnitude(lTargetPosition - lBone2Position) > 0.001f)
            {
                // Grabbing the rotation of the second bone is easier since we just look at the target
                Vector3 lForward = lTargetPosition - lBone2Position;
                Vector3 lRight   = lBone1Rotation * lBone2BendAxis;
                Vector3 lUp      = Vector3.Cross(lForward, lRight).normalized;

                lBone2Rotation = Quaternion.LookRotation(lForward, lUp);
            }

            // Return the results
            rState.Rotations.Clear();
            rState.AddRotation(lBone1, lBone1Rotation);
            rState.AddRotation(lBone2, lBone2Rotation);

            // Set the position valudes (for debugging)
            rState.BonePositions.Clear();
            rState.BonePositions.Add(lBone1Position);
            rState.BonePositions.Add(lBone2Position);
            rState.BonePositions.Add(lBone2Position + (lBone2Rotation * (Vector3.forward * lBone2Length)));

            // Debug
            if (rState.IsDebugEnabled)
            {
                DebugDraw.DrawOctahedronOverlay(lBone1Position, Quaternion.identity, 0.03f, Color.red, 1f);
                DebugDraw.DrawOctahedronOverlay(lBone2Position, Quaternion.identity, 0.03f, Color.green, 1f);
                DebugDraw.DrawOctahedronOverlay(lBone3Position, Quaternion.identity, 0.03f, Color.blue, 1f);
                DebugDraw.DrawOctahedronOverlay(lTargetPosition, Quaternion.identity, 0.03f, Color.magenta, 1f);

                DebugDraw.DrawLineOverlay(lBone1Position, lBone1Position + (lBone1Rotation * (Vector3.forward * 0.5f)), 0.01f, Color.blue, 0.75f);
                DebugDraw.DrawLineOverlay(lBone1Position, lBone1Position + (lBone1Rotation * (Vector3.up * 0.5f)), 0.01f, Color.green, 0.75f);
                DebugDraw.DrawLineOverlay(lBone1Position, lBone1Position + (lBone1Rotation * (Vector3.right * 0.5f)), 0.01f, Color.red, 0.75f);

                DebugDraw.DrawLineOverlay(lBone2Position, lBone2Position + (lBone2Rotation * Vector3.forward), 0.02f, Color.blue, 0.5f);
                DebugDraw.DrawLineOverlay(lBone2Position, lBone2Position + (lBone2Rotation * Vector3.up), 0.02f, Color.green, 0.5f);
                DebugDraw.DrawLineOverlay(lBone2Position, lBone2Position + (lBone2Rotation * Vector3.right), 0.02f, Color.red, 0.5f);
            }
        }
コード例 #18
0
        /// <summary>
        /// Updates the motor over time. This is called by the controller
        /// every update cycle so movement can be updated.
        /// </summary>
        /// <param name="rDeltaTime">Time since the last frame (or fixed update call)</param>
        /// <param name="rUpdateIndex">Index of the update to help manage dynamic/fixed updates. [0: Invalid update, >=1: Valid update]</param>
        /// <param name="rTiltAngle">Amount of tilting the camera needs to do to match the anchor</param>
        public override CameraTransform RigLateUpdate(float rDeltaTime, int rUpdateIndex, float rTiltAngle = 0f)
        {
            Transform lAnchorTransform = Anchor;

            if (lAnchorTransform == null)
            {
                return(mRigTransform);
            }

            if (RigController == null)
            {
                return(mRigTransform);
            }
            Transform lCameraTransform = RigController._Transform;

            // Determine how much the anchor's yaw changed (we want to stay relative to the anchor direction)
            float lAnchorRootYawDelta = Vector3Ext.HorizontalAngleTo(mAnchorLastRotation.Forward(), lAnchorTransform.forward, lAnchorTransform.up);
            float lAnchorYaw          = (Mathf.Abs(rTiltAngle) >= 2f ? lAnchorRootYawDelta : 0f);

            if (!RigController.RotateAnchorOffset)
            {
                lAnchorRootYawDelta = 0f;
                lAnchorYaw          = 0f;
            }

            // Grab any euler changes this frame
            mFrameEuler = GetFrameEuler(true, true); // RigController.RotateAnchorOffset);

            // Get our predicted based on the frame and anchor changes. We want this to get the right-vector
            Quaternion lNewCameraRotation = Quaternion.AngleAxis(mFrameEuler.y + lAnchorYaw, (RigController.RotateAnchorOffset ? RigController.Tilt.Up() : Vector3.up)) * lCameraTransform.rotation;

            // Now grab the full (vertical + horizontal) position of our final focus.
            //Vector3 lNewFocusPosition = lAnchorTransform.position + (lAnchorTransform.up * lOffset.y);
            //lNewFocusPosition = lNewFocusPosition + (lNewCameraRotation.Right() * lOffset.x);
            Vector3 lNewFocusPosition = GetFocusPosition(lNewCameraRotation);

            // Default the value
            Vector3 lNewCameraPosition = lCameraTransform.position;
            Vector3 lToFocusPosition   = lCameraTransform.forward;

            // If we're tilting, act like a fixed
            if (RigController.FrameForceToFollowAnchor || Mathf.Abs(rTiltAngle) >= 2f)
            {
                // Get the local position and the right vector of the camera relative to the last frame
                Matrix4x4 lOldFocusMatrix = Matrix4x4.TRS(mFocusLastPosition, (RigController.RotateAnchorOffset ? mAnchorLastRotation : Quaternion.identity), Vector3.one);
                Matrix4x4 lNewFocusMatrix = Matrix4x4.TRS(lNewFocusPosition, (RigController.RotateAnchorOffset ? lAnchorTransform.rotation : Quaternion.identity), Vector3.one);

                // The matrix will add our anchor delta. But, we also added it when we use the LocalYaw
                // We'll remove it so we don't double up.
                if (mTargetYaw < float.MaxValue)
                {
                    mFrameEuler.y = mFrameEuler.y - lAnchorRootYawDelta;
                }

                // If nothing has changed, we won't update. This is important due to the fact
                // that the inverse of the matix causes a small floating point error to move us.
                if (mFrameEuler.sqrMagnitude != 0f || lOldFocusMatrix != lNewFocusMatrix)
                {
                    Vector3 lLocalPosition    = lOldFocusMatrix.inverse.MultiplyPoint(lCameraTransform.position);
                    Vector3 lLocalCameraRight = lOldFocusMatrix.inverse.MultiplyVector(lCameraTransform.right);

                    // Rotate the old local position based on the frame's rotation changes
                    Quaternion lLocalRotation = Quaternion.AngleAxis(mFrameEuler.y, Vector3.up) * Quaternion.AngleAxis(mFrameEuler.x, lLocalCameraRight);
                    lLocalPosition = lLocalRotation * lLocalPosition;

                    // Grab the new position based on the updated matrix
                    lNewCameraPosition = lNewFocusMatrix.MultiplyPoint(lLocalPosition);
                }
            }
            // If we have a target forward, act like a fixed
            else if (mTargetForward.sqrMagnitude > 0f)
            {
                lNewCameraRotation = lNewCameraRotation * Quaternion.AngleAxis(mFrameEuler.x, Vector3.right);
                lNewCameraPosition = lNewFocusPosition - (lNewCameraRotation.Forward() * mDistance);
            }
            else
            {
                lNewCameraRotation = lNewCameraRotation * Quaternion.AngleAxis(mFrameEuler.x, Vector3.right);
                Vector3 lOldCameraPosition = mFocusLastPosition - (lNewCameraRotation.Forward() * mDistance);

                // Grab the new focus position using the drag rotation we get
                lToFocusPosition = lNewFocusPosition - lOldCameraPosition;
                if (lToFocusPosition.sqrMagnitude < 0.0001f)
                {
                    lToFocusPosition = lCameraTransform.forward;
                }

                lNewCameraRotation = Quaternion.LookRotation(lToFocusPosition.normalized, (RigController.RotateAnchorOffset ? lAnchorTransform.up : Vector3.up));
                //lNewFocusPosition = lAnchorTransform.position + (lAnchorTransform.up * lOffset.y);
                //lNewFocusPosition = lNewFocusPosition + (lNewCameraRotation.Right() * lOffset.x);
                lNewFocusPosition = GetFocusPosition(lNewCameraRotation);

                // If something is between the new focus position and the anchor, the new focus position is the anchor
                //Color lHitColor = Color.black;
                //RaycastHit lFocusHit;
                Vector3 lAnchorPosition = Vector3.zero;

                if (RigController.RotateAnchorOffset)
                {
                    lAnchorPosition = lAnchorTransform.position + (lAnchorTransform.rotation * AnchorOffset) + (lAnchorTransform.up * _Offset.y);
                }
                else
                {
                    lAnchorPosition = lAnchorTransform.position + AnchorOffset + (Vector3.up * _Offset.y);
                }

                lToFocusPosition = lNewFocusPosition - lAnchorPosition;

                // Get the drag direction and pull out the horizontal component
                lToFocusPosition = lNewFocusPosition - lOldCameraPosition;
                if (lToFocusPosition.sqrMagnitude < 0.0001f)
                {
                    lToFocusPosition = lCameraTransform.forward;
                }

                Vector3 lToFocusPositionVertical   = Vector3.Project(lToFocusPosition, (RigController.RotateAnchorOffset ? RigController.Tilt.Up() : Vector3.up));
                Vector3 lToFocusPositionHorizontal = lToFocusPosition - lToFocusPositionVertical;

                // Get the pitch rotation regardless of our tilt
                lNewCameraRotation = lCameraTransform.rotation * Quaternion.AngleAxis(mFrameEuler.x, Vector3.right);
                Vector3 lRotationEuler = (RigController.RotateAnchorOffset ? Quaternion.Inverse(RigController.Tilt) * lNewCameraRotation : lNewCameraRotation).eulerAngles;

                // Add the pitch to our look-at rotation
                Quaternion lNewAnchorRotation = Quaternion.LookRotation(lToFocusPositionHorizontal, (RigController.RotateAnchorOffset ? RigController.Tilt.Up() : Vector3.up)) * Quaternion.Euler(lRotationEuler.x, 0f, 0f);

                // Using the rotation, grab the new camera position
                lNewCameraPosition = lNewFocusPosition - (lNewAnchorRotation.Forward() * mDistance);
            }

            // Determine our rotation
            lToFocusPosition = lNewFocusPosition - lNewCameraPosition;
            if (lToFocusPosition.sqrMagnitude < 0.0001f)
            {
                lToFocusPosition = lCameraTransform.forward;
            }

            lNewCameraRotation = Quaternion.LookRotation(lToFocusPosition.normalized, (RigController.RotateAnchorOffset ? lAnchorTransform.up : Vector3.up));

            // We have to do a final check if we have exceeded rotation limits
            Quaternion lNewLocalCameraRotation = (RigController.RotateAnchorOffset ? Quaternion.Inverse(Anchor.transform.rotation) : Quaternion.identity) * lNewCameraRotation;
            Vector3    lNewLocalEuler          = lNewLocalCameraRotation.eulerAngles;

            if (lNewLocalEuler.y > 180f)
            {
                lNewLocalEuler.y = lNewLocalEuler.y - 360f;
            }
            else if (lNewLocalEuler.y < -180f)
            {
                lNewLocalEuler.y = lNewLocalEuler.y + 360f;
            }

            if (lNewLocalEuler.x > 180f)
            {
                lNewLocalEuler.x = lNewLocalEuler.x - 360f;
            }
            else if (lNewLocalEuler.x < -180f)
            {
                lNewLocalEuler.x = lNewLocalEuler.x + 360f;
            }

            float lYaw   = (_MinYaw > -180f || _MaxYaw < 180f ? Mathf.Clamp(lNewLocalEuler.y, _MinYaw, _MaxYaw) : lNewLocalEuler.y);
            float lPitch = Mathf.Clamp(lNewLocalEuler.x, _MinPitch, _MaxPitch);

            if (lYaw != lNewLocalEuler.y || lPitch != lNewLocalEuler.x)
            {
                lNewCameraRotation = (RigController.RotateAnchorOffset ? Anchor.transform.rotation : Quaternion.identity) * Quaternion.Euler(lPitch, lYaw, 0f);
                lNewCameraPosition = lNewFocusPosition - (lNewCameraRotation.Forward() * mDistance);
            }

            // Return the results
            mRigTransform.Position = lNewCameraPosition;
            mRigTransform.Rotation = lNewCameraRotation;
            return(mRigTransform);
        }
コード例 #19
0
        /// <summary>
        /// Grabs the euler changes that happen this frame.
        /// </summary>
        /// <param name="rAnchorYaw">Anchor yaw that should be added</param>
        /// <returns></returns>
        public virtual Vector3 GetFrameEuler(bool rUseYawLimits, bool rUsePitchLimits = true)
        {
            Vector3 lFrameEuler = Vector3.zero;

            // If the camera was moved externally, we need to recalculate the last focus position
            if (RigController.LastPosition != RigController._Transform.position)
            {
                mFocusLastPosition = GetFocusPosition(RigController._Transform.rotation);
            }

            // Now we can grab the movement
            if (mTarget != null)
            {
                mTargetForward = (mTarget.position - mRigTransform.Position).normalized;
            }

            if (mTargetForward.sqrMagnitude > 0f)
            {
                Quaternion lTargetRotation = Quaternion.LookRotation(mTargetForward, Anchor.up);

                Quaternion lLocalRotation       = Quaternion.Inverse(Anchor.rotation) * RigController._Transform.rotation;
                Quaternion lLocalTargetRotation = Quaternion.Inverse(Anchor.rotation) * lTargetRotation;

                float lDeltaYaw = lLocalTargetRotation.eulerAngles.y - lLocalRotation.eulerAngles.y;
                if (lDeltaYaw > 180f)
                {
                    lDeltaYaw = lDeltaYaw - 360f;
                }
                else if (lDeltaYaw < -180f)
                {
                    lDeltaYaw = lDeltaYaw + 360f;
                }

                float lDeltaPitch = lLocalTargetRotation.eulerAngles.x - lLocalRotation.eulerAngles.x;
                if (lDeltaPitch > 180f)
                {
                    lDeltaPitch = lDeltaPitch - 360f;
                }
                else if (lDeltaPitch < -180f)
                {
                    lDeltaPitch = lDeltaPitch + 360f;
                }

                if (mTargetYawSpeed <= 0f)
                {
                    lFrameEuler.y = lDeltaYaw;
                }
                else
                {
                    lFrameEuler.y = Mathf.Sign(lDeltaYaw) * Mathf.Min(mTargetYawSpeed * Time.deltaTime, Mathf.Abs(lDeltaYaw));
                }

                if (mTargetPitchSpeed <= 0f)
                {
                    lFrameEuler.x = lDeltaPitch;
                }
                else
                {
                    lFrameEuler.x = Mathf.Sign(lDeltaPitch) * Mathf.Min(mTargetPitchSpeed * Time.deltaTime, Mathf.Abs(lDeltaPitch));
                }

                if (Mathf.Abs(lFrameEuler.y) < EPSILON && Mathf.Abs(lFrameEuler.x) < EPSILON)
                {
                    _Euler.y     = LocalYaw;
                    _Euler.x     = LocalPitch;
                    _EulerTarget = _Euler;

                    if (mAutoClearTarget)
                    {
                        mTargetForward = Vector3.zero;
                    }
                }
            }
            else if (mTargetYaw < float.MaxValue || mTargetPitch < float.MaxValue)
            {
                if (mTargetYaw < float.MaxValue)
                {
                    float lDeltaYaw = mTargetYaw - LocalYaw;

                    if (mTargetYawSpeed <= 0f)
                    {
                        lFrameEuler.y = lDeltaYaw;
                    }
                    else
                    {
                        lFrameEuler.y = Mathf.Sign(lDeltaYaw) * Mathf.Min(mTargetYawSpeed * Time.deltaTime, Mathf.Abs(lDeltaYaw));
                    }

                    // TRT 04/09/2017 - Added to stop trying to reach the target when the character is rotating
                    Transform lAnchorTransform    = Anchor;
                    float     lAnchorRootYawDelta = Vector3Ext.HorizontalAngleTo(mAnchorLastRotation.Forward(), lAnchorTransform.forward, lAnchorTransform.up);
                    if (Mathf.Abs(lFrameEuler.y) - Mathf.Abs(lAnchorRootYawDelta * 2f) < EPSILON)
                    {
                        _Euler.y       = mTargetYaw;
                        _EulerTarget.y = mTargetYaw;

                        //if (mAutoClearTarget) { mTargetYaw = float.MaxValue; }
                    }

                    if (mAutoClearTarget && Mathf.Abs(lDeltaYaw) < EPSILON)
                    {
                        mTargetYaw = float.MaxValue;
                    }
                }

                if (mTargetPitch < float.MaxValue)
                {
                    float lDeltaPitch = mTargetPitch - LocalPitch;

                    if (mTargetPitchSpeed <= 0f)
                    {
                        lFrameEuler.x = lDeltaPitch;
                    }
                    else
                    {
                        lFrameEuler.x = Mathf.Sign(lDeltaPitch) * Mathf.Min(mTargetPitchSpeed * Time.deltaTime, Mathf.Abs(lDeltaPitch));
                    }

                    if (Mathf.Abs(lFrameEuler.x) < EPSILON)
                    {
                        _Euler.x       = mTargetPitch;
                        _EulerTarget.x = mTargetPitch;

                        //if (mAutoClearTarget) { mTargetPitch = float.MaxValue; }
                    }

                    if (mAutoClearTarget && Mathf.Abs(lDeltaPitch) < EPSILON)
                    {
                        mTargetPitch = float.MaxValue;
                    }
                }
            }
            else
            {
                IInputSource lInputSource = RigController.InputSource;

                if (lInputSource.IsViewingActivated)
                {
                    if (_IsYawEnabled && lFrameEuler.y == 0f)
                    {
                        lFrameEuler.y = lInputSource.ViewX * mDegreesYPer60FPSTick;
                    }
                    if (_IsPitchEnabled && lFrameEuler.x == 0f)
                    {
                        lFrameEuler.x = (RigController._InvertPitch || _InvertPitch ? -1f : 1f) * lInputSource.ViewY * mDegreesXPer60FPSTick;
                    }
                }

                // Grab the smoothed yaw
                _EulerTarget.y = (rUseYawLimits && (_MinYaw > -180f || _MaxYaw < 180f) ? Mathf.Clamp(_EulerTarget.y + lFrameEuler.y, _MinYaw, _MaxYaw) : _EulerTarget.y + lFrameEuler.y);
                lFrameEuler.y  = (_Smoothing <= 0f ? _EulerTarget.y : SmoothDamp(_Euler.y, _EulerTarget.y, _Smoothing * 0.001f, Time.deltaTime)) - _Euler.y;
                _Euler.y       = _Euler.y + lFrameEuler.y;

                // Grab the smoothed pitch
                _EulerTarget.x = (rUsePitchLimits && (_MinPitch > -180f || _MaxPitch < 180f) ? Mathf.Clamp(_EulerTarget.x + lFrameEuler.x, _MinPitch, _MaxPitch) : _EulerTarget.x + lFrameEuler.x);
                lFrameEuler.x  = (_Smoothing <= 0f ? _EulerTarget.x : SmoothDamp(_Euler.x, _EulerTarget.x, _Smoothing * 0.001f, Time.deltaTime)) - _Euler.x;
                _Euler.x       = _Euler.x + lFrameEuler.x;
            }

            return(lFrameEuler);
        }
コード例 #20
0
        /// <summary>
        /// Grabs the combatants that fit the specified criteria
        /// </summary>
        /// <param name="rHunter">Transform who is searching for the combatants</param>
        /// <param name="rSeekOrigin">Combat origin of the hunter</param>
        /// <param name="rFilter">Filters we'll use to limit which combatants are returned</param>
        /// <param name="rCombatantHits">List of CombatantHit values who are the combatants</param>
        /// <param name="rIgnore">Transform that we won't consider a target (typically the character)</param>
        /// <returns>Count of combatants returned</returns>
        public static int QueryCombatTargets(Transform rSeeker, Vector3 rSeekOrigin, CombatFilter rFilter, List <CombatTarget> rCombatTargets, Transform rIgnore)
        {
            if (rSeeker == null)
            {
                return(0);
            }
            if (rCombatTargets == null)
            {
                return(0);
            }

#if OOTII_PROFILE
            com.ootii.Utilities.Profiler.Start(rSeeker.name + ".QueryCombatTargets");
#endif

            Collider[] lHitColliders;

            rCombatTargets.Clear();

            int lHitCount = RaycastExt.SafeOverlapSphere(rSeekOrigin, rFilter.MaxDistance, out lHitColliders, rFilter.Layers, rIgnore);
            for (int i = 0; i < lHitCount; i++)
            {
                GameObject lGameObject = lHitColliders[i].gameObject;

                // Don't count the ignore
                if (lGameObject.transform == rSeeker)
                {
                    continue;
                }
                if (lGameObject.transform == rIgnore)
                {
                    continue;
                }

                // Determine if the combatant has the appropriate tag
                if (rFilter.Tag != null && rFilter.Tag.Length > 0)
                {
                    if (!lGameObject.CompareTag(rFilter.Tag))
                    {
                        continue;
                    }
                }

                // We only care about combatants we'll enage with
                ICombatant lCombatant = null;

                Transform lHitTransform = lHitColliders[i].transform;
                while (lHitTransform != null)
                {
                    lCombatant = lGameObject.GetComponent <ICombatant>();
                    if (lCombatant != null)
                    {
                        break;
                    }

                    lHitTransform = lHitTransform.parent;
                }

                if (rFilter.RequireCombatant && lCombatant == null)
                {
                    continue;
                }

                // Determine if the combatant is within range
                Vector3         lClosestPoint    = Vector3.zero;
                ActorController lActorController = lGameObject.GetComponent <ActorController>();
                if (lActorController != null)
                {
                    lClosestPoint = lActorController.ClosestPoint(rSeekOrigin);
                }
                else
                {
                    lClosestPoint = GeometryExt.ClosestPoint(rSeekOrigin, lHitColliders[i]);
                }

                // If we have an invalid point, stop
                if (lClosestPoint == Vector3Ext.Null)
                {
                    continue;
                }

                // Determine if the point is in range
                bool    lIsValid        = true;
                Vector3 lToClosestPoint = lClosestPoint - rSeekOrigin;

                float lDistance = lToClosestPoint.magnitude;
                if (rFilter.MinDistance > 0f && lDistance < rFilter.MinDistance)
                {
                    lIsValid = false;
                }
                if (rFilter.MaxDistance > 0f && lDistance > rFilter.MaxDistance)
                {
                    lIsValid = false;
                }

                // Ensure we're not ontop of the combatant. In that case, it's probably the ground
                Vector3 lDirection = lToClosestPoint.normalized;
                if (lDirection == -rSeeker.up)
                {
                    lIsValid = false;
                }

                // Check if we're within the field of view
                float lHAngle = Vector3Ext.HorizontalAngleTo(rSeeker.forward, lDirection, rSeeker.up);
                if (rFilter.HorizontalFOA > 0f && Mathf.Abs(lHAngle) > rFilter.HorizontalFOA * 0.5f)
                {
                    lIsValid = false;
                }

                float lVAngle = Vector3Ext.HorizontalAngleTo(rSeeker.forward, lDirection, rSeeker.right);
                if (rFilter.VerticalFOA > 0f && Mathf.Abs(lVAngle) > rFilter.VerticalFOA * 0.5f)
                {
                    lIsValid = false;
                }

                // This is an odd test, but we have to do it. If the closest point of a sphere is out of the FOA, it may
                // be that the top of the sphere is in the FOA. So, we'll grab the top of the sphere and test it.
                if (!lIsValid && lCombatant != null && lHitColliders[i] is SphereCollider)
                {
                    lIsValid = true;
                    SphereCollider lSphereCollider = lHitColliders[i] as SphereCollider;

                    lClosestPoint   = lCombatant.Transform.position + (lCombatant.Transform.rotation * (lSphereCollider.center + (Vector3.up * lSphereCollider.radius)));
                    lToClosestPoint = lClosestPoint - rSeekOrigin;

                    lDistance = lToClosestPoint.magnitude;
                    if (rFilter.MinDistance > 0f && lDistance < rFilter.MinDistance)
                    {
                        lIsValid = false;
                    }
                    if (rFilter.MaxDistance > 0f && lDistance > rFilter.MaxDistance)
                    {
                        lIsValid = false;
                    }

                    // Ensure we're not ontop of the combatant. In that case, it's probably the ground
                    lDirection = lToClosestPoint.normalized;
                    if (lDirection == -rSeeker.up)
                    {
                        lIsValid = false;
                    }

                    // Check if we're within the field of view
                    lHAngle = Vector3Ext.HorizontalAngleTo(rSeeker.forward, lDirection, rSeeker.up);
                    if (rFilter.HorizontalFOA > 0f && Mathf.Abs(lHAngle) > rFilter.HorizontalFOA * 0.5f)
                    {
                        lIsValid = false;
                    }

                    lVAngle = Vector3Ext.HorizontalAngleTo(rSeeker.forward, lDirection, rSeeker.right);
                    if (rFilter.VerticalFOA > 0f && Mathf.Abs(lVAngle) > rFilter.VerticalFOA * 0.5f)
                    {
                        lIsValid = false;
                    }
                }

                if (mShowDebug)
                {
                    GraphicsManager.DrawPoint(rSeekOrigin, Color.white, null, 2f);
                    GraphicsManager.DrawPoint(lClosestPoint, Color.red, null, 2f);
                }

                if (lIsValid)
                {
                    // Add the combatant to our list
                    CombatTarget lTargetInfo = new CombatTarget();
                    lTargetInfo.SeekOrigin      = rSeekOrigin;
                    lTargetInfo.Collider        = lHitColliders[i];
                    lTargetInfo.Combatant       = lCombatant;
                    lTargetInfo.ClosestPoint    = lClosestPoint;
                    lTargetInfo.Distance        = lDistance;
                    lTargetInfo.Direction       = lDirection;
                    lTargetInfo.HorizontalAngle = lHAngle;
                    lTargetInfo.VerticalAngle   = lVAngle;

                    rCombatTargets.Add(lTargetInfo);
                }
            }

            // Sort the combatants by distance
            if (rCombatTargets.Count > 1)
            {
                rCombatTargets.Sort((rLeft, rRight) => rLeft.Distance.CompareTo(rRight.Distance));

                // We also want to remove duplicates
                for (int i = 0; i < rCombatTargets.Count; i++)
                {
                    Transform lTarget = rCombatTargets[i].Collider.transform;
                    if (rCombatTargets[i].Combatant != null)
                    {
                        lTarget = rCombatTargets[i].Combatant.Transform;
                    }

                    // Check if there's a duplicate and remove it
                    for (int j = rCombatTargets.Count - 1; j > i && j > 0; j--)
                    {
                        Transform lNextTarget = rCombatTargets[j].Collider.transform;
                        if (rCombatTargets[j].Combatant != null)
                        {
                            lNextTarget = rCombatTargets[j].Combatant.Transform;
                        }

                        if (lNextTarget == lTarget)
                        {
                            rCombatTargets.RemoveAt(j);
                        }
                    }
                }
            }

#if OOTII_PROFILE
            float lTime = Utilities.Profiler.Stop(rSeeker.name + ".QueryCombatTargets");
            //Utilities.Debug.Log.FileWrite(rSeeker.name + ".QueryCombatTargets time:" + lTime.ToString("f5") + "ms");
#endif

            // Finally, return the count
            return(rCombatTargets.Count);
        }