Приключение/Приключение Shared/AI/ChaseArtificialIntelligence.swift

/*
  Copyright (C) 2014 Apple Inc. All Rights Reserved.
  See LICENSE.txt for this sample’s licensing information
  
  Abstract:
  
        Defines the class for AI that chases a character
      
*/
 
import SpriteKit
 
class ChaseArtificialIntelligence: ArtificialIntelligence {
    // MARK: Types
    
    struct Constants {
        static let enemyAlertRadius = Character.Constants.collisionRadius * 500
    }
    
    // MARK: Properties
 
    // Bosses and goblins have different attack and alert radii. These both have default values
    // that match goblins, but will change if they correspond to a boss.
    var attackRadius: CGFloat = Character.Constants.collisionRadius * 2.0
    var maxAlertRadius: CGFloat = Constants.enemyAlertRadius * 2.0
    
    // MARK: Scene Processing Support
 
    override func updateWithTimeSinceLastUpdate(timeInterval: NSTimeInterval) {
        // The goal of the implementation of this method is to find the closest hero within the
        // enemy alert radius. After finding the closest hero, chase it!
        
        // No need to move / attack the character if it's dying.
        if character.dying {
            target = nil
 
            return
        }
 
        if let (closestHeroDistance, closestHero) = closestHeroWithinEnemyAlertRadius() {
            target = closestHero
 
            chaseTargetWithinDistance(closestHeroDistance, timeInterval: timeInterval)
        }
        else {
            target = nil
        }
    }
    
    // MARK: Intelligence Implementation
    
    func closestHeroWithinEnemyAlertRadius() -> (closestHeroDistance: CGFloat, closestHero: HeroCharacter)? {
        let position = character.position
 
        // Start off with the maximum distance possible away from any of the heroes.
        var closestHeroDistance = CGFloat.max
        var closestHero: HeroCharacter?
        
        for hero in character.characterScene.heroes {
            let distance = position.distanceToPoint(hero.position)
            
            if distance < Constants.enemyAlertRadius && distance < closestHeroDistance && !hero.dying {
                closestHeroDistance = distance
                closestHero = hero
            }
        }
 
        if closestHero != nil && closestHeroDistance <= maxAlertRadius {
            return (closestHeroDistance: closestHeroDistance, closestHero: closestHero!)
        }
 
        return nil
    }
    
    func chaseTargetWithinDistance(closestHeroDistance: CGFloat, timeInterval: NSTimeInterval) {
        if let heroPosition = target?.position {
            if closestHeroDistance > attackRadius {
                character.moveTowards(heroPosition, withTimeInterval: timeInterval)
            }
            else {
                character.faceTo(heroPosition)
                character.performAttackAction()
            }
        }
    }
}