简体   繁体   English

runBlock发生后,在SKAction.sequence中延迟下一个动作(Swift)?

[英]Delay next action in SKAction.sequence after runBlock occurs (Swift)?

The duration property for moveTo isn't followed when inside a runBlock , allowing the subsequent action in a sequence to get executed immediately when it should only get executed after duration seconds. runBlock内部时,不遵循moveToduration属性,允许序列中的后续操作立即执行,只应在duration秒后执行。

Code A (sequence properly executed): 代码A(序列正确执行):

let realDest = CGPointMake(itemA.position.x, itemA.position.y)
let moveAction = SKAction.moveTo(realDest, duration: 2.0)

itemB.runAction(SKAction.sequence([SKAction.waitForDuration(0.5), moveAction, SKAction.runBlock {
    itemB.removeFromParent()
}]))

Code B (sequence not properly executed): 代码B(序列未正确执行):

let badMoveAction = SKAction.runBlock {
    let realDest = CGPointMake(itemA.position.x, itemA.position.y)
    let moveAction = SKAction.moveTo(realDest, duration: 2.0)
    itemB.runAction(moveAction)
}

itemB.runAction(SKAction.sequence([SKAction.waitForDuration(0.5), badMoveAction, SKAction.runBlock {
    itemB.removeFromParent()
}]))

In Code A , itemB gets removed after the moveAction completes (about 2 seconds). Code A ,在moveAction完成后(约2秒)删除itemB This is the correct sequence. 这是正确的顺序。

In Code B , itemB gets removed before badMoveAction finishes, meaning itemB never moves from its original position. Code BitemBbadMoveAction完成之前被删除,这意味着itemB永远不会从其原始位置移动。 It's as if the duration property isn't honored in Code B . 就像在Code B没有遵守持续时间属性一样。

How can we move itemB as in Code B but ensure the next action in the sequence doesn't start until badMoveAction completes? 我们如何在Code B移动itemB ,但确保序列中的下一个操作在badMoveAction完成之前不会启动?

This should do what you want. 这应该做你想要的。 i just re-arranged the code a little bit. 我只是稍微重新安排了代码。

itemB.runAction(SKAction.sequence([

    // wait for half a second
    SKAction.waitForDuration(0.5),
    SKAction.runBlock({

        // after waiting half a second, get itemA's position
        let realDest = CGPointMake(itemA.position.x, itemA.position.y)
        let moveAction = SKAction.moveTo(realDest, duration: 2.0)

        // move to that position, after we get there, remove itemB from scene
        itemB.runAction(moveAction, completion: {
            itemB.removeFromParent()
        })

    })
]))

EXPLANATION: When you execute a block of code, it is executed asynchronously. 说明:执行代码块时,它是异步执行的。 This means the code will be executed on a separate queue while the rest of your code continues to execute. 这意味着代码将在单独的队列中执行,而其余代码将继续执行。

In the case of Code A this does not cause an issue because the moveTo action is run on the current queue, completed and then the runBlock is fired. 代码A的情况下,这不会导致问题,因为moveTo操作在当前队列上运行,已完成,然后触发runBlock。

In the case of Code B this creates an issue because the badMoveAction block is fired, it begins executing on a separate queue and the code continues on to the next piece which happens to be the remove action that removes itemB, while the badMoveAction was executing in the background. 代码B的情况下,这会产生一个问题,因为badMoveAction块被触发,它开始在一个单独的队列上执行,代码继续到下一个恰好是删除itemB的删除操作,而badMoveAction正在执行的背景。 If you did something else in that runBlock you will see them run simultaneously, but because you removed it, everything is removed. 如果你在runBlock中做了其他事情,你会看到它们同时运行,但是因为你删除了它,一切都被删除了。

Solution If you are saying you want to add badMoveAction to a node and have that calculate every time you could do something like this: 解决方案如果您要将badMoveAction添加到节点,并且每次执行此操作时都要计算:

