Rob提供a great Objective-C solution子类化NSOperation以实现SKAction对象的串行排队机制。我在自己的Swift项目中成功实现了这一点。
import SpriteKit
class ActionOperation : NSOperation
{
let _node: SKNode // The sprite node on which an action is to be performed
let _action: SKAction // The action to perform on the sprite node
var _finished = false // Our read-write mirror of the super's read-only finished property
var _executing = false // Our read-write mirror of the super's read-only executing property
/// Override read-only superclass property as read-write.
override var executing: Bool {
get { return _executing }
set {
willChangeValueForKey("isExecuting")
_executing = newValue
didChangeValueForKey("isExecuting")
}
}
/// Override read-only superclass property as read-write.
override var finished: Bool {
get { return _finished }
set {
willChangeValueForKey("isFinished")
_finished = newValue
didChangeValueForKey("isFinished")
}
}
/// Save off node and associated action for when it's time to run the action via start().
init(node: SKNode, action: SKAction) {
// This is equiv to ObjC:
// - (instancetype)initWithNode(SKNode *)node (SKAction *)action
// See "Exposing Swift Interfaces in Objective-C" at https://developer.apple.com/library/mac/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-XID_35
_node = node
_action = action
super.init()
}
/// Add the node action to the main operation queue.
override func start()
{
if cancelled {
finished = true
return
}
executing = true
NSOperationQueue.mainQueue().addOperationWithBlock {
self._node.runAction(self._action) {
self.executing = false
self.finished = true
}
}
}
}
要使用ActionOperation,请在客户端类中实例化NSOperationQueue类成员:
var operationQueue = NSOperationQueue()
在init方法中添加以下重要行:
operationQueue.maxConcurrentOperationCount = 1; // disallow follow actions from overlapping one another
然后当您准备好向其添加SKActions时,它们会连续运行:
operationQueue.addOperation(ActionOperation(node: mySKNode, action: mySKAction))
您是否需要在任何时候终止操作:
operationQueue.cancelAllOperations() // this renders the queue unusable; you will need to recreate it if needing to queue anymore actions
希望有所帮助!
答案 0 :(得分:11)
根据the document:
在自定义实现中,只要操作对象的执行状态发生变化,就必须为
isExecuting
键路径生成KVO通知。
在自定义实现中,只要操作对象的完成状态发生更改,就必须为
isFinished
键路径生成KVO通知。
所以我认为你必须:
override var executing:Bool {
get { return _executing }
set {
willChangeValueForKey("isExecuting")
_executing = newValue
didChangeValueForKey("isExecuting")
}
}
override var finished:Bool {
get { return _finished }
set {
willChangeValueForKey("isFinished")
_finished = newValue
didChangeValueForKey("isFinished")
}
}
答案 1 :(得分:1)
我想为几个节点分组动画。我首先尝试使用runAction(_:onChildWithName:)
对所有操作进行分组,然后使用runAction(_:onChildWithName:)
来指定哪些操作必须由节点完成。
不幸的是,存在同步问题,因为在SKAction
的情况下(SKNode,SKActions)
的持续时间是瞬时的。因此,我必须找到另一种方法,在一次操作中为多个节点分组动画。
然后,我通过添加元组数组addExecutionBlock
来修改上面的代码。
此处提供的修改代码添加了一个功能,用于初始化多个节点的操作,每个节点都有自己的操作。
对于每个节点,在其内部运行的操作使用checkCompletion()
添加到操作中的自己的块。
当一个动作完成时,执行一个调用finished
的完成块以便将它们全部加入。完成所有操作后,操作将标记为class ActionOperation : NSOperation
{
let _theActions:[(SKNode,SKAction)]
// The list of tuples :
// - SKNode The sprite node on which an action is to be performed
// - SKAction The action to perform on the sprite node
var _finished = false // Our read-write mirror of the super's read-only finished property
var _executing = false // Our read-write mirror of the super's read-only executing property
var _numberOfOperationsFinished = 0 // The number of finished operations
override var executing:Bool {
get { return _executing }
set {
willChangeValueForKey("isExecuting")
_executing = newValue
didChangeValueForKey("isExecuting")
}
}
override var finished:Bool {
get { return _finished }
set {
willChangeValueForKey("isFinished")
_finished = newValue
didChangeValueForKey("isFinished")
}
}
// Initialisation with one action for one node
//
// For backwards compatibility
//
init(node:SKNode, action:SKAction) {
_theActions = [(node,action)]
super.init()
}
init (theActions:[(SKNode,SKAction)]) {
_theActions = theActions
super.init()
}
func checkCompletion() {
_numberOfOperationsFinished++
if _numberOfOperationsFinished == _theActions.count {
self.executing = false
self.finished = true
}
}
override func start()
{
if cancelled {
finished = true
return
}
executing = true
_numberOfOperationsFinished = 0
var operation = NSBlockOperation()
for (node,action) in _theActions {
operation.addExecutionBlock({
node.runAction(action,completion:{ self.checkCompletion() })
})
}
NSOperationQueue.mainQueue().addOperation(operation)
}
}
。
return bloguers.replaceOne({id: bloguer.id}, bloguer,{upsert:true}, function (err){
console.log(err);
res.status(400).end();
});
答案 2 :(得分:0)
在初始化期间传输的SKActions
为runAction(_:onChildWithName:)
时,存在一种限制情况。
在这种情况下,此SKAction
的持续时间是即时的。
根据Apple文档:
此动作具有即时持续时间,但对儿童执行的动作可能具有自己的持续时间。