Exemple #1
0
        /// <summary>
        /// The object has taken been damaged.
        /// </summary>
        /// <param name="amount">The amount of damage taken.</param>
        /// <param name="position">The position of the damage.</param>
        /// <param name="direction">The direction that the object took damage from.</param>
        /// <param name="forceMagnitude">The magnitude of the force that is applied to the object.</param>
        /// <param name="frames">The number of frames to add the force to.</param>
        /// <param name="radius">The radius of the explosive damage. If 0 then a non-explosive force will be used.</param>
        /// <param name="attacker">The GameObject that did the damage.</param>
        /// <param name="attackerObject">The object that did the damage.</param>
        /// <param name="hitCollider">The Collider that was hit.</param>
        public virtual void OnDamage(float amount, Vector3 position, Vector3 direction, float forceMagnitude, int frames, float radius, GameObject attacker, object attackerObject, Collider hitCollider)
        {
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
            if (m_NetworkInfo != null && m_NetworkInfo.IsLocalPlayer())
            {
                m_NetworkHealthMonitor.OnDamage(amount, position, direction, forceMagnitude, frames, radius, attacker, hitCollider);
            }
#endif

            // Add a multiplier if a particular collider was hit. Do not apply a multiplier if the damage is applied through a radius because multiple
            // collider are hit.
            if (radius == 0 && direction != Vector3.zero && hitCollider != null)
            {
                Hitbox hitbox;
                if (m_ColliderHitboxMap != null && m_ColliderHitboxMap.Count > 0)
                {
                    if (m_ColliderHitboxMap.TryGetValue(hitCollider, out hitbox))
                    {
                        amount *= hitbox.DamageMultiplier;
                    }
                    else
                    {
                        // The main collider may be overlapping child hitbox colliders. Perform one more raycast to ensure a hitbox collider shouldn't be hit.
                        float distance = 0.2f;
                        if (hitCollider is CapsuleCollider)
                        {
                            distance = (hitCollider as CapsuleCollider).radius;
                        }
                        else if (hitCollider is SphereCollider)
                        {
                            distance = (hitCollider as SphereCollider).radius;
                        }

                        // The hitbox collider may be underneath the base collider. Fire a raycast to detemine if there are any colliders underneath the hit collider
                        // that should apply a multiplier.
                        var hitCount = Physics.RaycastNonAlloc(position, direction, m_RaycastHits, distance,
                                                               ~(1 << LayerManager.IgnoreRaycast | 1 << LayerManager.Overlay | 1 << LayerManager.VisualEffect), QueryTriggerInteraction.Ignore);
                        for (int i = 0; i < hitCount; ++i)
                        {
                            var closestRaycastHit = QuickSelect.SmallestK(m_RaycastHits, hitCount, i, m_RaycastHitComparer);
                            if (closestRaycastHit.collider == hitCollider)
                            {
                                continue;
                            }
                            // A new collider has been found - stop iterating if the hitbox map exists and use the hitbox multiplier.
                            if (m_ColliderHitboxMap.TryGetValue(closestRaycastHit.collider, out hitbox))
                            {
                                amount     *= hitbox.DamageMultiplier;
                                hitCollider = hitbox.Collider;
                                break;
                            }
                        }
                    }
                }
            }

            // Apply the damage to the shield first because the shield can regenrate.
            if (m_ShieldAttribute != null && m_ShieldAttribute.Value > m_ShieldAttribute.MinValue)
            {
                var shieldAmount = Mathf.Min(amount, m_ShieldAttribute.Value - m_ShieldAttribute.MinValue);
                amount -= shieldAmount;
                m_ShieldAttribute.Value -= shieldAmount;
            }

            // Decrement the health by remaining amount after the shield has taken damage.
            if (m_HealthAttribute != null && m_HealthAttribute.Value > m_HealthAttribute.MinValue)
            {
                m_HealthAttribute.Value -= Mathf.Min(amount, m_HealthAttribute.Value - m_HealthAttribute.MinValue);
            }

            var force = direction * forceMagnitude;
            if (forceMagnitude > 0)
            {
                // Apply a force to the object.
                if (m_ForceObject != null)
                {
                    m_ForceObject.AddForce(force, frames);
                }
                else
                {
                    // Apply a force to the rigidbody if the object isn't a character.
                    if (m_Rigidbody != null && !m_Rigidbody.isKinematic)
                    {
                        if (radius == 0)
                        {
                            m_Rigidbody.AddForceAtPosition(force * MathUtility.RigidbodyForceMultiplier, position);
                        }
                        else
                        {
                            m_Rigidbody.AddExplosionForce(force.magnitude * MathUtility.RigidbodyForceMultiplier, position, radius);
                        }
                    }
                }
            }

            // Let other interested objects know that the object took damage.
            EventHandler.ExecuteEvent <float, Vector3, Vector3, GameObject, Collider>(m_GameObject, "OnHealthDamage", amount, position, force, attacker, hitCollider);
            if (m_OnDamageEvent != null)
            {
                m_OnDamageEvent.Invoke(amount, position, force, attacker);
            }

            // The object is dead when there is no more health or shield.
            if (!IsAlive())
            {
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
                if (m_NetworkInfo == null || m_NetworkInfo.IsLocalPlayer())
                {
#endif
                Die(position, force, attacker);
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
            }
#endif
            }
            else
            {
                // Play any take damage audio if the object did not die. If the object died then the death audio will play.
                m_TakeDamageAudioClipSet.PlayAudioClip(m_GameObject);
            }
        }
