2016-05-23 4 views
0

Я пытаюсь заставить мои узлы перемещаться по экрану и бесконечно появляться на таймере. Я хотел бы также иметь сразу несколько узлов на экране. Это мой стабильный код. Я пробовал несколько разных способов с замораживанием или сбоями.Быстрое создание узлов нереста

let bunnyTexture = SKTexture(imageNamed: "oval 1.png") 
    bunny = SKSpriteNode(texture: bunnyTexture) 
    bunny.position = CGPoint(x: (size.width/3), y: 750 + bunny.frame.height) 
    self.addChild(bunny) 
    bunny.physicsBody = SKPhysicsBody(circleOfRadius: bunnyTexture.size().height/2) 
    bunny.physicsBody!.dynamic = true 
    let spawnBunny = SKAction.moveByX(0, y: -self.frame.size.height, duration: 4) 
    let despawnBunny = SKAction.removeFromParent() 
    let spawnNdespawn2 = SKAction.sequence([spawnBunny, despawnBunny]) 
    bunny.runAction(spawnNdespawn2) 

    let gobblinTexture = SKTexture(imageNamed: "oval 2.png") 
    gobblin = SKSpriteNode(texture: gobblinTexture) 
    gobblin.position = CGPoint(x: 150 + gobblin.frame.width, y: (size.height/3)) 
    self.addChild(gobblin) 
    let randomGob = arc4random() % UInt32(self.frame.size.height/2) 
    let spawnGob = SKAction.moveByX(+self.frame.size.width, y: 0, duration: 4) 
    let despawnGob = SKAction.removeFromParent() 
    let spawnNdespawn = SKAction.sequence([spawnGob, despawnGob]) 
    gobblin.runAction(spawnNdespawn) 

    let ground = SKNode() 
    ground.position = CGPointMake(0, 0) 
    ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, -50)) 
    ground.physicsBody!.dynamic = false 
    self.addChild(ground) 

ответ

0

Чтобы создать таймер цикла, вы можете использовать SKAction.waitForDuration(interval).

Увеличить SKNode с новой функцией loopAction. Это занимает SKActionNSTimeInterval и () -> Bool.

SKAction - это функция, которая будет выполняться на каждом интервале. Функция () -> Bool будет использоваться для остановки бесконечного цикла.

Просто помните, что это фиксирует как SKNode, так и SKAction. Также не освобождается, пока цикл не остановится.

Его можно создать объект с флагом (Bool), чтобы сохранить всю эту информацию и установить флаг в false, когда необходимо остановить. Я просто предпочитаю этот путь.

LoopActionManager является примером реализации loopAction. Вам нужны SKNode и SKAction. Вместо того, чтобы звонить runAction на SKNode, вы вызываете loopAction и передаете интервал и функцию, которая управляет, когда остановиться. Вы разместили бы этот код где-нибудь, у вас есть доступ к рассматриваемым узлам.

Функция для остановки также может быть реализован в виде trailing closure

Вставьте код в игровую площадку, чтобы посмотреть, как это работает.

import UIKit 
import SpriteKit 
import XCPlayground 



extension SKNode { 

    func loopAction(action:SKAction,interval:NSTimeInterval,continueLoop:() -> Bool) { 

     guard continueLoop() else { return } 

     runAction(SKAction.waitForDuration(interval)) { 

      if continueLoop() { 
       self.runAction(action) 
       self.loopAction(action, interval: interval, continueLoop: continueLoop) 
      } 
     } 
    } 
} 

// example 
class LoopActionManager { 

    let node = SKSpriteNode(color: UIColor.whiteColor(), size: CGSize(width: 20, height: 20)) 
    let action = SKAction.moveBy(CGVector(dx: 10,dy: 0), duration: 0.5) 

    func continueMoveLoop() -> Bool { 
     return (node.position.x + node.size.width) < node.scene?.size.width 
    } 

    func start() { 
     node.loopAction(action, interval: 1, continueLoop: continueMoveLoop) 
    } 

} 

let view = SKView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) 
let scene = SKScene(size: view.frame.size) 
view.presentScene(scene) 

let example = LoopActionManager() 
scene.addChild(example.node) 
example.start() 



XCPlaygroundPage.currentPage.liveView = view 

Как указано в комментариях ниже, также возможно использовать repeatAction. Вы можете продлить SKAction с помощью static func, чтобы сгенерировать repeatAction на основе действия для повторения и интервала. По сравнению с первым решением это проще и более соответствует SDK. Вы теряете обработчик завершения для каждого интервала.

import UIKit 
import SpriteKit 
import XCPlayground 


extension SKAction { 

    static func repeatAction(action:SKAction,interval:NSTimeInterval) -> SKAction { 

     // diff between interval and action.duration will be the wait time. This makes interval the interval between action starts. Max of 0 and diff to make sure it isn't smaller than 0 
     let waitAction = SKAction.waitForDuration(max(0,interval - action.duration)) 
     let sequenceAction = SKAction.sequence([waitAction,action]) 
     let repeatAction = SKAction.repeatActionForever(sequenceAction) 

     return repeatAction 

    } 
} 


let view = SKView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) 
let scene = SKScene(size: view.frame.size) 
view.presentScene(scene) 

let node = SKSpriteNode(color: UIColor.whiteColor(), size: CGSize(width: 20, height: 20)) 
let action = SKAction.moveBy(CGVector(dx: 10,dy: 0), duration: 0.5) 

scene.addChild(node) 
node.runAction(SKAction.repeatAction(action, interval: 1.0)) 



XCPlaygroundPage.currentPage.liveView = view 
+0

Почему это так сложно? Не было бы проще разместить 2 действия (ждать и двигаться) в последовательности, а затем использовать повторное действие. также, если цикл продолжения является ложным, зачем беспокоиться о ожидании – Knight0fDragon

+0

@ Knight0fDragon 'continueLoop()' может/должен оцениваться как можно дольше, до и после 'wait' оба имеют смысл. Я просто выбрал после 'wait', потому что тогда он будет оценен после запуска последнего действия. Если время отличается, это больше не будет истинным. Глядя на 'repeatAction' ... –

+0

@ Knight0fDragon Вы были правы,' repeatAction' предлагает более чистое решение. Я добавил его к моему ответу. Хороший звонок! –

Смежные вопросы