let waitAction = SKAction.waitForDuration(0.5)
let removeAction = SKAction.removeFromParent()

let sequence = SKAction.sequence([waitAction, moveAction(), removeAction])

func moveAction() -> SKAction {
    let realDest = CGPointMake(itemA.position.x, itemA.position.y)
    let moveAction = SKAction.moveTo(realDest, duration:2.0)
    return moveAction()
}

*Code is just for example of what you can do to resolve this issue. *代码只是您可以采取的措施来解决此问题。

You can try an alternative solution: 您可以尝试替代解决方案:

itemB.runAction(SKAction.waitForDuration(0.5)) {
     let realDest = CGPointMake(itemA.position.x, itemA.position.y)
     let moveAction = SKAction.moveTo(realDest, duration: 2.0)
     itemB.runAction(moveAction) {
         itemB.removeFromParent()
     }
}

Trailing closure in runAction function is a completion block. runAction函数中的尾随闭包是一个完成块。

You need to change the caller of your runAction . 您需要更改runAction的调用者。 Use self to call it. 使用self来调用它。 Because you are using a runBlock and you say that the parasite runs the action inside it, there is no need to call the function on parasite . 因为您正在使用runBlock并且您说parasite在其中运行动作,所以无需在parasite上调用该函数。 So call it like that: 所以这样称呼它:

self.runAction(SKAction.sequence([SKAction.waitForDuration(0.5), moveParasite]))

According to the documentation the runBlock executes immediately, and the duration of the moveTo is not respected. 根据文档,runBlock立即执行,并且不遵守moveTo的持续时间。 The sequencing of both Code A and Code B is correct, but in the latter case it seems like it is out of sequence since the moveTo() duration is not respected. 代码A代码B的顺序是正确的,但在后一种情况下,由于不遵守moveTo()持续时间,因此它似乎不按顺序排列。

As a solution to the issue of running a block of code resulting in one or more actions, whilst respecting the duration, try this code: 作为运行代码块导致一个或多个操作的问题的解决方案,同时尊重持续时间,请尝试以下代码:

func notSoBadMoveAction() -> SKAction {
    let realDest = CGPointMake(itemA.position.x, itemA.position.y)
    let moveAction = SKAction.moveTo(realDest, duration: 2.0)
    return moveAction
}

itemB.runAction(SKAction.sequence([   
   SKAction.waitForDuration(0.5), 
   notSoBadMoveAction(), 
   SKAction.runBlock {
       itemB.removeFromParent()
   }]))

This code does use the full duration for the move, and it can replace some (but maybe not all other) other uses of runBlock. 此代码确实使用了移动的完整持续时间,它可以替换runBlock的一些(但可能不是所有其他)其他用途。 If you want to, the function can take parameters as well, and as such be made into an even more general case of generating actions. 如果您愿意,该函数也可以采用参数,因此可以生成更一般的生成动作的情况。

ADDITION: Here is an alternate version of the function displaying the possibilites to add actions, and calculate stuff within the function: 附加:这是该函数的替代版本,显示添加动作的可能性,并计算函数内的内容:

func myMoveAction(pos: CGPoint, duration : NSTimeInterval) -> SKAction {
    let realDest = CGPointMake(pos.x, pos.y)
    let moveAction = SKAction.moveTo(realDest, duration: duration/4)
    let moveAction2 = SKAction.moveTo(CGPointMake(realDest.x/2, realDest.y/2), duration: duration * 2/4)
    let moveAction3 = SKAction.moveTo(realDest, duration: duration/4)
    return SKAction.sequence([moveAction, moveAction2, moveAction3])
}

SKAction.runBlock has a duration of 0.0 . SKAction.runBlock的持续时间为0.0 Fortunately, the duration property is mutable. 幸运的是, duration属性是可变的。

badMoveAction.duration = 2.0 should delay the block long enough to run after the action within the block is finished. badMoveAction.duration = 2.0应该将块延迟足够长的时间,以便在块内的操作完成后运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM