Example #1
0
    // ----------------------------------------------------------------
    // Name	:	Reanimate (coroutine)
    // Desc	:	Starts the reanimation procedure
    // ----------------------------------------------------------------
    protected IEnumerator Reanimate()
    {
        // Only reanimate if we are in a ragdoll state
        if (_boneControlType != AIBoneControlType.Ragdoll || _animator == null)
        {
            yield break;
        }

        // Wait for the desired number of seconds before initiating the reanimation process
        yield return(new WaitForSeconds(_reanimationWaitTime));

        // Record time at start of reanimation procedure
        _ragdollEndTime = Time.time;

        // Set rigidbodies back to being kinematic
        foreach (Rigidbody body in _bodyParts)
        {
            body.isKinematic = true;
        }

        // Put us in reanimation mode
        _boneControlType = AIBoneControlType.RagdollToAnim;

        // Record postions and rotations of all bones prior to reanimation
        foreach (BodyPartSnapshot snapShot in _bodyPartSnapShots)
        {
            snapShot.position = snapShot.transform.position;
            snapShot.rotation = snapShot.transform.rotation;
        }

        // Record the ragdolls head and feet position
        _ragdollHeadPosition = _animator.GetBoneTransform(HumanBodyBones.Head).position;
        _ragdollFeetPosition = (_animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animator.GetBoneTransform(HumanBodyBones.RightFoot).position) * 0.5f;
        _ragdollHipPosition  = _rootBone.position;

        // Enable Animator
        _animator.enabled = true;

        if (_rootBone != null)
        {
            float forwardTest;

            switch (_rootBoneAlignment)
            {
            case AIBoneAlignmentType.ZAxis:
                forwardTest = _rootBone.forward.y; break;

            case AIBoneAlignmentType.ZAxisInverted:
                forwardTest = -_rootBone.forward.y; break;

            case AIBoneAlignmentType.YAxis:
                forwardTest = _rootBone.up.y; break;

            case AIBoneAlignmentType.YAxisInverted:
                forwardTest = -_rootBone.up.y; break;

            case AIBoneAlignmentType.XAxis:
                forwardTest = _rootBone.right.y; break;

            case AIBoneAlignmentType.XAxisInverted:
                forwardTest = -_rootBone.right.y; break;

            default:
                forwardTest = _rootBone.forward.y; break;
            }

            // Set the trigger in the animator
            if (forwardTest >= 0)
            {
                _animator.SetTrigger(_reanimateFromBackHash);
            }
            else
            {
                _animator.SetTrigger(_reanimateFromFrontHash);
            }
        }
    }
Example #2
0
    // ---------------------------------------------------------------
    // Name	:	LateUpdate
    // Desc	:	Called by Unity at the end of every frame update. Used
    //			here to perform reanimation.
    // ---------------------------------------------------------------
    protected virtual void LateUpdate()
    {
        if (_boneControlType == AIBoneControlType.RagdollToAnim)
        {
            if (Time.time <= _ragdollEndTime + _mecanimTransitionTime)
            {
                Vector3 animatedToRagdoll = _ragdollHipPosition - _rootBone.position;
                Vector3 newRootPosition   = transform.position + animatedToRagdoll;

                RaycastHit[] hits = Physics.RaycastAll(newRootPosition + (Vector3.up * 0.25f), Vector3.down, float.MaxValue, _geometryLayers);
                newRootPosition.y = float.MinValue;
                foreach (RaycastHit hit in hits)
                {
                    if (!hit.transform.IsChildOf(transform))
                    {
                        newRootPosition.y = Mathf.Max(hit.point.y, newRootPosition.y);
                    }
                }

                NavMeshHit navMeshHit;
                Vector3    baseOffset = Vector3.zero;
                if (_navAgent)
                {
                    baseOffset.y = _navAgent.baseOffset;
                }
                if (NavMesh.SamplePosition(newRootPosition, out navMeshHit, 25.0f, NavMesh.AllAreas))
                {
                    transform.position = navMeshHit.position + baseOffset;
                }
                else
                {
                    transform.position = newRootPosition + baseOffset;
                }


                Vector3 ragdollDirection = _ragdollHeadPosition - _ragdollFeetPosition;
                ragdollDirection.y = 0.0f;

                Vector3 meanFeetPosition  = 0.5f * (_animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animator.GetBoneTransform(HumanBodyBones.RightFoot).position);
                Vector3 animatedDirection = _animator.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition;
                animatedDirection.y = 0.0f;

                //Try to match the rotations. Note that we can only rotate around Y axis, as the animated characted must stay upright,
                //hence setting the y components of the vectors to zero.
                transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdollDirection.normalized);
            }

            // Calculate Interpolation value
            float blendAmount = Mathf.Clamp01((Time.time - _ragdollEndTime - _mecanimTransitionTime) / _reanimationBlendTime);

            // Calculate blended bone positions by interplating between ragdoll bone snapshots and animated bone positions
            foreach (BodyPartSnapshot snapshot in _bodyPartSnapShots)
            {
                if (snapshot.transform == _rootBone)
                {
                    snapshot.transform.position = Vector3.Lerp(snapshot.position, snapshot.transform.position, blendAmount);
                }

                snapshot.transform.rotation = Quaternion.Slerp(snapshot.rotation, snapshot.transform.rotation, blendAmount);
            }


            // Conditional to exit reanimation mode
            if (blendAmount == 1.0f)
            {
                _boneControlType = AIBoneControlType.Animated;
                if (_navAgent)
                {
                    _navAgent.enabled = true;
                }
                if (_collider)
                {
                    _collider.enabled = true;
                }

                AIState newState = null;
                if (_states.TryGetValue(AIStateType.Alerted, out newState))
                {
                    if (_currentState != null)
                    {
                        _currentState.OnExitState();
                    }
                    newState.OnEnterState();
                    _currentState     = newState;
                    _currentStateType = AIStateType.Alerted;
                }
            }
        }
    }
