Exemplo n.º 1
0
        /// <summary>
        /// Performs AI logic.
        /// </summary>
        private void Update()
        {
            if (_motor.IsFalling)
            {
                if (AutoStandUp)
                {
                    _motor.StandUp();
                }
                return;
            }

            CharacterMotor targetMotor = null;

            if (Target != null)
            {
                targetMotor = Target.GetComponent <CharacterMotor>();
            }

            var hasAFriendInBetween = false;
            var isFacingTheEnemy    = false;

            if (targetMotor != null)
            {
                var enemyDot = Vector3.Dot(_motor.Forward, Target.transform.position - transform.position);
                isFacingTheEnemy = enemyDot > 0;

                if (isFacingTheEnemy)
                {
                    var me = Characters.Get(gameObject);

                    foreach (var character in Characters.All)
                    {
                        if (character.Object != me.Object)
                        {
                            if (character.IsSameSide(me))
                            {
                                var dot = Vector3.Dot(_motor.Forward, character.Object.transform.position - transform.position);

                                if (dot > 0 && dot < enemyDot)
                                {
                                    hasAFriendInBetween = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            if (_attack > float.Epsilon && targetMotor != null && targetMotor.IsAlive)
            {
                if (ResetAttackCounterOnHit && _motor.IsGettingHit)
                {
                    _attack = AttackWait;
                }

                _attack -= Time.deltaTime;

                if (_attack < float.Epsilon && isFacingTheEnemy && !hasAFriendInBetween)
                {
                    _motor.InputAttack();
                    _attack = AttackWait;
                }
            }
            else
            {
                _attack = 0;
            }

            var cameraForward = Quaternion.AngleAxis(_motor.Angle, Vector3.up) * Vector3.forward;
            var current       = Vector3.Dot(cameraForward, transform.position);

            switch (State)
            {
            case AIState.Patrol:
                if (AutoNotice)
                {
                    var me = Characters.Get(gameObject);

                    foreach (var character in Characters.All)
                    {
                        if (character.Object != null && character.Object != gameObject && !character.IsSameSide(me))
                        {
                            if (Vector3.Distance(character.Object.transform.position, transform.position) < NoticeDistance)
                            {
                                Attack(character.Object);
                            }
                        }
                    }
                }

                var right = Vector3.Dot(cameraForward, _center + cameraForward * PatrolRight);
                var left  = Vector3.Dot(cameraForward, _center - cameraForward * PatrolLeft);

                if (_direction > 0)
                {
                    _motor.Direction = CharacterDirection.Right;

                    if (current < right)
                    {
                        if (!_motor.IsBlocked || !_motor.IsFacingWalkDirection)
                        {
                            _motor.InputMovement(1);
                        }
                        else
                        {
                            _motor.InputJump();
                        }
                    }
                    else
                    {
                        _direction = -1;
                    }
                }
                else
                {
                    _motor.Direction = CharacterDirection.Left;

                    if (current > left)
                    {
                        if (!_motor.IsBlocked || !_motor.IsFacingWalkDirection)
                        {
                            _motor.InputMovement(-1);
                        }
                        else
                        {
                            _motor.InputJump();
                        }
                    }
                    else
                    {
                        _direction = 1;
                    }
                }
                break;

            case AIState.Attack:
                if (Target == null)
                {
                    State = AIState.Patrol;
                }
                else
                {
                    var enemyAttackDistance = EnemyAttackDistance;
                    var minEnemyDistance    = MinEnemyDistance;

                    var radius = transform.TransformVector(Vector3.forward * _capsule.radius).magnitude;
                    enemyAttackDistance += radius;
                    minEnemyDistance    += radius;

                    var enemyCapsule = Target.GetComponent <CapsuleCollider>();
                    if (enemyCapsule != null)
                    {
                        var enemyRadius = Target.transform.TransformVector(Vector3.forward * enemyCapsule.radius).magnitude;
                        enemyAttackDistance += enemyRadius;
                        minEnemyDistance    += enemyRadius;
                    }

                    if (Vector3.Distance(transform.position, Target.transform.position) < enemyAttackDistance)
                    {
                        if (_attack < float.Epsilon)
                        {
                            _attack = AttackWait;
                        }
                    }

                    var enemy         = Vector3.Dot(cameraForward, Target.transform.position);
                    var enemyDistance = Vector2.Distance(new Vector2(transform.position.x, transform.position.z),
                                                         new Vector2(Target.transform.position.x, Target.transform.position.z));

                    if (enemyDistance > ForgetDistance)
                    {
                        Target = null;
                        State  = AIState.Patrol;
                    }
                    else
                    {
                        if (enemyDistance > radius)
                        {
                            if (current < enemy)
                            {
                                _motor.Direction = CharacterDirection.Right;
                            }
                            else
                            {
                                _motor.Direction = CharacterDirection.Left;
                            }
                        }

                        if (enemyDistance > minEnemyDistance && !hasAFriendInBetween)
                        {
                            if (current < enemy + float.Epsilon)
                            {
                                if (!_motor.IsBlocked || !_motor.IsFacingWalkDirection)
                                {
                                    _motor.InputMovement(1);
                                }
                                else if (_motor.Obstacle != Target)
                                {
                                    _motor.InputJump();
                                }
                            }
                            else if (current > enemy - float.Epsilon)
                            {
                                if (!_motor.IsBlocked || !_motor.IsFacingWalkDirection)
                                {
                                    _motor.InputMovement(-1);
                                }
                                else if (_motor.Obstacle != Target)
                                {
                                    _motor.InputJump();
                                }
                            }
                        }
                    }
                }
                break;
            }
        }