/// <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; } }