Example #3
0
    //Viene chiamato dopo l'update e quando l'Animator è già aggiornato
    protected virtual void LateUpdate()
    {
        if (_boneControlType == AIBoneControlType.RagdollToAnim)
        {
            if (Time.time <= _ragdollEndTime + _mecanimTransitionTime)
            {
                Vector3 animatedToRagdoll = _ragdollHipPosition - _rootBone.position;
                Vector3 newRootPosition   = transform.position + animatedToRagdoll;

                RaycastHit[] hits = Physics.RaycastAll(newRootPosition + (Vector3.up * 0.25f), Vector3.down, float.MaxValue, _geometryLayers);
                newRootPosition.y = float.MinValue;
                foreach (RaycastHit hit in hits)
                {
                    if (!hit.transform.IsChildOf(transform))
                    {
                        newRootPosition.y = Mathf.Max(hit.point.y, newRootPosition.y);
                    }
                }
                NavMeshHit navMeshHit;
                Vector3    baseOffset = Vector3.zero;

                if (_navAgent)
                {
                    baseOffset.y = _navAgent.baseOffset;
                }

                if (NavMesh.SamplePosition(newRootPosition, out navMeshHit, 25.0f, NavMesh.AllAreas))
                {
                    transform.position = navMeshHit.position + baseOffset;
                }
                else
                {
                    transform.position = newRootPosition + baseOffset;
                }

                Vector3 ragdollDirection = _ragdollHeadPosition - _ragdollFeetPosition;
                ragdollDirection.y = 0.0f;

                Vector3 meanFeetPosition  = 0.5f * (_animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animator.GetBoneTransform(HumanBodyBones.RightFoot).position);
                Vector3 animatedDirection = _animator.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition;
                animatedDirection.y = 0.0f;

                // Dato che il modello deve sempre rimanere in verticale
                // Setta l'asse Y dei vectors a 0 cercando di matchare le rotazioni
                transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdollDirection.normalized);
            }

            //Calcolo valore Interpolazione
            float blendAmount = Mathf.Clamp01((Time.time - _ragdollEndTime - _mecanimTransitionTime) / _reanimationBlendTime);


            foreach (BodyPartSnapshot snapshot in _bodyPartSnapShots)
            {
                if (snapshot.transform == _rootBone)
                {
                    snapshot.transform.position = Vector3.Lerp(snapshot.position, snapshot.transform.position, blendAmount);
                }
                snapshot.transform.rotation = Quaternion.Slerp(snapshot.rotation, snapshot.transform.rotation, blendAmount);
            }

            // Per uscire dalla modalità di rianimazione
            if (blendAmount == 1.0f)
            {
                _boneControlType = AIBoneControlType.Animated;
                if (_navAgent)
                {
                    _navAgent.enabled = true;
                }
                if (_collider)
                {
                    _collider.enabled = true;
                }

                AIState newState = null;
                if (_states.TryGetValue(AIStateType.Alerted, out newState))
                {
                    if (_currentState != null)
                    {
                        _currentState.OnExitState();
                    }

                    newState.OnEnterState();
                    _currentState     = newState;
                    _currentStateType = AIStateType.Alerted;
                }
            }
        }
    }
