Приключение/Приключение Shared/Sprites/Cave.swift

/*
  Copyright (C) 2014 Apple Inc. All Rights Reserved.
  See LICENSE.txt for this sample’s licensing information
  
  Abstract:
  
        Defines the class for the cave
      
*/
 
import SpriteKit
 
let caveCollisionRadius: CGFloat = 90.0
let caveCapacity = 50
let sSharedGoblinCap = 32
var sSharedGoblinAllocation = 0
var sSharedCaveBase = SKSpriteNode()
var sSharedCaveTop = SKSpriteNode()
var sSharedCaveDeathSplort = SKSpriteNode()
var sSharedCaveDeathEmitter = SKEmitterNode()
var kLoadSharedCaveAssetsOnceToken: dispatch_once_t = 0
 
class Cave: EnemyCharacter {
    // MARK: Properties
    
    var smokeEmitter: SKEmitterNode?
    var timeUntilNextGenerate: CGFloat = 5000.0
    var activeGoblins = [Goblin]()
    var inactiveGoblins = [Goblin]()
    
    // MARK: NSCopying
    
    override func copyWithZone(zone: NSZone) -> AnyObject {
        var cave = super.copyWithZone(zone) as Cave
        cave.smokeEmitter = smokeEmitter?.copy() as? SKEmitterNode
        cave.timeUntilNextGenerate = timeUntilNextGenerate
        cave.activeGoblins = [Goblin]()
        cave.inactiveGoblins = [Goblin]()
        cave.shadowBlob = shadowBlob.copy() as SKSpriteNode
        cave.shadowBlob.name = "caveShadow"
        return cave
    }
    
    // MARK: Setup
 
    override func configurePhysicsBody() {
        // Assign the physics body; unwrap the physics body to configure it.
        physicsBody = SKPhysicsBody(circleOfRadius: 90)
        physicsBody!.dynamic = false
        physicsBody!.categoryBitMask = ColliderType.Cave.rawValue
        physicsBody!.collisionBitMask = ColliderType.all
        physicsBody!.contactTestBitMask = ColliderType.Projectile.rawValue
        
        animated = false
        zPosition = -0.85
    }
 
    // MARK: Scene Processing Support
    
    override func updateWithTimeSinceLastUpdate(interval: NSTimeInterval) {
        super.updateWithTimeSinceLastUpdate(interval) // this triggers the update in the SpawnAI
 
        for goblin in activeGoblins {
            goblin.updateWithTimeSinceLastUpdate(interval)
        }
    }
    
    override func collidedWith(other: SKPhysicsBody) {
        if health > 0.0 {
            if (other.categoryBitMask & ColliderType.Projectile.rawValue) == ColliderType.Projectile.rawValue {
                let damage = 10.0
                applyCaveDamage(damage, projectile: other.node!)
            }
        }
    }
    
    func applyCaveDamage(damage: Double, projectile: SKNode) {
        let killed = super.applyDamage(damage)
        if killed {
            // give the player some points
        }
        
        // show damage
        updateSmokeForHealth()
        
        // show damage on parallax stacks
        for node in children as [SKNode] {
            node.runAction(self.dynamicType.damageAction)
        }
    }
    
    func updateSmokeForHealth() {
        if health > 75.0 || smokeEmitter != nil {
            return
        }
        
        var emitter: SKEmitterNode = sSharedCaveDeathEmitter.copy() as SKEmitterNode
        emitter.position = position
        emitter.zPosition = -0.8
        smokeEmitter = emitter
        characterScene.addNode(emitter, atWorldLayer: .AboveCharacter)
    }
    
    override func performDeath() {
        super.performDeath()
        
        let splort = sSharedCaveDeathSplort.copy() as SKSpriteNode
        splort.zPosition = -1.0
        splort.zRotation = virtualZRotation
        splort.position = position
        splort.alpha = 0.1
        splort.runAction(SKAction.fadeAlphaTo(1.0, duration: 0.5))
        
        characterScene.addNode(splort, atWorldLayer: .BelowCharacter)
        
        runAction(SKAction.sequence([
            SKAction.fadeAlphaTo(0.0, duration: 0.5),
            SKAction.removeFromParent()
            ]))
        if let smoke = smokeEmitter {
            smoke.runAction(SKAction.sequence([
                SKAction.waitForDuration(2.0),
                SKAction.runBlock {
                    smoke.particleBirthRate = 2.0
                },
                SKAction.waitForDuration(2.0),
                SKAction.runBlock {
                    smoke.particleBirthRate = 0.0
                },
                SKAction.waitForDuration(10.0),
                SKAction.fadeAlphaTo(0.0, duration: 0.5),
                SKAction.removeFromParent()
                ]))
        }
    }
    
    override func reset() {
        super.reset()
        
        animated = false
    }
 
    // MARK: Goblin Targeting
    
    func stopGoblinsFromTargettingHero(target: Character) {
        for goblin in activeGoblins {
            goblin.intelligence.target = nil
        }
    }
 
    // MARK: Spawning
    
    func generate() {
        if sSharedGoblinCap > 0 && sSharedGoblinAllocation >= sSharedGoblinCap {
            return
        }
 
        if inactiveGoblins.count > 0 {
            let goblin = inactiveGoblins.removeLast()
 
            let offset = caveCollisionRadius * 0.75
            let rot = adjustAssetOrientation(virtualZRotation)
            goblin.position = position + CGPoint(x: cos(rot)*offset, y: sin(rot)*offset)
 
            goblin.addToScene(characterScene)
 
            goblin.zPosition = -1.0
 
            goblin.fadeIn(0.5)
 
            activeGoblins.append(goblin)
 
            sSharedGoblinAllocation++
        }
    }
 
    func recycle(goblin: Goblin) {
        goblin.reset()
        if let index = find(activeGoblins, goblin) {
            activeGoblins.removeAtIndex(index)
        }
        inactiveGoblins.append(goblin)
        sSharedGoblinAllocation--
    }
    
    // MARK: Asset Pre-loading
    
    class func loadSharedAssets() {
        dispatch_once(&kLoadSharedCaveAssetsOnceToken) {
            let atlas = SKTextureAtlas(named: "Environment")
            
            let fire: SKEmitterNode = SKEmitterNode.nodeWithName("CaveFire")
            fire.zPosition = 1
            let smoke: SKEmitterNode = SKEmitterNode.nodeWithName("CaveFireSmoke")
            
            var torch = SKNode()
            torch.addChild(fire)
            torch.addChild(smoke)
            
            sSharedCaveBase = SKSpriteNode(texture: atlas.textureNamed("cave_base.png"))
            
            torch.position = CGPoint(x: 83, y: 83)
            sSharedCaveBase.addChild(torch)
            
            var torchB = torch.copy() as SKNode
            torch.position = CGPoint(x: -83, y: 83)
            sSharedCaveBase.addChild(torchB)
            
            sSharedCaveTop = SKSpriteNode(texture: atlas.textureNamed("cave_top.png"))
            
            self.damageEmitter = SKEmitterNode.nodeWithName("CaveDamage")
            sSharedCaveDeathEmitter = SKEmitterNode.nodeWithName("CaveDeathSmoke")
            
            sSharedCaveDeathSplort = SKSpriteNode(texture: atlas.textureNamed("cave_destroyed.png"))
            
            self.damageAction = SKAction.sequence([
                SKAction.colorizeWithColor(SKColor.redColor(), colorBlendFactor: 1.0, duration: 0.0),
                SKAction.waitForDuration(0.25),
                SKAction.colorizeWithColorBlendFactor(0.0, duration:0.1)])
        }
    }
}