Пример #1
0
        /// <summary>
        /// Returns the actor's depth under water. This is based on the water surface's
        /// position-y and the actor's root
        /// </summary>
        /// <returns>Depth the actor us under water or -1 if we don't think they are</returns>
        public float GetDepth()
        {
            float lDepth = -1f;

            RaycastHit lHitInfo;
            Vector3    lStart = mTransform.position + (Vector3.up * mMaxSurfaceTest);

            // Check surface height based on the raycast
            if (RaycastExt.SafeRaycast(lStart, Vector3.down, out lHitInfo, mMaxSurfaceTest, mWaterLayers, mTransform, null, false))
            {
                mWaterSurface = lHitInfo.collider.gameObject.transform;
            }
            // TRT 01/25/2017 - When exiting water, the ray may still hit the water plane and store the surface.
            // This can lead to us thinking low ground with no water has water. So, if we don't hit water
            // stop storing it.
            else if (mWaterSurface != null)
            {
                Vector3 lWaterPoint = mTransform.InverseTransformPoint(mWaterSurface.position);
                if (lWaterPoint.y < 0f)
                {
                    mWaterSurface = null;
                }
            }

            // As a sanity check, let's see if we're really far under water
            if (mWaterSurface != null)
            {
                lDepth = mWaterSurface.position.y - mTransform.position.y;
            }

            //Utilities.Debug.Log.ScreenWrite("Depth:" + lDepth.ToString("f3"), 12);

            return(lDepth);
        }
Пример #2
0
        /// <summary>
        /// Checks if the shape currently overlaps any colliders
        /// </summary>
        /// <param name="rPositionDelta">Movement to add to the current position</param>
        /// <param name="rLayerMask">Layer mask for determing what we'll collide with</param>
        /// <returns>Boolean that says if a hit occured or not</returns>
        public override List <BodyShapeHit> CollisionOverlap(Vector3 rPositionDelta, Quaternion rRotationDelta, int rLayerMask)
        {
            List <BodyShapeHit> lHits = new List <BodyShapeHit>();

            Vector3 lBodyShapePos1 = rPositionDelta + (_Transform == null ? _Parent.position + ((_Parent.rotation * rRotationDelta) * _Offset) : _Transform.position + ((_Transform.rotation * rRotationDelta) * _Offset));
            Vector3 lBodyShapePos2 = rPositionDelta + (_EndTransform == null ? _Parent.position + ((_Parent.rotation * rRotationDelta) * _EndOffset) : _EndTransform.position + ((_EndTransform.rotation * rRotationDelta) * _EndOffset));
            Vector3 lPosition      = lBodyShapePos1 + ((lBodyShapePos2 - lBodyShapePos1) / 2f);

            float lOverlapRadius = (Vector3.Distance(lBodyShapePos1, lBodyShapePos2) / 2f) + _Radius;

            GeometryExt.Ignore = _Parent;

            Collider[] lColliders    = null;
            int        lColliderHits = RaycastExt.SafeOverlapSphere(lPosition, lOverlapRadius, out lColliders, rLayerMask, _Parent);

            for (int i = 0; i < lColliderHits; i++)
            {
                Transform lCurrentTransform = lColliders[i].transform;
                if (lCurrentTransform == _Transform)
                {
                    continue;
                }
                if (lCurrentTransform == _EndTransform)
                {
                    continue;
                }

                if (_CharacterController != null && _CharacterController.IsIgnoringCollision(lColliders[i]))
                {
                    continue;
                }

                // Once we get here, we have a valid collider
                Vector3 lLinePoint     = Vector3.zero;
                Vector3 lColliderPoint = Vector3.zero;
                GeometryExt.ClosestPoints(lBodyShapePos1, lBodyShapePos2, _Radius, lColliders[i], ref lLinePoint, ref lColliderPoint, rLayerMask);

                if (lLinePoint != Vector3Ext.Null && lColliderPoint != Vector3Ext.Null)
                {
                    float lDistance = Vector3.Distance(lLinePoint, lColliderPoint);
                    if (lDistance < _Radius + 0.001f)
                    {
                        BodyShapeHit lHit = BodyShapeHit.Allocate();
                        lHit.StartPosition = lBodyShapePos1;
                        lHit.EndPosition   = lBodyShapePos2;
                        lHit.HitCollider   = lColliders[i];
                        lHit.HitOrigin     = lLinePoint;
                        lHit.HitPoint      = lColliderPoint;
                        lHit.HitDistance   = lDistance - _Radius - 0.001f;

                        lHits.Add(lHit);
                    }
                }
            }

            GeometryExt.Ignore      = null;
            GeometryExt.IgnoreArray = null;

            return(lHits);
        }
Пример #3
0
        /// <summary>
        /// Tests if this motion should be started. However, the motion
        /// isn't actually started.
        /// </summary>
        /// <returns></returns>
        public override bool TestActivate()
        {
            // If we're not startable, this is easy
            if (!mIsStartable)
            {
                return(false);
            }

            // If we're working as an NPC, this changes things a bit. We're being controlled
            // by our velocity. So, use that to determine if we're heading up.
            if (mActorController.UseTransformPosition)
            {
                if (!mActorController.IsGrounded)
                {
                    // If we're moving up, we're probably jumping
                    Vector3 lVerticalVelocity = Vector3.Project(mActorController.State.Velocity, mActorController._Transform.up);
                    if (Vector3.Dot(lVerticalVelocity, mActorController._Transform.up) > 0f)
                    {
                        if (mMotionLayer.ActiveMotion == null ||
                            mMotionLayer.ActiveMotion.Category != EnumMotionCategories.CLIMB)
                        {
                            return(true);
                        }
                    }
                }

                return(false);
            }

            // If we're not grounded, this is easy
            if (!mActorController.IsGrounded)
            {
                return(false);
            }

            // Ensure we have input to test
            if (_ActionAlias.Length == 0 || mMotionController._InputSource == null)
            {
                return(false);
            }

            // Test the action alias
            if (!mMotionController._InputSource.IsJustPressed(_ActionAlias))
            {
                return(false);
            }

            // Perform an upward raycast to determine if something is overhead. If it is, we need
            // to prevent or stop a jump
            if (_RequiredOverheadDistance > 0f)
            {
                if (RaycastExt.SafeRaycast(mActorController._Transform.position, mActorController._Transform.up, _RequiredOverheadDistance, mActorController._CollisionLayers, mActorController._Transform))
                {
                    return(false);
                }
            }

            // Allow the jump
            return(true);
        }
Пример #4
0
        /// <summary>
        /// Shoot a ray to determine if we found a ladder
        /// </summary>
        /// <returns>Boolean that says if we've found an acceptable edge</returns>
        public virtual bool TestForClimbUp()
        {
            // If there is active input pulling us away from the object, stop
            if (Mathf.Abs(mMotionController._InputSource.InputFromAvatarAngle) > 100f)
            {
                return(false);
            }

            // Test for an edge
            if (!RaycastExt.GetForwardEdge(mActorController._Transform, _MaxDistance, _MaxHeight, _ClimbableLayers, out mRaycastHitInfo))
            {
                return(false);
            }

            // Ensure the edge is in range
            Vector3 lLocalHitPoint = mActorController._Transform.InverseTransformPoint(mRaycastHitInfo.point);

            if (lLocalHitPoint.y + mActorController.State.GroundSurfaceDistance < _MinHeight - 0.01f)
            {
                return(false);
            }
            if (lLocalHitPoint.z < _MinDistance)
            {
                return(false);
            }

            // If we got here, we're good
            return(true);
        }
Пример #5
0
        /// <summary>
        /// Casts a ray out of the reticle (camera) to determine if we hit something.
        /// </summary>
        /// <param name="rHitInfo">RaycastHit with the hit information</param>
        /// <param name="rMinDistance">Distance from the camera to start the ray</param>
        /// <param name="rMaxDistance">Max distance to shoot the ray</param>
        /// <param name="rRadius">Radius of the ray (use 0 for a simple ray)</param>
        /// <param name="rLayerMask">Layers to collide with</param>
        /// <param name="rIgnore">Object that we'll ignore collision with</param>
        /// <returns>Returns true if a collision occurs or false if not</returns>
        public virtual bool Raycast(out RaycastHit rHitInfo, float rMinDistance, float rMaxDistance, float rRadius, int rLayerMask = -1, Transform rIgnore = null)
        {
            if (RaycastRoot == null && Camera.main != null)
            {
                RaycastRoot = Camera.main.transform;
            }

            Transform lOrigin = (RaycastRoot != null ? RaycastRoot : null);

            if (lOrigin == null)
            {
                lOrigin = transform;
            }

            Vector3 lStart     = lOrigin.position + (lOrigin.forward * rMinDistance);
            Vector3 lDirection = lOrigin.forward;

            rHitInfo = RaycastExt.EmptyHitInfo;

            if (rRadius > 0f)
            {
                if (RaycastExt.SafeSphereCast(lStart, lDirection, rRadius, out rHitInfo, rMaxDistance - rMinDistance, rLayerMask, rIgnore, null, true))
                {
                    return(true);
                }
            }

            // We do this even after the sphere cast so that we select the position in the reticle
            if (RaycastExt.SafeRaycast(lStart, lDirection, out rHitInfo, rMaxDistance, rLayerMask, rIgnore, null, true))
            {
                return(true);
            }

            return(false);
        }