Example #4
0
    // -------------------------------------------------------------------
    // Name	:	TakeDamage
    // Desc	:	Processes the zombie's reaction to being dealt damage
    // --------------------------------------------------------------------
    public override void TakeDamage(Vector3 position, Vector3 force, int damage, Rigidbody bodyPart, CharacterManager characterManager, int hitDirection = 0)
    {
        if (GameSceneManager.instance != null && GameSceneManager.instance.bloodParticles != null)
        {
            ParticleSystem sys = GameSceneManager.instance.bloodParticles;

            if (sys)
            {
                sys.transform.position = position;
                var settings = sys.main;
                settings.simulationSpace = ParticleSystemSimulationSpace.World;
                sys.Emit(60);
            }
        }

        float hitStrength = force.magnitude;

        if (_boneControlType == AIBoneControlType.Ragdoll)
        {
            if (bodyPart != null)
            {
                if (hitStrength > 1.0f)
                {
                    bodyPart.AddForce(force, ForceMode.Impulse);
                }


                if (bodyPart.CompareTag("Head"))
                {
                    _health = Mathf.Max(_health - damage, 0);
                }
                else
                if (bodyPart.CompareTag("Upper Body"))
                {
                    _upperBodyDamage += damage;
                }
                else
                if (bodyPart.CompareTag("Lower Body"))
                {
                    _lowerBodyDamage += damage;
                }

                UpdateAnimatorDamage();

                if (_health > 0)
                {
                    if (_reanimationCoroutine != null)
                    {
                        StopCoroutine(_reanimationCoroutine);
                    }

                    _reanimationCoroutine = Reanimate();
                    StartCoroutine(_reanimationCoroutine);
                }
            }

            return;
        }

        // Get local space position of attacker
        Vector3 attackerLocPos = transform.InverseTransformPoint(characterManager.transform.position);

        bool shouldRagdoll = (hitStrength > 1.0f);

        if (bodyPart != null)
        {
            if (bodyPart.CompareTag("Head"))
            {
                _health = Mathf.Max(_health - damage, 0);
                if (health == 0)
                {
                    shouldRagdoll = true;
                }
            }
            else
            if (bodyPart.CompareTag("Upper Body"))
            {
                _upperBodyDamage += damage;
                UpdateAnimatorDamage();
            }
            else
            if (bodyPart.CompareTag("Lower Body"))
            {
                _lowerBodyDamage += damage;
                UpdateAnimatorDamage();
                shouldRagdoll = true;
            }
        }

        if (_boneControlType != AIBoneControlType.Animated || isCrawling || IsLayerActive("Cinematic") || attackerLocPos.z < 0)
        {
            shouldRagdoll = true;
        }

        if (!shouldRagdoll)
        {
            float angle = 0.0f;
            if (hitDirection == 0)
            {
                Vector3 vecToHit = (position - transform.position).normalized;
                angle = AIState.FindSignedAngle(vecToHit, transform.forward);
            }

            int hitType = 0;
            if (bodyPart.gameObject.CompareTag("Head"))
            {
                if (angle < -10 || hitDirection == -1)
                {
                    hitType = 1;
                }
                else
                if (angle > 10 || hitDirection == 1)
                {
                    hitType = 3;
                }
                else
                {
                    hitType = 2;
                }
            }
            else
            if (bodyPart.gameObject.CompareTag("Upper Body"))
            {
                if (angle < -20 || hitDirection == -1)
                {
                    hitType = 4;
                }
                else
                if (angle > 20 || hitDirection == 1)
                {
                    hitType = 6;
                }
                else
                {
                    hitType = 5;
                }
            }

            if (_animator)
            {
                _animator.SetInteger(_hitTypeHash, hitType);
                _animator.SetTrigger(_hitTriggerHash);
            }

            return;
        }
        else
        {
            if (_currentState)
            {
                _currentState.OnExitState();
                _currentState     = null;
                _currentStateType = AIStateType.None;
            }

            if (_navAgent)
            {
                _navAgent.enabled = false;
            }
            if (_animator)
            {
                _animator.enabled = false;
            }
            if (_collider)
            {
                _collider.enabled = false;
            }

            // Mute Audio While Ragdoll is happening
            if (_layeredAudioSource != null)
            {
                _layeredAudioSource.Mute(true);
            }

            inMeleeRange = false;

            foreach (Rigidbody body in _bodyParts)
            {
                if (body)
                {
                    body.isKinematic = false;
                }
            }

            if (hitStrength > 1.0f)
            {
                if (bodyPart != null)
                {
                    bodyPart.AddForce(force, ForceMode.Impulse);
                }
            }

            _boneControlType = AIBoneControlType.Ragdoll;

            if (_health > 0)
            {
                if (_reanimationCoroutine != null)
                {
                    StopCoroutine(_reanimationCoroutine);
                }

                _reanimationCoroutine = Reanimate();
                StartCoroutine(_reanimationCoroutine);
            }
        }
    }