Exemple #2
0
        /// <summary>
        /// Determine any targets that are within the crosshairs raycast.
        /// </summary>
        private void Update()
        {
            var       crosshairsColor = m_DefaultColor;
            var       crosshairsRay   = m_Camera.ScreenPointToRay(m_CenterRectTransform.position);
            Transform target          = null;

            // Prevent the ray between the character and the camera from causing a false collision.
            if (!m_CharacterLocomotion.FirstPersonPerspective)
            {
                var direction = m_CharacterTransform.InverseTransformPoint(crosshairsRay.origin);
                direction.y          = 0;
                crosshairsRay.origin = crosshairsRay.GetPoint(direction.magnitude);
            }
            var hitCount = Physics.SphereCastNonAlloc(crosshairsRay, m_CollisionRadius, m_RaycastHits, m_CameraController.LookDirectionDistance, m_CharacterLayerManager.IgnoreInvisibleLayers, QueryTriggerInteraction.Ignore);

#if UNITY_EDITOR
            if (hitCount == m_MaxCollisionCount)
            {
                Debug.LogWarning("Warning: The crosshairs detected the maximum number of objects. Consider increasing the Max Collision Count on the Crosshairs Monitor.");
            }
#endif
            if (hitCount > 0)
            {
                for (int i = 0; i < hitCount; ++i)
                {
                    var closestRaycastHit          = QuickSelect.SmallestK(m_RaycastHits, hitCount, i, m_RaycastHitComparer);
                    var closestRaycastHitTransform = closestRaycastHit.transform;
                    // The crosshairs cannot hit the character that is attached to the camera.
                    if (closestRaycastHitTransform.IsChildOf(m_CharacterTransform))
                    {
                        continue;
                    }

                    if (MathUtility.InLayerMask(closestRaycastHitTransform.gameObject.layer, m_CharacterLayerManager.EnemyLayers))
                    {
                        target          = closestRaycastHitTransform;
                        crosshairsColor = m_TargetColor;
                    }
                    break;
                }
            }
            if (m_AimAssist != null)
            {
                m_AimAssist.SetTarget(target);
            }

            if (m_EquippedItem != null)
            {
                m_CurrentCrosshairsSpread = Mathf.SmoothDamp(m_CurrentCrosshairsSpread, m_TargetCrosshairsSpread, ref m_CrosshairsSpreadVelocity,
                                                             m_EquippedItem.QuadrantSpreadDamping);
            }
            m_CenterCrosshairsImage.color = crosshairsColor;
            if (m_LeftCrosshairsImage != null && m_LeftCrosshairsImage.enabled)
            {
                m_LeftCrosshairsImage.color = crosshairsColor;
                PositionSprite(m_LeftRectTransform, -m_EquippedItem.QuadrantOffset - m_CurrentCrosshairsSpread, 0);
            }
            if (m_TopCrosshairsImage != null && m_TopCrosshairsImage.enabled)
            {
                m_TopCrosshairsImage.color = crosshairsColor;
                PositionSprite(m_TopRectTransform, 0, m_EquippedItem.QuadrantOffset + m_CurrentCrosshairsSpread);
            }
            if (m_RightCrosshairsImage != null && m_RightCrosshairsImage.enabled)
            {
                m_RightCrosshairsImage.color = crosshairsColor;
                PositionSprite(m_RightRectTransform, m_EquippedItem.QuadrantOffset + m_CurrentCrosshairsSpread, 0);
            }
            if (m_BottomCrosshairsImage != null && m_BottomCrosshairsImage.enabled)
            {
                m_BottomCrosshairsImage.color = crosshairsColor;
                PositionSprite(m_BottomRectTransform, 0, -m_EquippedItem.QuadrantOffset - m_CurrentCrosshairsSpread);
            }

            var enableImage = !m_Aiming || (m_EquippedItem != null && m_EquippedItem.ShowCrosshairsOnAim);
            if (enableImage != m_EnableImage)
            {
                m_EnableImage = enableImage;
                EnableCrosshairsImage(enableImage);
            }
        }
        /// <summary>
        /// Update the rotation forces.
        /// </summary>
        public override void UpdateRotation()
        {
            var updateNormalRotation = m_Stopping;
            var targetNormal         = m_Stopping ? (m_StopGravityDirection.sqrMagnitude > 0 ? -m_StopGravityDirection : -m_CharacterLocomotion.GravityDirection) : m_CharacterLocomotion.Up;

            if (!m_Stopping)
            {
                // If the depth offset isn't zero then use two raycasts to determine the ground normal. This will allow a long character (such as a horse) to correctly
                // adjust to a slope.
                if (m_DepthOffset != 0)
                {
                    var        frontPoint = m_Transform.position;
                    bool       frontHit;
                    RaycastHit raycastHit;
                    if ((frontHit = Physics.Raycast(m_Transform.TransformPoint(0, m_CharacterLocomotion.Radius, m_DepthOffset * Mathf.Sign(m_CharacterLocomotion.InputVector.y)),
                                                    -m_CharacterLocomotion.Up, out raycastHit, m_Distance + m_CharacterLocomotion.Radius, m_CharacterLayerManager.SolidObjectLayers, QueryTriggerInteraction.Ignore)))
                    {
                        frontPoint   = raycastHit.point;
                        targetNormal = raycastHit.normal;
                    }

                    if (Physics.Raycast(m_Transform.TransformPoint(0, m_CharacterLocomotion.Radius, m_DepthOffset * -Mathf.Sign(m_CharacterLocomotion.InputVector.y)),
                                        -m_CharacterLocomotion.Up, out raycastHit, m_Distance + m_CharacterLocomotion.Radius, m_CharacterLayerManager.SolidObjectLayers, QueryTriggerInteraction.Ignore))
                    {
                        if (frontHit)
                        {
                            if (m_NormalizeDirection)
                            {
                                var backPoint = raycastHit.point;
                                var direction = (frontPoint - backPoint).normalized;
                                targetNormal = Vector3.Cross(direction, Vector3.Cross(m_CharacterLocomotion.Up, direction)).normalized;
                            }
                            else
                            {
                                targetNormal = (targetNormal + raycastHit.normal).normalized;
                            }
                        }
                        else
                        {
                            targetNormal = raycastHit.normal;
                        }
                    }

                    m_CharacterLocomotion.GravityDirection = -targetNormal;
                    updateNormalRotation = true;
                }
                else
                {
                    var hitCount = m_CharacterLocomotion.Cast(-m_CharacterLocomotion.Up * m_Distance,
                                                              m_CharacterLocomotion.PlatformMovement + m_CharacterLocomotion.Up * m_CharacterLocomotion.ColliderSpacing, ref m_CombinedRaycastHits, ref m_ColliderIndexMap);

                    // The character hit the ground if any hit points are below the collider.
                    for (int i = 0; i < hitCount; ++i)
                    {
                        var closestRaycastHit = QuickSelect.SmallestK(m_CombinedRaycastHits, hitCount, i, m_RaycastHitComparer);

                        // The hit point has to be under the collider for the character to align to it.
                        var activeCollider = m_CharacterLocomotion.ColliderCount > 1 ? m_CharacterLocomotion.Colliders[m_ColliderIndexMap[closestRaycastHit]] : m_CharacterLocomotion.Colliders[0];
                        if (!MathUtility.IsUnderCollider(m_Transform, activeCollider, closestRaycastHit.point))
                        {
                            continue;
                        }

                        targetNormal         = m_CharacterLocomotion.GravityDirection = -closestRaycastHit.normal;
                        updateNormalRotation = true;
                        break;
                    }
                }
            }

            // The rotation is affected by aligning to the ground or having a different up rotation from gravity.
            if (updateNormalRotation)
            {
                Rotate(targetNormal);
            }
        }
