Чтобы создать таймер цикла, вы можете использовать SKAction.waitForDuration(interval)
.
Увеличить SKNode
с новой функцией loopAction
. Это занимает SKAction
NSTimeInterval
и () -> 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
Почему это так сложно? Не было бы проще разместить 2 действия (ждать и двигаться) в последовательности, а затем использовать повторное действие. также, если цикл продолжения является ложным, зачем беспокоиться о ожидании – Knight0fDragon
@ Knight0fDragon 'continueLoop()' может/должен оцениваться как можно дольше, до и после 'wait' оба имеют смысл. Я просто выбрал после 'wait', потому что тогда он будет оценен после запуска последнего действия. Если время отличается, это больше не будет истинным. Глядя на 'repeatAction' ... –
@ Knight0fDragon Вы были правы,' repeatAction' предлагает более чистое решение. Я добавил его к моему ответу. Хороший звонок! –