Example #5
0
    protected virtual IEnumerator Reanimate()
    {
        if (_boneControlType != AIBoneControlType.Ragdoll || _animator == null)
        {
            yield break;
        }

        yield return(new WaitForSeconds(_reanimationWaitTime));


        _ragdollEndTime = Time.time;

        foreach (Rigidbody body in _bodyParts)
        {
            body.isKinematic = true;
        }

        _boneControlType = AIBoneControlType.RagdollToAnim;

        foreach (BodyPartSnapshot snapshot in _bodyPartSnapshots)
        {
            snapshot.position = snapshot.transform.position;
            snapshot.rotation = snapshot.transform.rotation;
        }

        // Record ragdolls head and feet position
        _ragdollHeadPosition = _animator.GetBoneTransform(HumanBodyBones.Head).position;
        _ragdollFeetPosition = (_animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animator.GetBoneTransform(HumanBodyBones.RightFoot).position) * .5f;
        _ragdollHipPosition  = _rootBone.position;

        _animator.enabled = true;

        if (_rootBone != null)
        {
            float forwardTest;
            switch (_rootBoneAlignment)
            {
            case AIBoneAlignmentType.ZAxis:
                forwardTest = _rootBone.forward.y; break;

            case AIBoneAlignmentType.ZAxisInverted:
                forwardTest = -_rootBone.forward.y; break;

            case AIBoneAlignmentType.YAxis:
                forwardTest = _rootBone.up.y; break;

            case AIBoneAlignmentType.YAxisInverted:
                forwardTest = -_rootBone.up.y; break;

            case AIBoneAlignmentType.XAxis:
                forwardTest = _rootBone.right.y; break;

            case AIBoneAlignmentType.XAxisInverted:
                forwardTest = -_rootBone.right.y; break;

            default: forwardTest = _rootBone.forward.y; break;
            }

            _animator.SetTrigger(forwardTest >= 0 ? _reanimateFromFrontHash : _reanimateFromBackHash);
        }
    }
Example #6
0
    protected IEnumerator Reanimate()
    {
        //Esegui Reanimate solo se si trova in Ragdoll State
        if (_boneControlType != AIBoneControlType.Ragdoll || _animator == null)
        {
            yield break;
        }

        // Attendi N secondi prima di eseguire il processo di rianimazione
        yield return(new WaitForSeconds(_reanimationWaitTime));

        // Salva quanto tempo passa da quando parte il processo di rianimazione
        _ragdollEndTime = Time.time;

        // Risetto i rigibodies a kinematic
        foreach (Rigidbody body in _bodyParts)
        {
            body.isKinematic = true;
        }

        // Inizia la mode reanimation
        _boneControlType = AIBoneControlType.RagdollToAnim;

        //Registra posizione e rotazione dei ragdoll bones prima che della rianimazione
        foreach (BodyPartSnapshot snapshot in _bodyPartSnapShots)
        {
            snapshot.position = snapshot.transform.position;
            snapshot.rotation = snapshot.transform.rotation;
        }

        //Registra posizione di testa e piedi del ragdoll
        _ragdollHeadPosition = _animator.GetBoneTransform(HumanBodyBones.Head).position;
        _ragdollFeetPosition = (_animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animator.GetBoneTransform(HumanBodyBones.RightFoot).position) * 0.5f;
        _ragdollHipPosition  = _rootBone.position;



        _animator.enabled = true;

        if (_rootBone != null)
        {
            float forwardTest;

            switch (_rootBoneAlignment)
            {
            case AIBoneAlignmentType.XAxis:
                forwardTest = _rootBone.right.y;
                break;

            case AIBoneAlignmentType.YAxis:
                forwardTest = _rootBone.up.y;
                break;

            case AIBoneAlignmentType.ZAxis:
                forwardTest = _rootBone.forward.y;
                break;

            case AIBoneAlignmentType.XAxisInverted:
                forwardTest = -_rootBone.right.y;
                break;

            case AIBoneAlignmentType.YAxisInverted:
                forwardTest = -_rootBone.up.y;
                break;

            case AIBoneAlignmentType.ZAxisInverted:
                forwardTest = -_rootBone.forward.y;
                break;

            default:
                forwardTest = _rootBone.forward.y;
                break;
            }

            if (forwardTest >= 0)
            {
                _animator.SetTrigger(_reanimateFromBackHash);
            }
            else
            {
                _animator.SetTrigger(_reanimateFromFrontHash);
            }
        }
    }