Exemple #4
0
        /// <summary>
        /// Determine any targets that are within the crosshairs raycast.
        /// </summary>
        private void Update()
        {
            var       crosshairsColor = m_DefaultColor;
            var       crosshairsRay   = m_Camera.ScreenPointToRay(m_CenterRectTransform.position);
            Transform target          = null;

            // Prevent the ray between the character and the camera from causing a false collision.
            if (!m_CharacterLocomotion.FirstPersonPerspective)
            {
                var direction = m_CharacterTransform.InverseTransformPoint(crosshairsRay.origin);
                direction.y          = 0;
                crosshairsRay.origin = crosshairsRay.GetPoint(direction.magnitude);
            }
#if UNITY_EDITOR
            // Visualize the direction of the look direction.
            if (m_DebugDrawLookRay)
            {
                Debug.DrawRay(crosshairsRay.origin, crosshairsRay.direction * m_CameraController.LookDirectionDistance, Color.white);
            }
#endif
            var hitCount = Physics.SphereCastNonAlloc(crosshairsRay, m_CollisionRadius, m_RaycastHits, m_CameraController.LookDirectionDistance, m_CharacterLayerManager.IgnoreInvisibleLayers, m_TriggerInteraction);
#if UNITY_EDITOR
            if (hitCount == m_MaxCollisionCount)
            {
                Debug.LogWarning("Warning: The crosshairs detected the maximum number of objects. Consider increasing the Max Collision Count on the Crosshairs Monitor.");
            }
#endif
            if (hitCount > 0)
            {
                for (int i = 0; i < hitCount; ++i)
                {
                    var closestRaycastHit          = QuickSelect.SmallestK(m_RaycastHits, hitCount, i, m_RaycastHitComparer);
                    var closestRaycastHitTransform = closestRaycastHit.transform;
                    // The crosshairs cannot hit the character that is attached to the camera.
                    if (closestRaycastHitTransform.IsChildOf(m_CharacterTransform))
                    {
                        continue;
                    }

                    if (MathUtility.InLayerMask(closestRaycastHitTransform.gameObject.layer, m_CharacterLayerManager.EnemyLayers))
                    {
                        target          = closestRaycastHitTransform;
                        crosshairsColor = m_TargetColor;
                    }
                    break;
                }
            }

            if (m_AutoAssignAimAssistTarget && m_AimAssist != null)
            {
                m_AimAssist.SetTarget(target);
            }

            // The crosshairs can move with the cursor position.
            if (m_MoveWithCursor && Cursor.visible)
            {
                m_RectTransform.position = new Vector3(m_PlayerInput.GetMousePosition().x, m_PlayerInput.GetMousePosition().y, 0);
            }

            // The spread of the crosshairs can change based on how quickly the character is moving.
            if (m_MovementSpread > 0)
            {
                var velocity = Mathf.Clamp01(m_CharacterLocomotion.LocalLocomotionVelocity.sqrMagnitude / m_MaxSpreadVelocitySqrMagnitude);
                m_SmoothedMovementVelocity = Mathf.SmoothStep(m_SmoothedMovementVelocity, velocity, m_MovementSpreadSpeed * Time.deltaTime);
            }
            if (m_EquippedItem != null)
            {
                var movementSpread = (((m_MovementSpread / 360) + m_SmoothedMovementVelocity) / 2) * m_EquippedItem.MaxQuadrantSpread;
                m_CurrentCrosshairsSpread = Mathf.SmoothDamp(m_CurrentCrosshairsSpread,
                                                             Mathf.Clamp(m_TargetCrosshairsSpread + movementSpread, 0, m_EquippedItem.MaxQuadrantSpread),
                                                             ref m_CrosshairsSpreadVelocity, m_EquippedItem.QuadrantSpreadDamping);
            }
            m_CenterCrosshairsImage.color = crosshairsColor;
            if (m_LeftCrosshairsImage != null && m_LeftCrosshairsImage.enabled)
            {
                m_LeftCrosshairsImage.color = crosshairsColor;
                PositionSprite(m_LeftRectTransform, -m_EquippedItem.QuadrantOffset - m_CurrentCrosshairsSpread, 0);
            }
            if (m_TopCrosshairsImage != null && m_TopCrosshairsImage.enabled)
            {
                m_TopCrosshairsImage.color = crosshairsColor;
                PositionSprite(m_TopRectTransform, 0, m_EquippedItem.QuadrantOffset + m_CurrentCrosshairsSpread);
            }
            if (m_RightCrosshairsImage != null && m_RightCrosshairsImage.enabled)
            {
                m_RightCrosshairsImage.color = crosshairsColor;
                PositionSprite(m_RightRectTransform, m_EquippedItem.QuadrantOffset + m_CurrentCrosshairsSpread, 0);
            }
            if (m_BottomCrosshairsImage != null && m_BottomCrosshairsImage.enabled)
            {
                m_BottomCrosshairsImage.color = crosshairsColor;
                PositionSprite(m_BottomRectTransform, 0, -m_EquippedItem.QuadrantOffset - m_CurrentCrosshairsSpread);
            }

            var enableImage = !m_Aiming || (m_EquippedItem != null && m_EquippedItem.ShowCrosshairsOnAim);
            if (enableImage != m_EnableImage)
            {
                m_EnableImage = enableImage;
                EnableCrosshairsImage(enableImage);
            }
        }