예제 #1
0
 /// <summary>
 /// Fade out the decals in the decals to fade list.
 /// </summary>
 private void Update()
 {
     for (int i = m_DecalsToFade.Count - 1; i >= 0; --i)
     {
         if (m_DecalsToFade[i] == null)
         {
             m_DecalsToFade.RemoveAt(i);
             continue;
         }
         var color = m_DecalsToFade[i].material.color;
         color.a = Mathf.Lerp(color.a, 0, Time.deltaTime * m_RemoveFadeoutSpeed);
         // The decal can be removed from the list when it is completely faded out.
         if (color.a == 0)
         {
             ObjectPoolBase.Destroy(m_DecalsToFade[i].gameObject);
             m_DecalsToFade.RemoveAt(i);
         }
         else
         {
             m_DecalsToFade[i].material.color = color;
         }
     }
     // The component can be disabled when there are no decals within the list.
     if (m_DecalsToFade.Count == 0)
     {
         enabled = false;
     }
 }
예제 #2
0
 /// <summary>
 /// Decrease the alpha value of the muzzle flash to give it a fading effect. As soon as the alpha value reaches zero place the muzzle flash back in
 /// the object pool. If a light exists decrease the intensity of the light as well.
 /// </summary>
 private void Update()
 {
     if (m_Color.a > 0)
     {
         m_Color.a = Mathf.Max(m_Color.a - (m_FadeSpeed * Time.deltaTime * m_TimeScale), 0);
         if (m_Material != null)
         {
             m_Material.SetColor(m_TintColorPropertyID, m_Color);
         }
         // Keep the light intensity synchronized with the alpha channel's value.
         if (m_Light != null)
         {
             m_Light.intensity = m_StartLightIntensity * (m_Color.a / m_StartAlpha);
         }
     }
     else
     {
         if (m_Pooled)
         {
             ObjectPoolBase.Destroy(m_GameObject);
         }
         else
         {
             m_GameObject.SetActive(false);
         }
     }
 }
예제 #3
0
        /// <summary>
        /// Initialize the default values.
        /// </summary>
        protected override void Awake()
        {
            base.Awake();

            m_TrajectoryObject    = GetComponent <TrajectoryObject>();
            m_CharacterLocomotion = m_Character.GetCachedComponent <UltimateCharacterLocomotion>();
            m_CharacterTransform  = m_CharacterLocomotion.transform;
#if ULTIMATE_CHARACTER_CONTROLLER_VR
            m_VRThrowableItem = GetComponent <IVRThrowableItem>();
#endif

            if (m_ThrownObject != null && m_TrajectoryObject != null)
            {
                // The object has to be instantiated for GetComponent to work.
                var instantiatedThrownObject = ObjectPoolBase.Instantiate(m_ThrownObject);
                var trajectoryCollider       = instantiatedThrownObject.GetComponent <Collider>();
                if (trajectoryCollider != null)
                {
                    // Only sphere and capsules are supported.
                    if (trajectoryCollider is SphereCollider)
                    {
                        var trajectorySphereCollider = trajectoryCollider as SphereCollider;
                        var sphereCollider           = m_GameObject.AddComponent <SphereCollider>();
                        sphereCollider.center  = trajectorySphereCollider.center;
                        sphereCollider.radius  = trajectorySphereCollider.radius;
                        sphereCollider.enabled = false;
                    }
                    else if (trajectoryCollider is CapsuleCollider)
                    {
                        var trajectoryCapsuleCollider = trajectoryCollider as CapsuleCollider;
                        var capsuleCollider           = m_GameObject.AddComponent <CapsuleCollider>();
                        capsuleCollider.center    = trajectoryCapsuleCollider.center;
                        capsuleCollider.radius    = trajectoryCapsuleCollider.radius;
                        capsuleCollider.height    = trajectoryCapsuleCollider.height;
                        capsuleCollider.direction = trajectoryCapsuleCollider.direction;
                        capsuleCollider.enabled   = false;
                    }
                    else
                    {
                        Debug.LogError($"Error: The collider of type {trajectoryCollider.GetType()} is not supported on the trajectory object " + m_ThrownObject.name);
                    }
                    m_GameObject.layer = LayerManager.SubCharacter;
                }
                ObjectPoolBase.Destroy(instantiatedThrownObject);
            }
            m_ThrowableItemPerpectiveProperties = m_ActivePerspectiveProperties as IThrowableItemPerspectiveProperties;

            if (m_ShowTrajectoryOnAim && m_TrajectoryObject == null)
            {
                Debug.LogError($"Error: A TrajectoryObject must be added to the {m_GameObject.name} GameObject in order for the trajectory to be shown.");
            }

            if (m_ThrownObject == null)
            {
                Debug.LogError($"Error: A ThrownObject must be assigned to the {m_GameObject.name} GameObject.");
            }

            EventHandler.RegisterEvent <bool, bool>(m_Character, "OnAimAbilityStart", OnAim);
            EventHandler.RegisterEvent(m_Character, "OnAnimatorReequipThrowableItem", ReequipThrowableItem);
        }