Example #7
0
    public override void TakeDamage(Vector3 position,
                                    Vector3 force,
                                    int damage,
                                    // The body part that got hit
                                    Rigidbody bodyPart,
                                    // To tell the damage system wchich player hit the zombie
                                    CharacterManager characterManager,
                                    int hitDirection = 0)
    {
        base.TakeDamage(position, force, damage, bodyPart, characterManager, hitDirection);

        if (GameSceneManager.instance != null && GameSceneManager.instance.bloodParticles != null)
        {
            ParticleSystem system = GameSceneManager.instance.bloodParticles;
            system.transform.position = position;
            system.simulationSpace    = ParticleSystemSimulationSpace.World;
            system.Emit(60);
        }

        float hitStrength = force.magnitude;
        float prevHealth  = _health;

        if (_boneControlType == AIBoneControlType.Ragdoll)
        {
            if (bodyPart != null)
            {
                if (Time.time > _nextRagdollSoundTime && _ragdollColletion != null && _health > 0)
                {
                    AudioClip clip = _ragdollColletion[1];
                    if (clip)
                    {
                        _nextRagdollSoundTime = Time.time + clip.length;
                        AudioManager.instance.PlayOneShotSound(_ragdollColletion.audioGroup,
                                                               clip,
                                                               position,
                                                               _ragdollColletion.volume,
                                                               _ragdollColletion.spatialBlend,
                                                               _ragdollColletion.priority);
                    }
                }

                if (hitStrength > 1)
                {
                    bodyPart.AddForce(force, ForceMode.Impulse);
                }
                if (bodyPart.CompareTag("Head"))
                {
                    _health = Mathf.Max(_health - damage, 0);
                }
                else if (bodyPart.CompareTag("Upper Body"))
                {
                    _upperBodyDamage += damage;
                }
                else if (bodyPart.CompareTag("Lower Body"))
                {
                    _lowerBodyDamage += damage;
                }

                UpdateAnimatorDamage();

                if (_health > 0)
                {
                    // Reanimate zombie
                    if (_reanimationCoroutine != null)
                    {
                        StopCoroutine(_reanimationCoroutine);
                    }

                    _reanimationCoroutine = Reanimate();
                    StartCoroutine(_reanimationCoroutine);
                }
            }
            return;
        }

        // Get local space position of attacker
        Vector3 attackerLocPos = transform.InverseTransformPoint(characterManager.transform.position);
        // Get local space position of hit
        Vector3 hitLocPos = transform.InverseTransformPoint(position);

        // We ragdoll if the hit strength is superior to 1
        bool shouldRagdoll = hitStrength > 1f;

        if (bodyPart != null)
        {
            if (bodyPart.CompareTag("Head"))
            {
                _health = Mathf.Max(_health - damage, 0);
                if (_health == 0)
                {
                    // We ragdoll if the zombie is dead: health = 0
                    shouldRagdoll = true;
                }
            }
            else if (bodyPart.CompareTag("Upper Body"))
            {
                _upperBodyDamage += damage;
                UpdateAnimatorDamage();
            }
            else if (bodyPart.CompareTag("Lower Body"))
            {
                _lowerBodyDamage += damage;
                UpdateAnimatorDamage();
                // When we do a leg shot, the zombie will always ragdoll
                shouldRagdoll = true;
            }
        }

        // We ragdoll if we are playing a cinematic (eating for example),
        // if we are getting attacked from behind,
        // if we are not in the animated state (meaning that we are trying to reanimate),
        // if we are crawling
        if (_boneControlType != AIBoneControlType.Animated || isCrawling || IsLayerActive("Cinematic") || attackerLocPos.z < 0)
        {
            shouldRagdoll = true;
        }

        if (!shouldRagdoll)
        {
            // We try to play one of hit animations
            float angle = 0f;
            if (hitDirection == 0)
            {
                Vector3 vecToHit = (position - transform.position).normalized;
                angle = AIState.FindSignedAngle(vecToHit, transform.forward);
            }
            int hitType = 0;
            if (bodyPart.CompareTag("Head"))
            {
                if (angle < -10 || hitDirection == -1)
                {
                    hitType = 1;
                }
                else if (angle > 10 || hitDirection == 1)
                {
                    hitType = 3;
                }
                else
                {
                    hitType = 2;
                }
            }
            else if (bodyPart.gameObject.CompareTag("Upper Body"))
            {
                if (angle < -20 || hitDirection == -1)
                {
                    hitType = 4;
                }
                else if (angle > 20 || hitDirection == 1)
                {
                    hitType = 6;
                }
                else
                {
                    hitType = 5;
                }
            }
            if (_animator)
            {
                _animator.SetInteger(_hitTypeHash, hitType);
                _animator.SetTrigger(_hitTriggerHash);
            }
        }
        else
        {
            // We are ragdolling

            // We exit the current state when we are ragdolling to avoid any moving or other actions.
            if (_currentState)
            {
                _currentState.OnExitState();
                _currentState     = null;
                _currentStateType = AIStateType.None;
            }

            if (_navAgent)
            {
                _navAgent.enabled = false;
            }

            if (_animator)
            {
                _animator.enabled = false;
            }

            if (_collider)
            {
                _collider.enabled = false;
            }

            // Mute audio while ragdoll is happening
            if (_layeredAudioSource != null)
            {
                _layeredAudioSource.Mute(true);
            }

            if (Time.time > _nextRagdollSoundTime && _ragdollColletion != null && prevHealth > 0)
            {
                AudioClip clip = _ragdollColletion[0];
                if (clip != null)
                {
                    _nextRagdollSoundTime = Time.time + clip.length;
                    AudioManager.instance.PlayOneShotSound(_ragdollColletion.audioGroup,
                                                           clip,
                                                           position,
                                                           _ragdollColletion.volume,
                                                           _ragdollColletion.spatialBlend,
                                                           _ragdollColletion.priority);
                }
            }

            inMeleeRange = false;

            // Transform all the rigid bodies to non kinematic so that they could start applying their physics
            foreach (Rigidbody body in _bodyParts)
            {
                if (body != null)
                {
                    body.isKinematic = false;
                }
            }

            // Add force to the part that got hit in the hit direction
            if (hitStrength > 1f)
            {
                bodyPart.AddForce(force, ForceMode.Impulse);
            }

            _boneControlType = AIBoneControlType.Ragdoll;

            if (_health > 0)
            {
                // Reanimate zombie
                if (_reanimationCoroutine != null)
                {
                    StopCoroutine(_reanimationCoroutine);
                }

                _reanimationCoroutine = Reanimate();
                StartCoroutine(_reanimationCoroutine);
            }
        }
    }