Пример #6
0
        /// <summary>
        /// Called each frame that the action is active
        /// </summary>
        public override void Update()
        {
            if (mProjector != null)
            {
                RaycastHit lHitInfo;
                Transform  lOwner = _Spell.Owner.transform;

                Ray lRay = Camera.main.ScreenPointToRay(UnityEngine.Input.mousePosition);
                if (RaycastExt.SafeRaycast(lRay.origin, lRay.direction, out lHitInfo, 200f, -1, lOwner))
                {
                    float lAngle = Vector3.Angle(lHitInfo.normal, lOwner.up);
                    if (!_RequireMatchingUp || Mathf.Abs(lAngle) <= 2f)
                    {
                        Vector3 lToPoint         = lHitInfo.point - lOwner.position;
                        float   lToPointDistance = lToPoint.magnitude;
                        mForward = lToPoint.normalized;

                        lToPointDistance = Mathf.Clamp(lToPointDistance, (MinDistance > 0f ? MinDistance : lToPointDistance), MaxDistance);
                        mPosition        = lOwner.position + (mForward * lToPointDistance);

                        mProjector.transform.rotation = Quaternion.LookRotation(-lOwner.up, mForward);
                        mProjector.transform.position = mPosition + (Vector3.up * 1f);
                    }
                }

                // Determine if we're done choosing a point
                if (_Spell.SpellInventory != null && _Spell.SpellInventory._InputSource != null)
                {
                    if (_Spell.SpellInventory._InputSource.IsJustPressed(_ActionAlias))
                    {
                        OnSelected(null, mPosition);
                    }
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Casts a ray using the reticle and then validates the position
        /// </summary>
        /// <returns></returns>
        protected virtual bool Raycast(bool rUseReticle = true)
        {
            bool      lRayHit = false;
            Transform lOwner  = mOwner.transform;

            if (rUseReticle && TargetingReticle.Instance != null)
            {
                RaycastHit[] lHitInfos;
                int          lHitCount = TargetingReticle.Instance.RaycastAll(out lHitInfos, _MinDistance, _MaxDistance, _Radius, _CollisionLayers, lOwner);

                if (lHitCount > 0)
                {
                    if (_Tags == null || _Tags.Length == 0)
                    {
                        lRayHit  = true;
                        mHitInfo = lHitInfos[0];
                    }
                    else
                    {
                        for (int i = 0; i < lHitCount; i++)
                        {
                            IAttributeSource lAttributeSource = lHitInfos[i].collider.gameObject.GetComponent <IAttributeSource>();
                            if (lAttributeSource != null && lAttributeSource.AttributesExist(_Tags))
                            {
                                lRayHit  = true;
                                mHitInfo = lHitInfos[i];

                                break;
                            }
                        }
                    }
                }
            }
            else
            {
                Ray lRay = Camera.main.ScreenPointToRay(UnityEngine.Input.mousePosition);
                if (RaycastExt.SafeRaycast(lRay.origin, lRay.direction, out mHitInfo, _MaxDistance, _CollisionLayers, lOwner))
                {
                    if (_Tags == null || _Tags.Length == 0)
                    {
                        lRayHit = true;
                    }
                    else
                    {
                        IAttributeSource lAttributeSource = mHitInfo.collider.gameObject.GetComponent <IAttributeSource>();
                        if (lAttributeSource != null && lAttributeSource.AttributesExist(_Tags))
                        {
                            lRayHit = true;
                        }
                    }
                }
            }

            return(lRayHit);
        }
Пример #8
0
        /// <summary>
        /// Test if we have an impact. If we have a prediction factor an impact may not occur, but we
        /// will store the prediction.
        /// </summary>
        /// <param name="rMovementDirection"></param>
        /// <param name="rMovementDistance"></param>
        /// <param name="rPrecictFactor"></param>
        /// <returns></returns>
        protected virtual bool TestImpact(Vector3 rStartPosition, Vector3 rMovementDirection, float rMovementDistance, float rPredictFactor = 2f)
        {
#if OOTII_DEBUG
            Debug.DrawLine(rStartPosition, rStartPosition + (rMovementDirection * Mathf.Max(rMovementDistance * rPredictFactor, 0.1f)), Color.red);
#endif

            // Test for a hit
            RaycastHit lRaycastHit;
            if (RaycastExt.SafeRaycast(rStartPosition, rMovementDirection, out lRaycastHit, Mathf.Max(rMovementDistance * rPredictFactor, 0.1f), -1, _Transform))
            {
                // Ensure we're not hitting another projectile
                if (lRaycastHit.collider.gameObject.GetComponent <IProjectileCore>() != null)
                {
                    return(false);
                }

                // This is really a predictive hit ans we extended the Distance a bit
                Collider  lHitCollider  = lRaycastHit.collider;
                Vector3   lHitPoint     = lRaycastHit.point + (rMovementDirection * _EmbedDistance);
                Transform lHitTransform = GetClosestTransform(lHitPoint, lHitCollider.transform);

                Vector3 lHitPosition = lHitTransform.InverseTransformPoint(lHitPoint);
                float   lDistance    = Vector3.Distance(lHitPosition, mLaunchPosition);
                if (lDistance < _MinRange)
                {
                    mHasExpired = true;
                    //mSpellAction.OnFailure();

                    return(false);
                }

#if OOTII_DEBUG
                mWorldHitPoint = lHitPoint;
                GraphicsManager.DrawLine(rStartPosition, rStartPosition + (rMovementDirection * Mathf.Max(rMovementDistance * rPredictFactor, 0.1f)), Color.red);
#endif

                // If we're within the actual Distance, we will consider this a real hit
                if (lRaycastHit.distance - rMovementDistance <= 0f)
                {
                    mLastImpact.Collider = lHitCollider;
                    mLastImpact.Point    = lHitPoint;
                    mLastImpact.Normal   = lRaycastHit.normal;
                    mLastImpact.Vector   = rMovementDirection;
                    mLastImpact.Distance = lRaycastHit.distance;
                    mLastImpact.Index    = mImpactCount;

                    OnImpact(mLastImpact);

                    return(true);
                }
            }

            return(false);
        }
Пример #9
0
        /// <summary>
        /// Updates the motion over time. This is called by the controller
        /// every update cycle so animations and stages 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>
        public override void Update(float rDeltaTime, int rUpdateIndex)
        {
            mMovement = Vector3.zero;

            // Add movement based on the dive
            if ((mMotionLayer._AnimatorStateID == STATE_run_to_dive && mMotionLayer._AnimatorStateNormalizedTime > 0.5f) ||
                mMotionLayer._AnimatorTransitionID == TRANS_run_to_dive_SwimIdlePose ||
                mMotionLayer._AnimatorTransitionID == TRANS_run_to_dive_TreadIdlePose)
            {
                mMovement = mMomentum * _InWaterMomentumFactor * rDeltaTime;
            }

            // Test if it's time to play the splash
            if (!mHasHitWater)
            {
                if ((mMotionLayer._AnimatorStateID == STATE_run_to_dive && mMotionLayer._AnimatorStateNormalizedTime > 0.65f) ||
                    (mMotionLayer._AnimatorStateID == STATE_StandingDive && mMotionLayer._AnimatorStateNormalizedTime > 0.65f))
                {
                    float lDepth = mSwimmerInfo.GetDepth();

                    if (!mHasSplashed && lDepth > 0.1f)
                    {
                        mHasSplashed = true;
                        mSwimmerInfo.CreateSplash(mMotionController._Transform.position + (mMotionController._Transform.forward * 1f));
                    }

                    if (lDepth > _RecoverDepth)
                    {
                        mHasHitWater = true;
                        mSwimmerInfo.EnterWater();

                        mMotionController.SetAnimatorMotionPhase(mMotionLayer._AnimatorLayerIndex, PHASE_ENTER_WATER, true);
                    }
                }
            }
            else
            {
                // We still want gravity to take effect to a little while... just to represent momentum
                if (mMomentum.y == 0f && mMotionLayer._AnimatorTransitionID != 0 && mMotionLayer._AnimatorTransitionNormalizedTime < 0.5f)
                {
                    mMovement.y = mMovement.y + (UnityEngine.Physics.gravity.y * _InWaterMomentumFactor * 0.25f * rDeltaTime);
                }
            }

            // This is a safety check to ensure we don't run aground
            if ((mMotionLayer._AnimatorStateID == STATE_run_to_dive && mMotionLayer._AnimatorStateNormalizedTime > 0.65f))
            {
                if (RaycastExt.SafeRaycast(mMotionController._Transform.position + (Vector3.up * mSwimmerInfo.EnterDepth * 0.1f), Vector3.down, 0.12f, mActorController.GroundingLayers, mMotionController._Transform, null, false))
                {
                    Deactivate();
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Test if we hit a wall based on how we're moving.
        /// </summary>
        /// <param name="rMovement">Movement we're trying to make</param>
        /// <param name="rWallHitInfo">Returned information about the wall (if there is a hit)</param>
        /// <returns>Determines if we actually hit a wall</returns>
        protected bool TestForWallCollision(Vector3 rMovement, out RaycastHit rWallHitInfo)
        {
            Vector3 lRayStart     = transform.position + (transform.up * 0.7f);
            Vector3 lRayDirection = rMovement.normalized;
            float   lRayDistance  = 0.8f;

            if (RaycastExt.SafeRaycast(lRayStart, lRayDirection, out rWallHitInfo, lRayDistance))
            {
                return(true);
            }

            return(false);
        }
Пример #11
0
        /// <summary>
        /// Find a position by targeting down
        /// </summary>
        /// <returns></returns>
        public virtual bool FindPosition()
        {
            Transform lOwner = _Spell.Owner.transform;

            float lStep = (_MinDistance - _MinDistance) / 5f;

            // Start at the center and spiral out
            for (float lDistance = _MaxDistance; lDistance >= _MinDistance; lDistance = lDistance - lStep)
            {
                //GraphicsManager.DrawLine(mMotionController.CameraTransform.position, mMotionController.CameraTransform.TransformPoint(lPosition), (lCount == 0 ? Color.red : lColor), null, 5f);

                RaycastHit lHitInfo;
                Vector3    lStart     = lOwner.position + _StartOffset + (lOwner.forward * lDistance);
                Vector3    lDirection = -lOwner.up;
                if (RaycastExt.SafeRaycast(lStart, lDirection, out lHitInfo, _MaxDistance, _CollisionLayers, lOwner))
                {
                    // Grab the gameobject this collider belongs to
                    GameObject lGameObject = lHitInfo.collider.gameObject;

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

                    if (_Tags != null && _Tags.Length > 0)
                    {
                        IAttributeSource lAttributeSource = lGameObject.GetComponent <IAttributeSource>();
                        if (lAttributeSource == null || !lAttributeSource.AttributesExist(_Tags))
                        {
                            continue;
                        }
                    }

                    // Determine if we're done choosing a point
                    if (_Spell.Data.Positions == null)
                    {
                        _Spell.Data.Positions = new List <Vector3>();
                    }
                    _Spell.Data.Positions.Clear();

                    _Spell.Data.Positions.Add(lHitInfo.point);

                    return(true);
                }
            }

            // Return the target hit
            return(false);
        }
Пример #12
0
        /// <summary>
        /// Determines the cameras vertical distance to the ground
        /// </summary>
        /// <returns></returns>
        public float GetGroundDistance()
        {
            Vector3 lStart    = RigController._Transform.position;
            float   lDistance = (_GroundDistance > 0f ? _GroundDistance * 20f : 100f);

            RaycastHit lHitInfo;

            if (RaycastExt.SafeRaycast(lStart, Vector3.down, out lHitInfo, lDistance, _GroundLayers, _Anchor))
            {
                return(lHitInfo.distance);
            }

            return(0f);
        }
Пример #13
0
        /// <summary>
        /// Provides a place to set the properties of the animator
        /// </summary>
        /// <param name="rInput">Vector3 representing the input</param>
        /// <param name="rMove">Vector3 representing the amount of movement taking place (in world space)</param>
        /// <param name="rRotate">Quaternion representing the amount of rotation taking place</param>
        protected override void SetAnimatorProperties(Vector3 rInput, Vector3 rMovement, Quaternion rRotation)
        {
            if (mInputSource == null || !mInputSource.IsEnabled)
            {
                return;
            }

            // Jump based on space
            bool lIsInJump = !mActorController.State.IsGrounded;

            if (mInputSource.IsJustPressed("Jump"))
            {
                if (!lIsInJump && !mIsInJumpToWall)
                {
                    lIsInJump = true;

                    // We need to check if we're actually jumping towards a wall
                    RaycastHit lHitInfo;
                    if (RaycastExt.SafeRaycast(transform.position + (transform.up * JumpToWallHeight), transform.forward, out lHitInfo, JumpToWallDistance))
                    {
                        mIsInJumpToWall        = true;
                        mJumpToWallPoint       = lHitInfo.point;
                        mJumpToWallNormal      = lHitInfo.normal;
                        mJumpToWallElapsedTime = 0f;

                        mSavedOrientToGroundSpeed            = mActorController.OrientToGroundSpeed;
                        mActorController.OrientToGroundSpeed = JumpToWallOrientSpeed;
                    }

                    // Perform the jump
                    mActorController.AddImpulse(transform.up * _JumpForce);
                }
            }

            // Direction of the camera
            float lDirection = 0f;

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

            // Forward direction of the actor in "natural up"
            Vector3 lControllerForward = lInvTilt * mActorController._Transform.forward;

            // Get the angular difference between the camera-based input and the spider's "natural-up" forward
            lDirection = NumberHelper.GetHorizontalAngle(lControllerForward, rInput);

            mAnimator.SetFloat("Direction", lDirection);
            mAnimator.SetFloat("Speed", rInput.magnitude);
            mAnimator.SetBool("Jump", lIsInJump);
        }
Пример #14
0
        /// <summary>
        /// Event function for when we arrive at the destination. In this instance,
        /// we're going to find a random position and move there.
        /// </summary>
        protected override void OnArrived()
        {
            bool    lIsPositionValid = false;
            Vector3 lNewPosition     = Vector3.zero;

            for (int i = 0; i < 20; i++)
            {
                lNewPosition = GetRandomPosition();
                if (Vector3.Distance(lNewPosition, transform.position) < 2f)
                {
                    continue;
                }

                if (lNewPosition.x < -45 || lNewPosition.x > 45)
                {
                    lNewPosition = new Vector3(12, 0, 24);
                }
                if (lNewPosition.z < -45 || lNewPosition.z > 45)
                {
                    lNewPosition = new Vector3(12, 0, 24);
                }

                Collider[] lColliders = null;
                int        lHits      = RaycastExt.SafeOverlapSphere(lNewPosition, mActorController.OverlapRadius * 2f, out lColliders, -1, transform);

                // Ensure the position isn't someplace we can't get to
                if (lColliders == null || lHits == 0)
                {
                    lIsPositionValid = true;
                }
                else if (lHits == 1 && lColliders[0] is TerrainCollider)
                {
                    lIsPositionValid = true;
                }

                if (lIsPositionValid)
                {
                    break;
                }
            }

            // If we have a valid position, set it
            if (lIsPositionValid)
            {
                TargetPosition = lNewPosition;
            }
        }
        /// <summary>
        /// Sphere cast collisions are slower to perform, but will test for collisions that
        /// may be parallel to the bone axis due to the radius of the bone. We do this check
        /// after the previous one.
        /// </summary>
        /// <param name="rIndex"></param>
        /// <returns>Determines if a collision occured or not</returns>
        private bool ProcessBoneCollisions(int rIndex)
        {
            // Ensure the ignore list is built
            if (mBoneTransforms.Count == 0 && mBones.Count > 0)
            {
                if (mBones[0].Parent != null)
                {
                    mBoneTransforms.Add(mBones[0].Parent._Transform);
                }

                for (int i = 0; i < mBones.Count; i++)
                {
                    mBoneTransforms.Add(mBones[i]._Transform);
                }
            }

            // Test for collisions
            float   lBoneRadius  = 0.02f;
            float   lBoneLength  = _BoneInfo[rIndex].Length;
            Vector3 lBoneVector  = _BoneInfo[rIndex + 1].Position - _BoneInfo[rIndex].Position;
            Vector3 lBoneForward = lBoneVector.normalized;

            Vector3 lBoneStart = _BoneInfo[rIndex].Position + (lBoneForward * lBoneRadius);

            //Vector3 lBoneEnd = _BoneInfo[rIndex].Position + (lBoneForward * (lBoneLength - lBoneRadius));

            // Test if there is a collision within the start of the bone. If so we don't need to go on.
            Collider[] lColliders = null;
            int        lHits      = RaycastExt.SafeOverlapSphere(lBoneStart, lBoneRadius, out lColliders, _CollisionLayers, null, mBoneTransforms);

            if (lColliders != null && lHits > 0)
            {
                return(true);
            }

            // Do a sphere cast down the length of the bone
            RaycastHit[] lHitArray = null;
            lHits = RaycastExt.SafeSphereCastAll(lBoneStart, lBoneForward, lBoneRadius, out lHitArray, lBoneLength - (lBoneRadius * 2f), _CollisionLayers, null, mBoneTransforms);
            if (lHits > 0)
            {
                return(true);
            }

            // No collision
            return(false);
        }
Пример #16
0
        /// <summary>
        /// Casts a ray out of the reticle (camera) and returns all the items that the ray hits
        /// </summary>
        /// <param name="rHitInfos">RaycastHit info that describes what are hit</param>
        /// <param name="rMinDistance">Starting distance of the ray</param>
        /// <param name="rMaxDistance">Max distance of the ray</param>
        /// <param name="rRadius">Radius to use in order to cast a sphere</param>
        /// <param name="rLayerMask">Mask of things to hit</param>
        /// <param name="rIgnore">Transform to ignore</param>
        /// <param name="rIgnoreList">List of transforms to ignore</param>
        /// <returns>Number of items the ray hits</returns>
        public virtual int RaycastAll(out RaycastHit[] rHitInfos, float rMinDistance, float rMaxDistance, float rRadius, int rLayerMask = -1, Transform rIgnore = null, List <Transform> rIgnoreList = null)
        {
            if (RaycastRoot == null && Camera.main != null)
            {
                RaycastRoot = Camera.main.transform;
            }

            Transform lOrigin = (RaycastRoot != null ? RaycastRoot : null);

            if (lOrigin == null)
            {
                lOrigin = transform;
            }

            Vector3 lStart     = lOrigin.position + (lOrigin.forward * rMinDistance);
            Vector3 lDirection = lOrigin.forward;

            int lHitCount = 0;

            if (rRadius <= 0)
            {
                lHitCount = RaycastExt.SafeRaycastAll(lStart, lDirection, out rHitInfos, rMaxDistance - rMinDistance, rLayerMask, rIgnore, rIgnoreList, true);
            }
            else
            {
                lHitCount = RaycastExt.SafeSphereCastAll(lStart, lDirection, rRadius, out rHitInfos, rMaxDistance - rMinDistance, rLayerMask, rIgnore, rIgnoreList, true);
            }

            if (lHitCount > 1)
            {
                Array.Sort(rHitInfos, 0, lHitCount, RaycastExt.HitDistanceComparer);
            }

            //Graphics.GraphicsManager.DrawLine(lStart, lStart + (lDirection * (rMaxDistance - rMinDistance)), Color.red);

            //for (int i = 0; i < lHitCount; i++)
            //{
            //    Graphics.GraphicsManager.DrawPoint(rHitInfos[i].point, Color.red);
            //}

            return(lHitCount);
        }
Пример #17
0
        /// <summary>
        /// Checks if the shape currently overlaps any colliders
        /// </summary>
        /// <param name="rPositionDelta">Movement to add to the current position</param>
        /// <param name="rLayerMask">Layer mask for determing what we'll collide with</param>
        /// <returns>Boolean that says if a hit occured or not</returns>
        public override List <BodyShapeHit> CollisionOverlap(Vector3 rPositionDelta, Quaternion rRotationDelta, int rLayerMask)
        {
            List <BodyShapeHit> lHits = new List <BodyShapeHit>();

            Vector3 lBodyShapePos1 = rPositionDelta + (_Transform == null ? _Parent.position + ((_Parent.rotation * rRotationDelta) * _Offset) : _Transform.position + ((_Transform.rotation * rRotationDelta) * _Offset));

            Collider[] lColliders    = null;
            int        lColliderHits = RaycastExt.SafeOverlapSphere(lBodyShapePos1, _Radius, out lColliders, -1, _Parent);

            for (int i = 0; i < lColliderHits; i++)
            {
                if (lColliders[i].transform == _Transform)
                {
                    continue;
                }
                if (_CharacterController != null && _CharacterController.IsIgnoringCollision(lColliders[i]))
                {
                    continue;
                }

                // Once we get here, we have a valid collider
                Vector3 lLinePoint     = lBodyShapePos1;
                Vector3 lColliderPoint = GeometryExt.ClosestPoint(lBodyShapePos1, _Radius, lColliders[i]);

                float lDistance = Vector3.Distance(lLinePoint, lColliderPoint);
                if (lDistance < _Radius + 0.001f)
                {
                    BodyShapeHit lHit = BodyShapeHit.Allocate();
                    lHit.StartPosition = lBodyShapePos1;
                    lHit.HitCollider   = lColliders[i];
                    lHit.HitOrigin     = lLinePoint;
                    lHit.HitPoint      = lColliderPoint;
                    lHit.HitDistance   = lDistance - _Radius - 0.001f;

                    lHits.Add(lHit);
                }
            }

            return(lHits);
        }
Пример #18
0
        /// <summary>
        /// Provides a place to set the properties of the animator
        /// </summary>
        /// <param name="rInput">Vector3 representing the input</param>
        /// <param name="rMove">Vector3 representing the amount of movement taking place (in world space)</param>
        /// <param name="rRotate">Quaternion representing the amount of rotation taking place</param>
        protected override void SetAnimatorProperties(Vector3 rInput, Vector3 rMovement, Quaternion rRotation)
        {
            if (mInputSource == null || !mInputSource.IsEnabled)
            {
                return;
            }

            // Jump based on space
            bool lIsInJump = !mActorController.State.IsGrounded;

            if (mInputSource.IsJustPressed("Jump"))
            {
                if (!lIsInJump && !mIsInJumpToWall)
                {
                    lIsInJump = true;

                    // We need to check if we're actually jumping towards a wall
                    RaycastHit lHitInfo;
                    if (RaycastExt.SafeRaycast(transform.position + (transform.up * JumpToWallHeight), transform.forward, out lHitInfo, JumpToWallDistance))
                    {
                        mIsInJumpToWall        = true;
                        mJumpToWallPoint       = lHitInfo.point;
                        mJumpToWallNormal      = lHitInfo.normal;
                        mJumpToWallElapsedTime = 0f;

                        mSavedOrientToGroundSpeed            = mActorController.OrientToGroundSpeed;
                        mActorController.OrientToGroundSpeed = JumpToWallOrientSpeed;
                    }

                    // Perform the jump
                    mActorController.AddImpulse(transform.up * _JumpForce);
                }
            }

            // Tell the animator what to do next
            mAnimator.SetFloat("Speed", rInput.magnitude);
            mAnimator.SetFloat("Direction", Mathf.Atan2(rInput.x, rInput.z) * 180.0f / 3.14159f);
            mAnimator.SetBool("Jump", lIsInJump);
        }
Пример #19
0
        /// <summary>
        /// Shoot a ray to determine if we found a ladder
        /// </summary>
        /// <returns>Boolean that says if we've found an acceptable edge</returns>
        public virtual bool TestForClimbUp()
        {
            // If there is active input pulling us away from the object, stop
            if (mMotionController._InputSource != null && Mathf.Abs(mMotionController._InputSource.InputFromAvatarAngle) > 100f)
            {
                return(false);
            }

#if UNITY_EDITOR
            if (ShowDebug)
            {
                Transform lRoot = mActorController._Transform;
                GraphicsManager.DrawLine(lRoot.position + new Vector3(0f, _MinHeight, 0f) + (mMotionController.transform.forward * _MinDistance), lRoot.position + new Vector3(0f, _MinHeight, 0f) + (mMotionController.transform.forward * _MaxDistance), Color.green, null, 2f);
                GraphicsManager.DrawLine(lRoot.position + new Vector3(0f, _MaxHeight, 0f) + (mMotionController.transform.forward * _MinDistance), lRoot.position + new Vector3(0f, _MaxHeight, 0f) + (mMotionController.transform.forward * _MaxDistance), Color.green, null, 2f);
            }
#endif

            // Test for an edge
            if (!RaycastExt.GetForwardEdge(mActorController._Transform, _MaxDistance, _MaxHeight, _ClimbableLayers, out mRaycastHitInfo))
            {
                return(false);
            }

            // Ensure the edge is in range
            Vector3 lLocalHitPoint = mActorController._Transform.InverseTransformPoint(mRaycastHitInfo.point);
            if (lLocalHitPoint.y + mActorController.State.GroundSurfaceDistance < _MinHeight - 0.01f)
            {
                return(false);
            }
            if (lLocalHitPoint.z < _MinDistance)
            {
                return(false);
            }

            // If we got here, we're good
            return(true);
        }
Пример #20
0
        /// <summary>
        /// Test if we're about to run off a ledge, but there's a wall under us we can orient too instead
        /// </summary>
        /// <param name="rMovement">Movement we're trying to make</param>
        /// <param name="rWallHitInfo">Returned information about the wall (if there is a hit)</param>
        /// <returns>Determines if we actually hit a wall</returns>
        protected bool TestForWallAt90DegreeDrop(Vector3 rMovement, out RaycastHit rWallHitInfo)
        {
            if (mActorController.IsGrounded)
            {
                rWallHitInfo = RaycastExt.EmptyHitInfo;
                return(false);
            }

            Vector3 lRayStart     = transform.position + (transform.up * 0.7f);
            Vector3 lRayDirection = rMovement.normalized;
            float   lRayDistance  = 0.8f;

            // First, test if there's a wall in front of us. If so, we can stop as that means there is no drop
            if (RaycastExt.SafeRaycast(lRayStart, lRayDirection, out rWallHitInfo, lRayDistance))
            {
                return(false);
            }

            lRayStart     = transform.position + (rMovement * 0.1f) + (transform.up * 0.7f);
            lRayDirection = -transform.up;
            lRayDistance  = 0.8f;

            // Next, test if there's an empty floor ahead of us
            if (!RaycastExt.SafeRaycast(lRayStart, lRayDirection, out rWallHitInfo, lRayDistance))
            {
                lRayStart     = transform.position + (rMovement * 0.1f) - (transform.up * 0.1f);
                lRayDirection = -rMovement.normalized;
                lRayDistance  = 0.8f;

                if (RaycastExt.SafeRaycast(lRayStart, lRayDirection, out rWallHitInfo, lRayDistance))
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #21
0
        /// <summary>
        /// Determines if the swimmer is in shallow water
        /// </summary>
        /// <param name="rGroundLayers">Ground Layer masks to testing the ground</param>
        /// <returns></returns>
        public bool IsInShallowWater(int rGroundLayers = -1)
        {
            if (mTransform == null)
            {
                return(false);
            }

            float lDepth = GetDepth();

            if (lDepth > mEnterDepth)
            {
                return(false);
            }

            // Test if the ground is close
            Vector3 lStart = mTransform.position + (Vector3.up * mEnterDepth);

            if (RaycastExt.SafeRaycast(lStart, Vector3.down, mEnterDepth + 0.1f, rGroundLayers, mTransform, null, false))
            {
                return(true);
            }

            return(false);
        }
Пример #22
0
        /// <summary>
        /// Casts out a shape to see if a collision will occur. The resulting array
        /// should NOT be persisted. It is re-used by this function over and over to
        /// reduce memory allocation.
        /// </summary>
        /// <param name="rPositionDelta">Movement to add to the current position</param>
        /// <param name="rDirection">Direction of the cast</param>
        /// <param name="rDistance">Distance of the case</param>
        /// <param name="rLayerMask">Layer mask for determing what we'll collide with</param>
        /// <returns>Returns an array of BodyShapeHit values representing all the hits that take place</returns>
        public override BodyShapeHit[] CollisionCastAll(Vector3 rPositionDelta, Vector3 rDirection, float rDistance, int rLayerMask)
        {
            Vector3 lBodyShapePos1 = rPositionDelta + (_Transform == null ? _Parent.position + (_Parent.rotation * _Offset) : _Transform.position + (_Transform.rotation * _Offset));

            // Clear any existing body shape hits. They are released by the calloer
            for (int i = 0; i < mBodyShapeHitArray.Length; i++)
            {
                mBodyShapeHitArray[i] = null;
            }

            // Use the non-allocating version if we can
            int lHitCount = 0;

#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
            mRaycastHitArray = UnityEngine.Physics.SphereCastAll(lBodyShapePos1, _Radius, rDirection, rDistance + EPSILON, rLayerMask);
            if (mRaycastHitArray != null)
            {
                lHitCount          = mRaycastHitArray.Length;
                mBodyShapeHitArray = new BodyShapeHit[lHitCount];
            }
#else
            lHitCount = UnityEngine.Physics.SphereCastNonAlloc(lBodyShapePos1, _Radius, rDirection, mRaycastHitArray, rDistance + EPSILON, rLayerMask, QueryTriggerInteraction.Ignore);
#endif

            int lBodyShapeHitsIndex = 0;
            for (int i = 0; i < lHitCount; i++)
            {
                if (mRaycastHitArray[i].collider.isTrigger)
                {
                    continue;
                }
                if (_CharacterController != null && _CharacterController.IsIgnoringCollision(mRaycastHitArray[i].collider))
                {
                    continue;
                }

                Transform lCurrentTransform = mRaycastHitArray[i].collider.transform;
                if (lCurrentTransform == _Transform)
                {
                    continue;
                }

                // Ensure we're not colliding with a transform in our chain
                bool lIsValidHit = true;
                while (lCurrentTransform != null)
                {
                    if (lCurrentTransform == _Parent)
                    {
                        lIsValidHit = false;
                        break;
                    }

                    lCurrentTransform = lCurrentTransform.parent;
                }

                if (!lIsValidHit)
                {
                    continue;
                }

                // Once we get here, we have a valid collider
                BodyShapeHit lBodyShapeHit = BodyShapeHit.Allocate();
                lBodyShapeHit.StartPosition = lBodyShapePos1;
                lBodyShapeHit.Shape         = this;
                lBodyShapeHit.Hit           = mRaycastHitArray[i];
                lBodyShapeHit.HitOrigin     = lBodyShapePos1;
                lBodyShapeHit.HitCollider   = mRaycastHitArray[i].collider;
                lBodyShapeHit.HitPoint      = mRaycastHitArray[i].point;
                lBodyShapeHit.HitNormal     = mRaycastHitArray[i].normal;

                // This distance is the distance between the surfaces and not the start!
                lBodyShapeHit.HitDistance = mRaycastHitArray[i].distance;

                // With the sphere cast all, we can recieve hits for colliders that
                // start by intruding on the sphere. In this case, the distance is "0". So,
                // we'll find the true distance ourselves.
                if (mRaycastHitArray[i].distance == 0f)
                {
                    Vector3 lColliderPoint = Vector3.zero;

                    //if (lBodyShapeHit.HitCollider is TerrainCollider)
                    //{
                    //    lColliderPoint = GeometryExt.ClosestPoint(lBodyShapePos1, rDirection * rDistance, _Radius, (TerrainCollider)lBodyShapeHit.HitCollider, rLayerMask);
                    //}
                    //else
                    //{
                    lColliderPoint = GeometryExt.ClosestPoint(lBodyShapePos1, _Radius, lBodyShapeHit.HitCollider, rLayerMask);
                    //}

                    // If we don't have a valid point, we will skip
                    if (lColliderPoint == Vector3.zero)
                    {
                        BodyShapeHit.Release(lBodyShapeHit);
                        continue;
                    }

                    // If the hit is further than our radius, we can skip
                    Vector3 lHitVector = lColliderPoint - lBodyShapePos1;
                    //if (lHitVector.magnitude > _Radius + EPSILON)
                    //{
                    //    BodyShapeHit.Release(lBodyShapeHit);
                    //    continue;
                    //}

                    // Setup the remaining info
                    lBodyShapeHit.HitOrigin = lBodyShapePos1;
                    lBodyShapeHit.HitPoint  = lColliderPoint;

                    // We want distance between the surfaces. We have the start point and
                    // surface collider point. So, we remove our radius to get to the surface.
                    lBodyShapeHit.HitDistance    = lHitVector.magnitude - _Radius;
                    lBodyShapeHit.HitPenetration = (lBodyShapeHit.HitDistance < 0f);

                    // Shoot a ray for the normal
                    RaycastHit lRaycastHitInfo;
                    if (RaycastExt.SafeRaycast(lBodyShapePos1, lHitVector.normalized, out lRaycastHitInfo, Mathf.Max(lBodyShapeHit.HitDistance + _Radius, _Radius + 0.01f)))
                    {
                        lBodyShapeHit.HitNormal = lRaycastHitInfo.normal;
                    }
                    // If the ray is so close that we can't get a result we can end up here
                    else if (lBodyShapeHit.HitDistance < EPSILON)
                    {
                        lBodyShapeHit.HitNormal = (lBodyShapePos1 - lColliderPoint).normalized;
                    }
                }

                // Add the collision info
                if (lBodyShapeHit != null)
                {
                    // We can't really trust the hit normal we have since it probably came from an edge. So, we'll
                    // shoot a ray along our movement path. This will give us a better angle to look at. However, if we're
                    // falling (probably from gravity), we don't want to replace the edge value.
                    if (rDirection != Vector3.down)
                    {
                        RaycastHit lRaycastHitInfo;
                        if (RaycastExt.SafeRaycast(lBodyShapeHit.HitPoint - (rDirection * rDistance), rDirection, out lRaycastHitInfo, rDistance + _Radius, -1, _Parent))
                        {
                            lBodyShapeHit.HitNormal = lRaycastHitInfo.normal;
                        }
                    }

                    // Store the distance between the hit point and our character's root
                    lBodyShapeHit.HitRootDistance = _Parent.InverseTransformPoint(lBodyShapeHit.HitPoint).y;

                    // Add the valid hit to our array
                    mBodyShapeHitArray[lBodyShapeHitsIndex] = lBodyShapeHit;
                    lBodyShapeHitsIndex++;
                }
            }

            // Return this array. The array should not be kept
            return(mBodyShapeHitArray);
        }
Пример #23
0
        /// <summary>
        /// Tests if this motion should be started. However, the motion
        /// isn't actually started.
        /// </summary>
        /// <returns></returns>
        public override bool TestActivate()
        {
            if (!mIsStartable)
            {
                return(false);
            }
            if (!mMotionController.IsGrounded)
            {
                return(false);
            }

            // Raycast if needed
            if (_IsInteractableRaycastEnabled)
            {
                bool lIsFound = false;

                RaycastHit lHitInfo;

                // Even though we have a raycast root, we really want to shoot from the camera. We'll check distance with the root later.
                Vector3 lStart   = (mMotionController.CameraTransform != null ? mMotionController.CameraTransform.position : mMotionController._Transform.position);
                Vector3 lForward = (mMotionController.CameraTransform != null ? mMotionController.CameraTransform.forward : mMotionController._Transform.forward);

                if (RaycastExt.SafeRaycast(lStart, lForward, out lHitInfo, _InteractableDistance * 5f, _InteractableLayers, mMotionController._Transform))
                {
                    bool lIsValid = true;

                    if (mRaycastRoot != null)
                    {
                        float lDistance = Vector3.Distance(lHitInfo.point, mRaycastRoot.position);
                        if (lDistance > _InteractableDistance)
                        {
                            lIsValid = false;
                        }
                    }

                    if (lIsValid)
                    {
                        IInteractableCore lCore = lHitInfo.collider.gameObject.GetComponent <IInteractableCore>();
                        if (lCore == null)
                        {
                            lCore = lHitInfo.collider.gameObject.GetComponentInParent <IInteractableCore>();
                        }

                        if (!_IsInteractableCoreRequired && lCore == null)
                        {
                            lIsFound     = true;
                            Interactable = lHitInfo.collider.gameObject;
                        }
                        else
                        {
                            if (lCore == null)
                            {
                                lIsValid = false;
                            }
                            if (lIsValid && !lCore.IsEnabled)
                            {
                                lIsValid = false;
                            }
                            if (lIsValid && !lCore.TestActivator(mMotionController._Transform))
                            {
                                lIsValid = false;
                            }
                            if (lIsValid && lCore.RaycastCollider != null && lHitInfo.collider != lCore.RaycastCollider)
                            {
                                lIsValid = false;
                            }

                            if (lIsValid)
                            {
                                lIsFound         = true;
                                InteractableCore = lCore;
                                InteractableCore.StartFocus();

                                mActiveForm = lCore.Form;
                            }
                        }
                    }
                }

                // Deselect any interactable if none is found
                if (!lIsFound && _IsInteractableRaycastEnabled)
                {
                    Interactable = null;
                }
            }

            // Test if we're supposed to activate
            if (_ActionAlias.Length > 0 && mMotionController._InputSource != null)
            {
                if (mMotionController._InputSource.IsJustPressed(_ActionAlias))
                {
                    // Check if the interactable is going to prepare thier activator. If so, we
                    // aren't going to activate here. The activator will trigger the activation.
                    if (InteractableCore != null)
                    {
                        if (InteractableCore.ForcePosition || InteractableCore.ForceRotation)
                        {
                            mMotionController.StartCoroutine(MoveToTargetInternal(InteractableCore));
                        }
                        else
                        {
                            return(true);
                        }
                    }
                    // Since we're just dealing with a simple game object, activate
                    else if (Interactable != null)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Пример #24
0
        /// <summary>
        /// Tests if this motion should be started. However, the motion
        /// isn't actually started.
        /// </summary>
        /// <returns></returns>
        public override bool TestActivate()
        {
            if (!mIsStartable)
            {
                return(false);
            }

            if (mMotionController._InputSource != null && mMotionController._InputSource.IsJustPressed(ActionAlias))
            {
                // Grab the swimmer info if it doesn't exist
                if (mSwimmerInfo == null)
                {
                    mSwimmerInfo = SwimmerInfo.GetSwimmerInfo(mMotionController._Transform);
                }
                if (mSwimStrafe == null)
                {
                    mSwimStrafe = mMotionController.GetMotion <Swim_Strafe>();
                }

                // We need to test if there is water to dive in to
                // This is only valid if we're in the right stance
                if (mActorController.State.Stance != EnumControllerStance.SWIMMING)
                {
                    float lWaterDistance    = 0f;
                    float lObstacleDistance = float.MaxValue;


                    // Do a test to see if there is actually water to jump into
                    RaycastHit lHitInfo;

                    float lMinDepth  = Mathf.Max(MinDepth, mSwimmerInfo.EnterDepth * 1.5f);
                    float lDepthTest = Mathf.Max(lMinDepth * 1.6f, mSwimmerInfo.MaxSurfaceTest);

                    float lTestDistance = TestDistance;
                    if (mMotionController.State.InputMagnitudeTrend.Value > 0.5f)
                    {
                        lTestDistance = MovingTestDistance;
                    }

                    // Check if we can dive forward without hitting something
                    Vector3 lStart = mMotionController._Transform.position + (Vector3.up * mSwimmerInfo.EnterDepth);
                    if (!RaycastExt.SafeRaycast(lStart, mMotionController._Transform.forward, lTestDistance, mActorController.CollisionLayers, mMotionController._Transform, null, false))
                    {
                        // Check surface height based on the raycast
                        lStart = mMotionController._Transform.position + (mMotionController._Transform.forward * lTestDistance) + (Vector3.up * mSwimmerInfo.EnterDepth * 1.5f);
                        if (RaycastExt.SafeRaycast(lStart, Vector3.down, out lHitInfo, lDepthTest, mSwimmerInfo.WaterLayers, mMotionController._Transform, null, false))
                        {
                            lWaterDistance = lHitInfo.distance;

                            // Ensure nothing is blocking the water
                            if (RaycastExt.SafeRaycast(lStart, Vector3.down, out lHitInfo, lDepthTest, mActorController.GroundingLayers, mMotionController._Transform, null, false))
                            {
                                lObstacleDistance = Mathf.Min(lHitInfo.distance, lObstacleDistance);
                            }

                            if (RaycastExt.SafeRaycast(lStart, Vector3.down, out lHitInfo, lDepthTest, mActorController.CollisionLayers, mMotionController._Transform, null, false))
                            {
                                lObstacleDistance = Mathf.Min(lHitInfo.distance, lObstacleDistance);
                            }

                            // Ensure there's enough depth to swim in
                            float lMaxDepthFound = lObstacleDistance - lWaterDistance;
                            if (lMaxDepthFound > lMinDepth)
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            // Return the final result
            return(false);
        }
Пример #25
0
        /// <summary>
        /// Shoot rays to determine if a horizontal edge exists that
        /// we may be able to grab onto. It needs to be within the range
        /// of the avatar's feelers.
        /// </summary>
        /// <returns>Boolean that says if we've found an acceptable edge</returns>
        public virtual bool TestForClimbUp()
        {
            // If there is active input pulling us away from the object, stop
            if (mMotionController._InputSource != null && Mathf.Abs(mMotionController._InputSource.InputFromAvatarAngle) > 100f)
            {
                return(false);
            }

            //Vector3 lRayStart = Vector3.zero;

            //float lTargetDistance = mMaxDistance;

            // Root position for the test
            //Transform lRoot = mActorController._Transform;

            // Determine the ray positions
            //float lEdgeTop = mMaxHeight;
            //float lEdgeBottom = mMinHeight;

            // Debug
            //Debug.DrawLine(lRoot.position + new Vector3(0f, lEdgeTop, 0f), lRoot.position + new Vector3(0f, lEdgeTop, 0f) + mMotionController.transform.forward * lTargetDistance, Color.red);
            //Debug.DrawLine(lRoot.position + new Vector3(0f, lEdgeBottom, 0f), lRoot.position + new Vector3(0f, lEdgeBottom, 0f) + mMotionController.transform.forward * lTargetDistance, Color.red);

            // Debug
#if UNITY_EDITOR
            if (ShowDebug)
            {
                Transform lRoot = mActorController._Transform;
                GraphicsManager.DrawLine(lRoot.position + new Vector3(0f, _MinHeight, 0f) + (mMotionController.transform.forward * _MinDistance), lRoot.position + new Vector3(0f, _MinHeight, 0f) + (mMotionController.transform.forward * _MaxDistance), Color.green, null, 2f);
                GraphicsManager.DrawLine(lRoot.position + new Vector3(0f, _MaxHeight, 0f) + (mMotionController.transform.forward * _MinDistance), lRoot.position + new Vector3(0f, _MaxHeight, 0f) + (mMotionController.transform.forward * _MaxDistance), Color.green, null, 2f);
            }
#endif

            // Shoot forward and ensure below the edge is blocked
            //lRayStart = mActorController._Transform.position + (mActorController._Transform.up * lEdgeBottom);
            //if (!RaycastExt.SafeRaycast(lRayStart, mActorController._Transform.forward, lTargetDistance, mClimbableLayers, mActorController._Transform, out mRaycastHitInfo))
            //{
            //    return false;
            //}

            //// If it's too close, we're done
            //if (mRaycastHitInfo.distance < mMinDistance)
            //{
            //    return false;
            //}

            // Find the exact edge that is infront of us
            if (!RaycastExt.GetForwardEdge(mActorController._Transform, _MaxDistance, _MaxHeight, _ClimbableLayers, out mRaycastHitInfo))
            {
                return(false);
            }

            // Ensure the edge is in range
            Vector3 lLocalHitPoint = mActorController._Transform.InverseTransformPoint(mRaycastHitInfo.point);
            if (lLocalHitPoint.y + mActorController.State.GroundSurfaceDistance < _MinHeight - 0.01f)
            {
                return(false);
            }
            if (lLocalHitPoint.z < _MinDistance)
            {
                return(false);
            }

            // Finally, one last check to make sure the area under the edge is NOT clear
            RaycastHit lMidHitInfo;
            Vector3    lRayStart = mActorController._Transform.position + (mActorController._Transform.up * _MinHeight);
            if (!RaycastExt.SafeRaycast(lRayStart, mActorController._Transform.forward, out lMidHitInfo, _MaxDistance, _ClimbableLayers, mActorController._Transform))
            {
                return(false);
            }

            // If we have hand positions, ensure that they collide with something as well. Otherwise,
            // the hand will look like it's floating in the air.
            if (_HandGrabOffset > 0)
            {
                RaycastHit lHandHitInfo;

                // Check the right hand
                Vector3 lRightHandPosition = mRaycastHitInfo.point + (mRaycastHitInfo.normal * 1f) + (mActorController._Transform.rotation * new Vector3(_HandGrabOffset, 0f, 0f));
                if (!RaycastExt.SafeRaycast(lRightHandPosition, -mRaycastHitInfo.normal, out lHandHitInfo, 1.1f, _ClimbableLayers, mActorController._Transform))
                {
                    return(false);
                }

                // Check the left hand
                Vector3 lLeftHandPosition = mRaycastHitInfo.point + (mRaycastHitInfo.normal * 1f) + (mActorController._Transform.rotation * new Vector3(-_HandGrabOffset, 0f, 0f));
                if (!RaycastExt.SafeRaycast(lLeftHandPosition, -mRaycastHitInfo.normal, out lHandHitInfo, 1.1f, _ClimbableLayers, mActorController._Transform))
                {
                    return(false);
                }
            }

            // If we got here, we found an edge
            return(true);
        }
Пример #26
0
        /// <summary>
        /// Attempt to find a target that we can focus on. This approach uses a spiralling raycast
        /// </summary>
        /// <returns></returns>
        public virtual Transform FindTarget()
        {
            float lMaxRadius      = 8f;
            float lMaxDistance    = 20f;
            float lRevolutions    = 2f;
            float lDegreesPerStep = 27f;
            float lSteps          = lRevolutions * (360f / lDegreesPerStep);
            float lRadiusPerStep  = lMaxRadius / lSteps;

            float   lAngle    = 0f;
            float   lRadius   = 0f;
            Vector3 lPosition = Vector3.zero;
            //float lColorPerStep = 1f / lSteps;
            //Color lColor = Color.white;

            Transform lOwner = _Spell.Owner.transform;

            // We want our final revolution to be max radius. So, increase the steps
            lSteps = lSteps + (360f / lDegreesPerStep) - 1f;

            // Start at the center and spiral out
            int lCount = 0;

            for (lCount = 0; lCount < lSteps; lCount++)
            {
                lPosition.x = lRadius * Mathf.Cos(lAngle * Mathf.Deg2Rad);
                lPosition.y = lRadius * Mathf.Sin(lAngle * Mathf.Deg2Rad);
                lPosition.z = lMaxDistance;

                //GraphicsManager.DrawLine(mMotionController.CameraTransform.position, mMotionController.CameraTransform.TransformPoint(lPosition), (lCount == 0 ? Color.red : lColor), null, 5f);

                RaycastHit lHitInfo;
                Vector3    lStart     = lOwner.position + _StartOffset;
                Vector3    lDirection = lOwner.forward;
                if (RaycastExt.SafeRaycast(lStart, lDirection, out lHitInfo, _MaxDistance, _CollisionLayers, lOwner))
                {
                    // Grab the gameobject this collider belongs to
                    GameObject lGameObject = lHitInfo.collider.gameObject;

                    // Don't count the ignore
                    if (lGameObject.transform == lOwner)
                    {
                        continue;
                    }
                    if (lHitInfo.collider is TerrainCollider)
                    {
                        continue;
                    }

                    if (_Tags != null && _Tags.Length > 0)
                    {
                        IAttributeSource lAttributeSource = lGameObject.GetComponent <IAttributeSource>();
                        if (lAttributeSource == null || !lAttributeSource.AttributesExist(_Tags))
                        {
                            continue;
                        }
                    }

                    if (RequiresRigidbody && lGameObject.GetComponent <Rigidbody>() == null)
                    {
                        continue;
                    }
                    if (RequiresActorCore && lGameObject.GetComponent <ActorCore>() == null)
                    {
                        continue;
                    }
                    if (RequiresCombatant && lGameObject.GetComponent <ICombatant>() == null)
                    {
                        continue;
                    }

                    // Store the target
                    if (_Spell.Data.Targets == null)
                    {
                        _Spell.Data.Targets = new List <GameObject>();
                    }
                    _Spell.Data.Targets.Clear();

                    _Spell.Data.Targets.Add(lGameObject);

                    return(lGameObject.transform);
                }

                // Increment the spiral
                lAngle += lDegreesPerStep;
                lRadius = Mathf.Min(lRadius + lRadiusPerStep, lMaxRadius);

                //lColor.r = lColor.r - lColorPerStep;
                //lColor.g = lColor.g - lColorPerStep;
            }

            // Return the target hit
            return(null);
        }
Пример #27
0
        /// <summary>
        /// Shoot rays to determine if a horizontal edge exists that
        /// we may be able to grab onto. It needs to be within the range
        /// of the avatar's feelers.
        /// </summary>
        /// <returns>Boolean that says if we've found an acceptable edge</returns>
        public virtual bool TestForClimbUp()
        {
            float lTargetDistance = _MaxDistance;

            // Root position for the test
            Transform lTransform = mActorController._Transform;

            // Determine the ray positions
            //float lEdgeTop = _MaxHeight;
            //float lEdgeBottom = _MinHeight;

            // Debug
            //Debug.DrawLine(lRoot.position + new Vector3(0f, lEdgeTop, 0f), lRoot.position + new Vector3(0f, lEdgeTop, 0f) + mMotionController.transform.forward * lTargetDistance, Color.red);
            //Debug.DrawLine(lRoot.position + new Vector3(0f, lEdgeBottom, 0f), lRoot.position + new Vector3(0f, lEdgeBottom, 0f) + mMotionController.transform.forward * lTargetDistance, Color.red);

            // Shoot forward and ensure below the edge is blocked
            Vector3 lRayStart     = lTransform.position + (lTransform.up * _MinHeight);
            Vector3 lRayDirection = lTransform.forward;
            float   lRayDistance  = _MaxDistance;

            if (!RaycastExt.SafeRaycast(lRayStart, lRayDirection, out mRaycastHitInfo, lRayDistance, _ClimbableLayers, lTransform))
            {
                return(false);
            }

            float lHitDepth = mRaycastHitInfo.distance;

            // If it's too close, we're done
            if (lHitDepth < _MinDistance)
            {
                return(false);
            }

            // Shoot forward and ensure above the edge is open
            lRayStart = lTransform.position + (lTransform.up * _MaxHeight);

            if (RaycastExt.SafeRaycast(lRayStart, lRayDirection, out mRaycastHitInfo, lRayDistance, _ClimbableLayers, lTransform))
            {
                return(false);
            }

            // Now that we know there is an edge, determine it's exact position.
            // First, we sink into the collision point a tad. Then, we use our
            // collision point and start above it (where the top ray failed). Finally,
            // we shoot a ray down
            lRayStart     = lRayStart + (lTransform.forward * (lHitDepth + 0.01f));
            lRayDirection = -lTransform.up;
            lRayDistance  = _MaxHeight;

            if (!RaycastExt.SafeRaycast(lRayStart, -mMotionController.transform.up, out mRaycastHitInfo, _MaxHeight - _MinHeight + 0.01f, _ClimbableLayers, mActorController._Transform))
            {
                return(false);
            }

            Vector3 lLocalHitPoint = lTransform.InverseTransformPoint(mRaycastHitInfo.point);

            // Finally we shoot one last ray forward. We do this because we want the collision
            // data to be about the wall facing the avatar, not the wall facing the
            // last ray (which was shot down).
            lRayStart     = lTransform.position + (lTransform.up * (lLocalHitPoint.y - 0.01f));
            lRayDirection = lTransform.forward;
            lRayDistance  = _MaxDistance;

            if (!RaycastExt.SafeRaycast(lRayStart, mMotionController.transform.forward, out mRaycastHitInfo, lTargetDistance, _ClimbableLayers, mActorController._Transform))
            {
                return(false);
            }

            // Finally, test for the depth. This needs to be a fence or shallow wall.
            RaycastHit lDepthHitInfo;

            lRayStart = mRaycastHitInfo.point + (mActorController.transform.forward * 0.3f) + (mActorController._Transform.up * 0.2f);
            if (RaycastExt.SafeRaycast(lRayStart, -mMotionController.transform.up, out lDepthHitInfo, _MinHeight, _ClimbableLayers, mActorController._Transform))
            {
                return(false);
            }

            // If we got here, we found an edge
            return(true);
        }
Пример #28
0
        /// <summary>
        /// Shoots a ray into the character that simply tests for a hit
        /// </summary>
        /// <param name="rOrigin"></param>
        /// <param name="rDirection"></param>
        /// <param name="rRange"></param>
        /// <param name="rForce"></param>
        public BoneControllerBone Raycast(Vector3 rOrigin, Vector3 rVelocity, float rRange, bool rStopIfBlocked, ref Vector3 lHitPoint)
        {
            int lHitIndex = 0;
            BoneControllerBone lHitBone = null;

            //float lSpeed = rVelocity.magnitude;
            Vector3 lDirection = rVelocity.normalized;

            // Cast the ray and see if we hit a bone we care about
            //RaycastHit[] lHits = RaycastExt.SafeRaycastAll(rOrigin, lDirection, rRange).OrderBy(h => h.distance).ToArray();
            //RaycastHit[] lHits = RaycastExt.SafeRaycastAll(rOrigin, lDirection, rRange, false);

            RaycastHit[] lHits     = null;
            int          lHitCount = RaycastExt.SafeRaycastAll(rOrigin, lDirection, out lHits, rRange);

            if (lHitCount > 1)
            {
                RaycastExt.Sort(lHits, lHitCount);
            }

            for (lHitIndex = 0; lHitIndex < lHitCount; lHitIndex++)
            {
                if (_UseAllBones)
                {
                    lHitBone = mSkeleton.GetBone(lHits[lHitIndex].collider.transform) as BoneControllerBone;
                }
                else
                {
                    for (int i = 0; i < mBones.Count; i++)
                    {
                        // Grab the collider on the bone (if there is one)
                        Collider lBaseCollider = mBones[i]._Transform.GetComponent <Collider>();

                        if (lHits[lHitIndex].collider == lBaseCollider)
                        {
                            lHitBone = mBones[i];
                            break;
                        }
                    }
                }

                if (lHitBone != null)
                {
                    break;
                }

                // If our first hit isn't a bone, then we're blocked
                if (rStopIfBlocked)
                {
                    return(null);
                }
            }

            // Start grabbing the hit info
            if (lHitBone != null)
            {
                lHitPoint = lHits[lHitIndex].point;
            }

            // Return the fact if we hit a bone or not
            return(lHitBone);
        }
Пример #29
0
        /// <summary>
        /// Called when the action is first activated
        /// <param name="rPreviousSpellActionState">State of the action prior to this one activating</param>
        public override void Activate(int rPreviousSpellActionState = -1, object rData = null)
        {
            base.Activate(rPreviousSpellActionState, rData);

            mActivations   = 0;
            mBatchDelay    = 0f;
            mLastBatchTime = 0f;

            if (_Spell != null && _Spell.Data != null)
            {
                SpellData lSpellData = _Spell.Data;

                Transform lCenter         = null;
                Vector3   lCenterPosition = PositionOffset;
                GetBestPosition(SearchRootIndex, rData, _Spell.Data, PositionOffset, out lCenter, out lCenterPosition);

                // Ignore any existing targets for future tests
                if (IgnorePreviousTargets && lSpellData.Targets != null && lSpellData.Targets.Count > 0)
                {
                    if (lSpellData.PreviousTargets == null)
                    {
                        lSpellData.PreviousTargets = new List <GameObject>();
                    }

                    for (int i = 0; i < lSpellData.Targets.Count; i++)
                    {
                        if (!lSpellData.PreviousTargets.Contains(lSpellData.Targets[i]))
                        {
                            lSpellData.PreviousTargets.Add(lSpellData.Targets[i]);
                        }
                    }
                }

                // Remove any existing targets
                if (Replace)
                {
                    if (lSpellData.Targets != null)
                    {
                        lSpellData.Targets.Clear();
                        lSpellData.Targets = null;
                    }
                }

                // Find new targets
                if (lCenterPosition != Vector3Ext.Null)
                {
                    Collider[]        lColliders = null;
                    List <GameObject> lTargets   = null;

                    int lCount = RaycastExt.SafeOverlapSphere(lCenterPosition, Radius, out lColliders, CollisionLayers, _Spell.Owner.transform, null, true);
                    if (lColliders != null && lCount > 0)
                    {
                        if (lTargets == null)
                        {
                            lTargets = new List <GameObject>();
                        }

                        for (int i = 0; i < lCount; i++)
                        {
                            GameObject lGameObject = lColliders[i].gameObject;
                            if (lGameObject == _Spell.Owner)
                            {
                                continue;
                            }
                            if (RequireRigidbody && lGameObject.GetComponent <Rigidbody>() == null)
                            {
                                continue;
                            }
                            if (RequireActorCore && lGameObject.GetComponent <ActorCore>() == null)
                            {
                                continue;
                            }
                            if (RequireCombatant && lGameObject.GetComponent <ICombatant>() == null)
                            {
                                continue;
                            }
                            if (lSpellData.PreviousTargets != null && lSpellData.PreviousTargets.Contains(lGameObject))
                            {
                                continue;
                            }

                            if (_Tags != null && _Tags.Length > 0)
                            {
                                IAttributeSource lAttributeSource = lGameObject.GetComponent <IAttributeSource>();
                                if (lAttributeSource == null || !lAttributeSource.AttributesExist(_Tags))
                                {
                                    continue;
                                }
                            }

                            if (!lTargets.Contains(lGameObject))
                            {
                                lTargets.Add(lGameObject);
                            }
                        }

                        // Sort the list based on distance
                        if (lTargets.Count > 1)
                        {
                            lTargets = lTargets.OrderBy(x => Vector3.Distance(lCenterPosition, x.transform.position)).ToList <GameObject>();
                        }
                    }

                    // Choose what we want
                    if (lTargets != null && lTargets.Count > 0)
                    {
                        if (lSpellData.Targets == null)
                        {
                            lSpellData.Targets = new List <GameObject>();
                        }

                        // Any or nearest
                        if (SearchTypeIndex == 0 || SearchTypeIndex == 1)
                        {
                            for (int i = 0; i < lTargets.Count; i++)
                            {
                                if (!lSpellData.Targets.Contains(lTargets[i]))
                                {
                                    lSpellData.Targets.Add(lTargets[i]);
                                }
                                if (MaxTargets > 0 && lSpellData.Targets.Count >= MaxTargets)
                                {
                                    break;
                                }
                            }
                        }
                        // Furthest
                        else if (SearchTypeIndex == 2)
                        {
                            for (int i = lTargets.Count - 1; i >= 0; i--)
                            {
                                if (!lSpellData.Targets.Contains(lTargets[i]))
                                {
                                    lSpellData.Targets.Insert(0, lTargets[i]);
                                }
                                if (MaxTargets > 0 && lSpellData.Targets.Count >= MaxTargets)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                if (lSpellData.Targets != null && lSpellData.Targets.Count > 0)
                {
                    if (!UseBatches)
                    {
                        OnSuccess();
                        return;
                    }
                }
            }

            // Immediately deactivate
            if (!UseBatches)
            {
                OnFailure();
            }
        }
Пример #30
0
        /// <summary>
        /// Gets the focus position given the new/predicted camera rotation
        /// </summary>
        /// <param name="rCameraRotation"></param>
        /// <returns></returns>
        public virtual Vector3 GetFocusPosition(Quaternion rCameraRotation)
        {
            Transform lAnchorTransform = Anchor;

            Vector3 lAnchorOffset     = AnchorOffset;
            Vector3 lAnchorPosition   = AnchorPosition;
            Vector3 lNewFocusPosition = (rCameraRotation.Right() * _Offset.x) + (rCameraRotation.Forward() * _Offset.z);

            if (lAnchorTransform != null)
            {
                // We need to see if the AnchorPosition is reachable from the Anchor
                if (RigController.IsCollisionsEnabled && _IsCollisionEnabled && lAnchorOffset.sqrMagnitude > 0f)
                {
                    Vector3 lToAnchor        = lAnchorPosition - lAnchorTransform.position;
                    Vector3 lAnchorDirection = lToAnchor.normalized;
                    float   lAnchorDistance  = lToAnchor.magnitude;

                    RaycastHit lFocusHit;
                    float      lDistanceOffset = lAnchorDistance * 0.5f;
                    if (RaycastExt.SafeSphereCast(lAnchorTransform.position + (lAnchorDirection * lDistanceOffset), lAnchorDirection, RigController.CollisionRadius * 1.1f, out lFocusHit, lAnchorDistance - lDistanceOffset, RigController.CollisionLayers, AnchorRoot))
                    {
                        if (lFocusHit.distance > 0f)
                        {
                            mAnchorOffsetDistance = lFocusHit.distance + lDistanceOffset;
                        }
                    }

                    lAnchorOffset     = lAnchorDirection * mAnchorOffsetDistance;
                    lNewFocusPosition = lAnchorTransform.position + lAnchorOffset + lNewFocusPosition;
                }
                else
                {
                    lNewFocusPosition = lAnchorTransform.position + ((RigController.RotateAnchorOffset ? lAnchorTransform.rotation : Quaternion.identity) * lAnchorOffset) + lNewFocusPosition;
                }

#if UNITY_EDITOR
                Vector3 lSegmentEnd = lNewFocusPosition;
#endif

                lNewFocusPosition = lNewFocusPosition + ((RigController.RotateAnchorOffset ? lAnchorTransform.up : Vector3.up) * _Offset.y);

#if UNITY_EDITOR
                if (RigController.EditorShowDebug)
                {
                    Graphics.GraphicsManager.DrawCapsule(lAnchorTransform.position, lAnchorPosition, RigController.CollisionRadius * 1.1f, Color.white);
                    Graphics.GraphicsManager.DrawCapsule(lAnchorPosition, lSegmentEnd, RigController.CollisionRadius * 1.1f, Color.gray);
                    Graphics.GraphicsManager.DrawCapsule(lSegmentEnd, lNewFocusPosition, RigController.CollisionRadius * 1.1f, Color.gray);
                }
#endif
                //float lCameraDistance = Vector3.Distance(lNewFocusPosition, RigController._Transform.position);
                //float lCameraDistancePercent = Mathf.Clamp01(MaxDistance > 0f ? lCameraDistance / MaxDistance : 1f);
                //if (lCameraDistancePercent < 1f)
                //{
                //    Vector3 lToFocus = lNewFocusPosition - lAnchorPosition;
                //    lNewFocusPosition = lAnchorPosition + (lToFocus.normalized * (lToFocus.magnitude * lCameraDistancePercent));
                //}

                // We need to see if the focus position is reachable. If there
                // is a collision, we need to pull it in.
                if (RigController.IsCollisionsEnabled && _IsCollisionEnabled && Offset.sqrMagnitude > 0f)
                {
                    Vector3 lToFocus        = lNewFocusPosition - lAnchorPosition;
                    Vector3 lFocusDirection = lToFocus.normalized;
                    float   lFocusDistance  = lToFocus.magnitude;

                    RaycastHit lFocusHit;
                    if (RaycastExt.SafeSphereCast(lAnchorPosition, lFocusDirection, RigController.CollisionRadius * 1.1f, out lFocusHit, lFocusDistance, RigController.CollisionLayers, AnchorRoot))
                    {
                        lNewFocusPosition = lAnchorPosition + (lFocusDirection * lFocusHit.distance);
                    }
                }
            }

#if UNITY_EDITOR
            if (RigController.EditorShowDebug)
            {
                Graphics.GraphicsManager.DrawPoint(lNewFocusPosition, Color.green);
            }
#endif

            return(lNewFocusPosition);
        }