예제 #4
0
        /// <summary>
        /// Move and rotate the object according to a parabolic trajectory.
        /// </summary>
        protected override void FixedUpdate()
        {
            base.FixedUpdate();

            if (Time.time > m_RemoveTime)   // The shell should be removed.
            {
                m_Transform.localScale = Vector3.Lerp(m_Transform.localScale, Vector3.zero, TimeUtility.FramerateDeltaTime * 0.2f);
                if (Time.time > m_RemoveTime + 0.5f)
                {
                    ObjectPoolBase.Destroy(m_GameObject);
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Destroys the object.
        /// </summary>
        /// <param name="hitPosition">The position of the destruction.</param>
        /// <param name="hitNormal">The normal direction of the destruction.</param>
        public void Destruct(Vector3 hitPosition, Vector3 hitNormal)
        {
            for (int i = 0; i < m_SpawnedObjectsOnDestruction.Length; ++i)
            {
                if (m_SpawnedObjectsOnDestruction[i] == null)
                {
                    continue;
                }

                var spawnedObject = m_SpawnedObjectsOnDestruction[i].Instantiate(hitPosition, hitNormal, m_NormalizedGravity);
                if (spawnedObject == null)
                {
                    continue;
                }
                var explosion = spawnedObject.GetCachedComponent <Explosion>();
                if (explosion != null)
                {
                    explosion.Explode(m_DamageAmount, m_ImpactForce, m_ImpactForceFrames, m_Originator);
                }
            }

            // The component and collider no longer need to be enabled after the object has been destroyed.
            if (m_Collider != null)
            {
                m_Collider.enabled = false;
            }
            if (m_ParticleSystem != null)
            {
                m_ParticleSystem.Stop();
            }
            m_Destroyed    = true;
            m_DestroyEvent = null;
            enabled        = false;

            // The destructible should be destroyed.
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
            if (NetworkObjectPool.IsNetworkActive())
            {
                // The object may have already been destroyed over the network.
                if (!m_GameObject.activeSelf)
                {
                    return;
                }
                NetworkObjectPool.Destroy(m_GameObject);
                return;
            }
#endif
            ObjectPoolBase.Destroy(m_GameObject);
        }
예제 #6
0
        /// <summary>
        /// The object has been picked up.
        /// </summary>
        /// <param name="pickedUpBy">A reference to the object that picked up the object.</param>
        protected virtual void ObjectPickedUp(GameObject pickedUpBy)
        {
            // The object may not have been instantiated within the scene.
            if (m_GameObject == null)
            {
                return;
            }

            m_IsDepleted = true;

            // Send an event notifying of the pickup.
            EventHandler.ExecuteEvent(pickedUpBy, "OnObjectPickedUp", this);

            // Optionally play a pickup sound if the object picking up the item is attached to a camera.
            // A null GameObject indicates that the clip will play from the AudioManager.
            var foundCamera = Shared.Camera.CameraUtility.FindCamera(pickedUpBy);

            if (foundCamera != null)
            {
                m_PickupAudioClipSet.PlayAtPosition(m_Transform.position);
            }

            if (ObjectPoolBase.InstantiatedWithPool(m_GameObject))
            {
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
                if (NetworkObjectPool.IsNetworkActive())
                {
                    NetworkObjectPool.Destroy(m_GameObject);
                    return;
                }
#endif
                ObjectPoolBase.Destroy(m_GameObject);
            }
            else
            {
                // Deactivate the pickup for now. It can appear again if a Respawner component is attached to the GameObject.
                m_GameObject.SetActive(false);
            }
        }
예제 #7
0
        /// <summary>
        /// Stops the cast.
        /// </summary>
        public override void Stop()
        {
            if (m_SpawnedObject != null)
            {
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
                if (NetworkObjectPool.IsNetworkActive())
                {
                    // The object may have already been destroyed over the network.
                    if (!m_GameObject.activeSelf)
                    {
                        return;
                    }
                    NetworkObjectPool.Destroy(m_SpawnedObject);
                    return;
                }
#endif
                ObjectPoolBase.Destroy(m_SpawnedObject);
                m_SpawnedObject = null;
            }

            base.Stop();
        }
예제 #8
0
        /// <summary>
        /// Instantiates a new decal.
        /// </summary>
        /// <param name="original">The original prefab to spawn an instance of.</param>
        /// <param name="hit">The RaycastHit which caused the footprint to spawn.</param>
        /// <param name="rotation">The rotation of the decal which should be spawned.</param>
        /// <param name="scale">The scale of the decal to spawn.</param>
        /// <param name="allowedEdgeOverlap">How close to the edge the footprint is allowed to spawn.</param>
        /// <returns>The spawned decal. Can be null.</returns>
        private GameObject SpawnDecal(GameObject original, RaycastHit hit, Quaternion rotation, float scale, float allowedEdgeOverlap)
        {
            // Prevent z fighting by slightly raising the decal off of the surface.
            var decal = ObjectPoolBase.Instantiate(original, hit.point + (hit.normal * 0.001f), rotation);

            // Only set the decal parent to the hit transform on uniform objects to prevent stretching.
            if (MathUtility.IsUniform(hit.transform.localScale))
            {
                decal.transform.parent = hit.transform;
            }
            if (scale != 1)
            {
                var vectorScale = Vector3.one;
                vectorScale.x = vectorScale.y = scale;
                decal.transform.localScale = vectorScale;
            }

            // Destroy the object if it cannot be cached. The object won't be able to be cached if it doesn't have all of the required components.
            if (!CacheMeshAndRenderer(decal))
            {
                ObjectPoolBase.Destroy(decal);
                return(null);
            }

            // Do a test on the decal's quad to ensure all four corners are flush against a surface. This will prevent the decal from sticking out on an edge.
            if (allowedEdgeOverlap < 0.5f)
            {
                if (!DoQuadTest(decal, allowedEdgeOverlap))
                {
                    ObjectPoolBase.Destroy(decal);
                    return(null);
                }
            }

            // The decal can be added.
            Add(decal);

            return(decal);
        }
예제 #9
0
        /// <summary>
        /// Returns the GameObject back to the ObjectPool.
        /// </summary>
        private void PoolGameObject()
        {
            // The particle may be looping so it shouldn't be stopped yet.
            if (m_ParticleSystem.IsAlive(true))
            {
                m_PoolEvent = SchedulerBase.Schedule(m_ParticleSystem.main.duration, PoolGameObject);
                return;
            }
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
            if (NetworkObjectPool.IsNetworkActive())
            {
                // The object may have already been destroyed over the network.
                if (!m_GameObject.activeSelf)
                {
                    return;
                }
                NetworkObjectPool.Destroy(m_GameObject);
                return;
            }
#endif
            m_PoolEvent = null;
            ObjectPoolBase.Destroy(m_GameObject);
        }
예제 #10
0
 /// <summary>
 /// Place itself back in the ObjectPool.
 /// </summary>
 public void DestroySelf()
 {
     ObjectPoolBase.Destroy(m_GameObject);
 }
예제 #11
0
        /// <summary>
        /// Removes any slices which have existed for more than the visible time.
        /// </summary>
        private void RemoveOldSlices()
        {
            if (m_TrailSlicesCount == 0)
            {
                if (!m_GenerateSlices)
                {
                    if (ObjectPoolBase.InstantiatedWithPool(m_GameObject))
                    {
                        ObjectPoolBase.Destroy(m_GameObject);
                    }
                    else
                    {
                        m_GameObject.SetActive(false);
                    }
                }
                return;
            }

            var startIndex = m_TrailSlicesIndex - m_TrailSlicesCount + 1;

            if (startIndex < 0)
            {
                startIndex = m_TrailSlices.Length + startIndex;
            }
            var count = m_TrailSlicesCount;

            for (int i = 0; i < count; ++i)
            {
                var trailSlice = m_TrailSlices[(startIndex + i) % m_TrailSlices.Length];
                if (trailSlice.Time + m_VisibilityTime > Time.time)
                {
                    break;
                }

                // The slice has existed for more than the visiblity time - remove it by decreasing the count.
                m_TrailSlicesCount--;
            }

            if (m_SmoothedTrailSlicesCount == 0)
            {
                return;
            }

            startIndex = m_SmoothedTrailSlicesIndex - m_SmoothedTrailSlicesCount + 1;
            if (startIndex < 0)
            {
                startIndex = m_SmoothedTrailSlices.Length + startIndex;
            }
            count = m_SmoothedTrailSlicesCount;
            for (int i = 0; i < count; ++i)
            {
                var trailSlice = m_SmoothedTrailSlices[(startIndex + i) % m_SmoothedTrailSlices.Length];
                if (trailSlice.Time + m_VisibilityTime > Time.time)
                {
                    break;
                }

                // The slice has existed for more than the visiblity time - remove it by decreasing the count.
                m_SmoothedTrailSlicesCount--;
                m_SmoothedTrailSlicesPrevCount--;
            }

            if (m_TrailSlicesCount == 0 && m_SmoothedTrailSlicesCount == 0)
            {
                m_GenerateSlices = false;
            }
        }
예제 #12
0
 /// <summary>
 /// Places the object back in the ObjectPool.
 /// </summary>
 private void DestroyObject()
 {
     ObjectPoolBase.Destroy(gameObject);
 }
예제 #13
0
 /// <summary>
 /// Remove the object.
 /// </summary>
 private void Remove()
 {
     ObjectPoolBase.Destroy(m_GameObject);
     m_RemoveEvent = null;
 }
예제 #14
0
        /// <summary>
        /// Throws the throwable object.
        /// </summary>
        public void ThrowItem()
        {
            if (m_Thrown || m_InstantiatedThrownObject == null)
            {
                return;
            }
            m_Thrown = true;

#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
            // The object has been thrown. If the ItemAction is on the server then that object should be spawned on the network.
            // Non-server actions should disable the mesh renderers so the object can take its place. The mesh renderers will be enabled again in a separate call.
            if (m_NetworkInfo != null)
            {
                EnableObjectMeshRenderers(false);
                if (!m_NetworkInfo.IsServer())
                {
                    if (m_InstantiatedThrownObject != null)
                    {
                        ObjectPoolBase.Destroy(m_InstantiatedThrownObject);
                        m_InstantiatedThrownObject = null;
                    }
                    return;
                }
            }
#endif

            m_InstantiatedThrownObject.transform.parent = null;
            // The collider was previously disabled. Enable it again when it is thrown.
            var thrownCollider = m_InstantiatedThrownObject.GetCachedComponent <Collider>();
            thrownCollider.enabled = true;

            // When the item is used the trajectory object should start moving on its own.
            // The throwable item may be on the other side of an object (especially in the case of separate arms for the first person perspective). Perform a linecast
            // to ensure the throwable item doesn't move through any objects.
            var collisionEnabled = m_CharacterLocomotion.CollisionLayerEnabled;
            m_CharacterLocomotion.EnableColliderCollisionLayer(false);
            if (!m_CharacterLocomotion.ActiveMovementType.UseIndependentLook(false) &&
                Physics.Linecast(m_CharacterLocomotion.LookSource.LookPosition(true), m_InstantiatedTrajectoryObject.transform.position, out m_RaycastHit,
                                 m_ImpactLayers, QueryTriggerInteraction.Ignore))
            {
                m_InstantiatedTrajectoryObject.transform.position = m_RaycastHit.point;
            }
            m_CharacterLocomotion.EnableColliderCollisionLayer(collisionEnabled);

            var trajectoryTransform = m_ThrowableItemPerpectiveProperties.TrajectoryLocation != null ? m_ThrowableItemPerpectiveProperties.TrajectoryLocation : m_CharacterTransform;
            var lookDirection       = m_LookSource.LookDirection(trajectoryTransform.TransformPoint(m_TrajectoryOffset), false, m_ImpactLayers, true, true);
#if ULTIMATE_CHARACTER_CONTROLLER_VR
            if (m_VRThrowableItem != null && m_CharacterLocomotion.FirstPersonPerspective)
            {
                m_Velocity = m_VRThrowableItem.GetVelocity();
            }
#endif
            var velocity = MathUtility.TransformDirection(m_Velocity, Quaternion.LookRotation(lookDirection, m_CharacterLocomotion.Up));
            // Prevent the item from being thrown behind the character. This can happen if the character is looking straight up and there is a positive
            // y velocity. Gravity will cause the thrown object to go in the opposite direction.
            if (Vector3.Dot(velocity.normalized, m_CharacterTransform.forward) < 0 && m_CharacterTransform.InverseTransformDirection(velocity.normalized).y > 0)
            {
                velocity = m_CharacterTransform.up * velocity.magnitude;
            }
            m_InstantiatedTrajectoryObject.Initialize(m_CharacterLocomotion.Alive ? (velocity + (m_CharacterTransform.forward * m_CharacterLocomotion.LocalVelocity.z)) : Vector3.zero, Vector3.zero, m_Character, false);

#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
            if (m_NetworkInfo != null)
            {
                NetworkObjectPool.NetworkSpawn(m_ThrownObject, m_InstantiatedThrownObject, true);
            }
#endif
            // Optionally change the layer after the object has been thrown. This allows the object to change from the first person Overlay layer
            // to the Default layer after it has cleared the character's hands.
            if (m_StartLayer != m_ThrownLayer)
            {
                SchedulerBase.ScheduleFixed(m_LayerChangeDelay, ChangeThrownLayer, m_InstantiatedThrownObject);
            }
        }
예제 #15
0
 /// <summary>
 /// Place the object back in the ObjectPool.
 /// </summary>
 private void Destroy()
 {
     ObjectPoolBase.Destroy(gameObject);
     m_DestructionEvent = null;
 }
예제 #16
0
        /// <summary>
        /// The object is no longer alive.
        /// </summary>
        /// <param name="position">The position of the damage.</param>
        /// <param name="force">The amount of force applied to the object while taking the damage.</param>
        /// <param name="attacker">The GameObject that killed the character.</param>
        public virtual void Die(Vector3 position, Vector3 force, GameObject attacker)
        {
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
            if (m_NetworkInfo != null && m_NetworkInfo.IsLocalPlayer())
            {
                m_NetworkHealthMonitor.Die(position, force, attacker);
            }
#endif

            // Spawn any objects on death, such as an explosion if the object is an explosive barrel.
            if (m_SpawnedObjectsOnDeath != null)
            {
                for (int i = 0; i < m_SpawnedObjectsOnDeath.Length; ++i)
                {
                    var       spawnedObject = ObjectPoolBase.Instantiate(m_SpawnedObjectsOnDeath[i], m_Transform.position, m_Transform.rotation);
                    Explosion explosion;
                    if ((explosion = spawnedObject.GetCachedComponent <Explosion>()) != null)
                    {
                        explosion.Explode(gameObject);
                    }
                    var rigidbodies = spawnedObject.GetComponentsInChildren <Rigidbody>();
                    for (int j = 0; j < rigidbodies.Length; ++j)
                    {
                        rigidbodies[j].AddForceAtPosition(force, position);
                    }
                }
            }

            // Destroy any objects on death. The objects will be placed back in the object pool if they were created within it otherwise the object will be destroyed.
            if (m_DestroyedObjectsOnDeath != null)
            {
                for (int i = 0; i < m_DestroyedObjectsOnDeath.Length; ++i)
                {
                    if (ObjectPoolBase.InstantiatedWithPool(m_DestroyedObjectsOnDeath[i]))
                    {
                        ObjectPoolBase.Destroy(m_DestroyedObjectsOnDeath[i]);
                    }
                    else
                    {
                        Object.Destroy(m_DestroyedObjectsOnDeath[i]);
                    }
                }
            }

            // Change the layer to a death layer.
            if (m_DeathLayer.value != 0)
            {
                m_AliveLayer       = m_GameObject.layer;
                m_GameObject.layer = m_DeathLayer;
            }

            // Play any take death audio. Use PlayAtPosition because the audio won't play if the GameObject is inactive.
            m_DeathAudioClipSet.PlayAtPosition(m_Transform.position);

            // Deactivate the object if requested.
            if (m_DeactivateOnDeath)
            {
                SchedulerBase.Schedule(m_DeactivateOnDeathDelay, Deactivate);
            }

            // The attributes shouldn't regenerate.
            if (m_ShieldAttribute != null)
            {
                m_ShieldAttribute.CancelAutoUpdate();
            }
            if (m_HealthAttribute != null)
            {
                m_HealthAttribute.CancelAutoUpdate();
            }

            // Notify those interested.
            EventHandler.ExecuteEvent <Vector3, Vector3, GameObject>(m_GameObject, "OnDeath", position, force, attacker);
            if (m_OnDeathEvent != null)
            {
                m_OnDeathEvent.Invoke(position, force, attacker);
            }
        }