Example #8
0
    protected virtual void LateUpdate()
    {
        if (_boneControlType == AIBoneControlType.RagdollToAnim)
        {
            // The first time the late update function is gonna be called, the animator won't be playing the right animation after we set the triggers in the previous frame
            // So we wait for a period of time since the last time the zombie was ragdolled:
            if (Time.time <= _ragdollEndTime + _mecanimTransitionTime)
            {
                // The ragdoll hip may be in a different position from that understood and set by the animator.
                Vector3 animatedToRagdoll = _ragdollHipPosition - _rootBone.position;
                // Sliding our transform along the previous vector to the location of the ragdoll hip.
                // We this, we only get the right x and z position of the character.
                Vector3 newRootPosition = transform.position + animatedToRagdoll;

                RaycastHit[] hits = Physics.RaycastAll(newRootPosition, Vector3.down, float.MaxValue, _geometryLayers);
                //newRootPosition.y = float.MinValue;
                foreach (RaycastHit hit in hits)
                {
                    if (!hit.transform.IsChildOf(transform))
                    {
                        //newRootPosition.y = Mathf.Max(newRootPosition.y, hit.point.y);
                    }
                }

                NavMeshHit navMeshHit;
                Vector3    baseOffset = Vector3.zero;
                if (_navAgent)
                {
                    baseOffset.y = _navAgent.baseOffset;
                }
                if (NavMesh.SamplePosition(newRootPosition, out navMeshHit, 2f, NavMesh.AllAreas))
                {
                    transform.position = navMeshHit.position + baseOffset;
                }
                else
                {
                    transform.position = newRootPosition + baseOffset;
                }

                Vector3 ragdollDirection = _ragdollHeadPosition - _ragdollFeetPosition;
                ragdollDirection.y = 0;

                Vector3 meanFeetPosition  = .5f * (_animator.GetBoneTransform(HumanBodyBones.RightFoot).position + _animator.GetBoneTransform(HumanBodyBones.LeftFoot).position);
                Vector3 animatedDirection = _animator.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition;
                animatedDirection.y = 0f;

                transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdollDirection.normalized);
            }

            float blendAmount = Mathf.Clamp01((Time.time - _ragdollEndTime - _mecanimTransitionTime) / _reanimationBlendTime);

            // Calculate blended bone positions by interpolating between ragdoll bone snapshots and animated bone positions
            foreach (BodyPartSnapshot snapshot in _bodyPartSnapshots)
            {
                if (snapshot.transform == _rootBone)
                {
                    snapshot.transform.position = Vector3.Lerp(snapshot.position, snapshot.transform.position, blendAmount);
                }
                // All other child bones are gonna automatically move with the parent bone.
                // They are just gonna be rotated by the animator
                snapshot.transform.rotation = Quaternion.Slerp(snapshot.rotation, snapshot.transform.rotation, blendAmount);
            }

            // Conditional to exit reanimation code
            if (blendAmount >= 1)
            {
                _boneControlType = AIBoneControlType.Animated;
                if (_navAgent)
                {
                    _navAgent.enabled = true;
                }
                if (_collider)
                {
                    _collider.enabled = true;
                }

                AIState newState = null;
                if (_states.TryGetValue(AIStateType.Alerted, out newState))
                {
                    if (_currentState != null)
                    {
                        _currentState.OnExitState();
                    }

                    newState.OnEnterState();
                    _currentState     = newState;
                    _currentStateType = AIStateType.Alerted;
                }
            }
        }
    }
Example #9
0
    //called at the end of every frame
    protected virtual void LateUpdate()
    {
        if (_boneControlType == AIBoneControlType.RAGDOLLTOANIM)
        {
            //Aligning the parent obj to the zombie
            if (Time.time <= _ragdollEndTime + _mecanimTransitionTime)
            {
                Vector3 animatedToRagdoll = _ragdollHipPosition - _rootBone.position;
                Vector3 newRootPosition   = transform.position + animatedToRagdoll;

                //Vector3.up makes sure the ray isnt cast from under the floor
                RaycastHit[] hits = Physics.RaycastAll(newRootPosition + (Vector3.up * 0.25f), Vector3.down, float.MaxValue, _geometryLayers);
                newRootPosition.y = float.MinValue;
                foreach (RaycastHit hit in hits)
                {
                    //make sure the object is not attached to the zombie
                    if (!hit.transform.IsChildOf(transform))
                    {
                        //if the current y is larger that the current one we have set assign it
                        newRootPosition.y = Mathf.Max(hit.point.y, newRootPosition.y);
                    }
                }

                //make sure point is on the nav mesh, use this to pass in a position and find the closest point on the nav mesh
                NavMeshHit navMeshHit;
                Vector3    baseOffset = Vector3.zero;
                if (_navAgent)
                {
                    baseOffset.y = _navAgent.baseOffset;
                }
                if (NavMesh.SamplePosition(newRootPosition, out navMeshHit, 2.0f, NavMesh.AllAreas))
                {
                    //if it can find an area on the nav mesh
                    transform.position = navMeshHit.position + baseOffset;
                }
                else
                {
                    //else set this as our new transform
                    transform.position = newRootPosition + baseOffset;
                }

                Vector3 ragdollDirection = _ragdollHeadPosition - _ragdollFeetPosition;
                //set y to 0
                ragdollDirection.y = 0.0f;

                //mid point between feet
                Vector3 meanFeetPosition  = 0.5f * (_animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animator.GetBoneTransform(HumanBodyBones.RightFoot).position);
                Vector3 animatedDirection = _animator.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition;
                //set y to 0
                animatedDirection.y = 0;

                //try to match rotation, rotating only around Y as animated character mys stay upright
                //this is y components are set to 0 above
                transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdollDirection.normalized);
            }

            //calcutae interpolation t value
            float blendAmount = Mathf.Clamp01((Time.time - _ragdollEndTime - _mecanimTransitionTime) / _reanimationBlendTime);

            //calculate blended bone transforms by interplating between ragdoll bone snapshots and animator positions
            foreach (BodyPartSnapshot snapshot in _bodyPartSnapShots)
            {
                //hip bone from ragdoll and animated version my have transformed so it has to be moved, all other bones are childed so only rotation need to be changed
                if (snapshot.transform == _rootBone)
                {
                    snapshot.transform.position = Vector3.Lerp(snapshot.position, snapshot.transform.position, blendAmount);
                }

                snapshot.transform.rotation = Quaternion.Slerp(snapshot.rotation, snapshot.transform.rotation, blendAmount);
            }

            //hand control back to animator
            if (blendAmount == 1.0f)
            {
                _boneControlType = AIBoneControlType.ANIMATED;
                if (_navAgent)
                {
                    _navAgent.enabled = true;
                }
                if (_collider)
                {
                    _collider.enabled = true;
                }

                AIState newState = null;
                if (_states.TryGetValue(AIStateType.ALERTED, out newState))
                {
                    if (_currentState != null)
                    {
                        _currentState.OnExitState();
                    }
                    newState.OnEnterState();
                    _currentState     = newState;
                    _currentStateType = AIStateType.ALERTED;
                }
            }
        }
    }
Example #10
0
    protected IEnumerator Reanimate()
    {
        //Only reanimate in ragdoll state
        if (_boneControlType != AIBoneControlType.RAGDOLL || _animator == null)
        {
            yield break;
        }

        //wait for desired time
        yield return(new WaitForSeconds(_reanimationWaitTime));

        //record time at start of reanimation
        _ragdollEndTime = Time.time;

        //set rbs in body to kinematic so animator can take hold
        foreach (Rigidbody body in _bodyParts)
        {
            body.isKinematic = true;
        }

        //put into reanimation mode
        _boneControlType = AIBoneControlType.RAGDOLLTOANIM;

        //record pos and rot of all bones before reanimation
        foreach (BodyPartSnapshot snapShot in _bodyPartSnapShots)
        {
            snapShot.position = snapShot.transform.position;
            snapShot.rotation = snapShot.transform.rotation;
        }

        //record ragdoll head and feet position
        _ragdollHeadPosition = _animator.GetBoneTransform(HumanBodyBones.Head).position;
        _ragdollFeetPosition = (_animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animator.GetBoneTransform(HumanBodyBones.RightFoot).position) * 0.5f;
        _ragdollHipPosition  = _rootBone.position;

        //enable animator
        _animator.enabled = true;

        if (_rootBone != null)
        {
            //figure out which animation to play based on orientation
            float forwardTest;

            switch (_rootBoneAlignment)
            {
            //forward axis of model(used on models that are orientated wrong when imported)
            case AIBoneAlignmentType.ZAXIS:
                forwardTest = _rootBone.forward.y; break;

            case AIBoneAlignmentType.ZAXISINVERTED:
                forwardTest = -_rootBone.forward.y; break;

            case AIBoneAlignmentType.YAXIS:
                forwardTest = _rootBone.up.y; break;

            case AIBoneAlignmentType.YAXISINVERTED:
                forwardTest = -_rootBone.up.y; break;

            case AIBoneAlignmentType.XAXIS:
                forwardTest = _rootBone.right.y; break;

            case AIBoneAlignmentType.XAXISINVERTED:
                forwardTest = -_rootBone.right.y; break;

            default:
                forwardTest = _rootBone.forward.y; break;
            }

            if (forwardTest >= 0)
            {
                _animator.SetTrigger(_reanimateFromBackHash);
            }
            else
            {
                _animator.SetTrigger(_reanimateFromFrontHash);
            }
        }
    }
Example #11
0
    //function overview
    //Check if we have ragdolled the zombie, if not send info to animator, if ragdolled and still alive then reanimate
    public override void TakeDamage(Vector3 position, Vector3 force, int damage, Rigidbody bodyPart, CharacterManager characterManager, int hitDirection = 0)
    {
        if (GameSceneManager.instance != null && GameSceneManager.instance.bloodParticles != null)
        {
            ParticleSystem sys = GameSceneManager.instance.bloodParticles;
            sys.transform.position = position;
            var settings = sys.main;
            settings.simulationSpace = ParticleSystemSimulationSpace.World;
            sys.Emit(60);
        }

        float hitStrength = force.magnitude;

        //if ragdolled
        if (_boneControlType == AIBoneControlType.RAGDOLL)
        {
            if (bodyPart != null)
            {
                if (hitStrength > 1.0f)
                {
                    bodyPart.AddForce(force, ForceMode.Impulse);
                }

                if (bodyPart.CompareTag("Head"))
                {
                    _health = Mathf.Max(_health - damage, 0);
                }
                else
                if (bodyPart.CompareTag("Upper Body"))
                {
                    _upperBodyDamage += damage;
                }
                else
                if (bodyPart.CompareTag("Lower Body"))
                {
                    _lowerBodyDamage += damage;
                }

                UpdateAnimatorDamage();

                if (_health > 0)
                {
                    if (_reanimationCoroutine != null)
                    {
                        StopCoroutine(_reanimationCoroutine);
                    }

                    _reanimationCoroutine = Reanimate();
                    StartCoroutine(_reanimationCoroutine);
                }
            }
            //return because already in a ragdoll state
            return;
        }

        //characters position relative to the zombie
        Vector3 attackerLocalPos = transform.InverseTransformPoint(characterManager.transform.position);

        //local position of the hit point
        Vector3 hitLocPos = transform.InverseTransformPoint(position);

        bool shouldRagdoll = (hitStrength > 1.0f);

        //what happens in normal play if the zombie is hit
        if (bodyPart != null)
        {
            if (bodyPart.CompareTag("Head"))
            {
                _health = Mathf.Max(_health - damage, 0);
                if (health == 0)
                {
                    shouldRagdoll = true;
                }
            }
            else
            if (bodyPart.CompareTag("Upper Body"))
            {
                _upperBodyDamage += damage;
                UpdateAnimatorDamage();
            }
            else
            if (bodyPart.CompareTag("Lower Body"))
            {
                _lowerBodyDamage += damage;
                UpdateAnimatorDamage();
                shouldRagdoll = true;
            }
        }

        //should rag doll: if animated, if crawling, if in cinematic layer, if attack came from behind
        if (_boneControlType != AIBoneControlType.ANIMATED || isCrawling || cinematicEnabled || attackerLocalPos.z < 0)
        {
            shouldRagdoll = true;
        }

        //should NOT ragdoll: play animation instead
        if (!shouldRagdoll)
        {
            float angle = 0.0f;
            if (hitDirection == 0)
            {
                Vector3 vecToHit = (position - transform.position).normalized;
                angle = AIState.FindSignedAngle(vecToHit, transform.forward);
            }

            //decide animation to play, hit direction is used for melee weapons
            int hitType = 0;
            if (bodyPart.gameObject.CompareTag("Head"))
            {
                if (angle < -10 || hitDirection == -1)
                {
                    hitType = 1;
                }
                else
                if (angle > 10 || hitDirection == 1)
                {
                    hitType = 3;
                }
                else
                {
                    hitType = 2;
                }
            }
            else
            if (bodyPart.gameObject.CompareTag("Upper Body"))
            {
                if (angle < -20 || hitDirection == -1)
                {
                    hitType = 4;
                }
                else
                if (angle > 20 || hitDirection == 1)
                {
                    hitType = 6;
                }
                else
                {
                    hitType = 5;
                }
            }
            //put in more hit animation parameters here
            //TODO try with rb reacting to forces

            if (_animator)
            {
                _animator.SetInteger(_hitTypeHash, hitType);
                _animator.SetTrigger(_hitTriggerHash);
            }

            return;
        }
        else
        {
            //stops the machine from calling a state, shuts off AIStateMachine
            if (_currentState)
            {
                _currentState.OnExitState();
                _currentState     = null;
                _currentStateType = AIStateType.NONE;
            }

            if (_navAgent)
            {
                _navAgent.enabled = false;
            }
            if (_animator)
            {
                _animator.enabled = false;
            }
            if (_collider)
            {
                _collider.enabled = false;
            }

            inMeleeRange = false;



            foreach (Rigidbody body in _bodyParts)
            {
                if (body)
                {
                    //ragdoll body
                    body.isKinematic = false;
                }
            }

            if (hitStrength > 1.0f)
            {
                bodyPart.AddForce(force, ForceMode.Impulse);
            }

            _boneControlType = AIBoneControlType.RAGDOLL;

            if (_health > 0)
            {
                if (_reanimationCoroutine != null)
                {
                    StopCoroutine(_reanimationCoroutine);
                }

                _reanimationCoroutine = Reanimate();
                StartCoroutine(_reanimationCoroutine);
            }
        }
    }