在 OS X 上使用 NSPanGestureRecognizer 拖动 SKNode 时闪烁
Flickering while dragging SKNode using NSPanGestureRecognizer on OS X
今天我决定尝试添加到 OS X 中的一些新的闪亮(iOS 灵感)东西:手势识别器和 Sprite Kit。我已经为 SKView 设置了一个 NSPanGestureRecognizer,我正在使用它来拖动添加到场景中的节点。但是,我在快速拖动节点时看到奇怪的闪烁。
代码非常简单,在 AppDelegate 中设置所有内容,
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
// Add and scene to the view and create a root node
hostingView.presentScene(SKScene(size: CGSize(width: 1500.0, height: 1500.0)))
rootNode = SKNode()
// A a red circle
let node = SKShapeNode(circleOfRadius: 50.0)
node.lineWidth = 5.0
node.strokeColor = NSColor.whiteColor()
node.fillColor = NSColor.redColor()
node.userInteractionEnabled = true
rootNode?.addChild(node)
hostingView.scene?.addChild(rootNode!)
}
然后实现手势识别器的动作方法,
@IBAction func panAction(sender: AnyObject) {
// Get the location in the view from the pan gesture recogniser
let viewPoint = (sender as NSPanGestureRecognizer).locationInView(hostingView)
// Convert from view -> scene -> root node coordinates
if let scene = hostingView.scene {
let scenePoint = hostingView.convertPoint(viewPoint, toScene:scene)
if let root = self.rootNode {
let rootNodePoint = scene.convertPoint(scenePoint, toNode: root)
let node = root.nodeAtPoint(rootNodePoint)
node.position = rootNodePoint
println("Drag to point:", NSStringFromPoint(scenePoint))
return
}
}
println("Node was nil.")
}
如果想运行这个项目,it's on github.
当鼠标快速拖动退出节点边界时,nodeAtPoint:
返回背景节点。这导致了闪烁(感谢@sangony)。
解决方法是使用NSGestureRecognizer's state值来区分第一次触发(NSGestureRecognizerStateBegan
)、一次更新(NSGestureRecognizerStateChanged
)、鼠标释放时(NSGestureRecognizerStateEnded
)。通过检查这些值,即使鼠标移动到节点边界之外,也可以缓存更新正确的节点。
更新后的动作方法是,
@IBAction func panAction(sender: AnyObject) {
// Get the location in the view from the pan gesture recogniser
let recognizer = (sender as NSPanGestureRecognizer)
let viewPoint = recognizer.locationInView(hostingView)
if let scene = hostingView.scene {
// Convert from view -> scene
let scenePoint = hostingView.convertPoint(viewPoint, toScene:scene)
if let root = self.rootNode {
// Convert from scene -> rootNode
let rootNodePoint = scene.convertPoint(scenePoint, toNode: root)
// Use the recogniser state, this keeps track of the correct node
// even if the mouse has moved outside of the node bounds during
// the drag operation.
switch recognizer.state {
case .Began:
// Cache the clicked node
let node = root.nodeAtPoint(rootNodePoint)
if node != root {
node.position = rootNodePoint
draggedNode = node
return
}
case .Changed:
// Update the cached node position
if let draggedNode = self.draggedNode {
draggedNode.position = rootNodePoint
}
case .Ended:
// Finally update the position and clear the cache
if let draggedNode = self.draggedNode {
draggedNode.position = rootNodePoint
self.draggedNode = nil
}
default:
return
}
}
}
}
今天我决定尝试添加到 OS X 中的一些新的闪亮(iOS 灵感)东西:手势识别器和 Sprite Kit。我已经为 SKView 设置了一个 NSPanGestureRecognizer,我正在使用它来拖动添加到场景中的节点。但是,我在快速拖动节点时看到奇怪的闪烁。
代码非常简单,在 AppDelegate 中设置所有内容,
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
// Add and scene to the view and create a root node
hostingView.presentScene(SKScene(size: CGSize(width: 1500.0, height: 1500.0)))
rootNode = SKNode()
// A a red circle
let node = SKShapeNode(circleOfRadius: 50.0)
node.lineWidth = 5.0
node.strokeColor = NSColor.whiteColor()
node.fillColor = NSColor.redColor()
node.userInteractionEnabled = true
rootNode?.addChild(node)
hostingView.scene?.addChild(rootNode!)
}
然后实现手势识别器的动作方法,
@IBAction func panAction(sender: AnyObject) {
// Get the location in the view from the pan gesture recogniser
let viewPoint = (sender as NSPanGestureRecognizer).locationInView(hostingView)
// Convert from view -> scene -> root node coordinates
if let scene = hostingView.scene {
let scenePoint = hostingView.convertPoint(viewPoint, toScene:scene)
if let root = self.rootNode {
let rootNodePoint = scene.convertPoint(scenePoint, toNode: root)
let node = root.nodeAtPoint(rootNodePoint)
node.position = rootNodePoint
println("Drag to point:", NSStringFromPoint(scenePoint))
return
}
}
println("Node was nil.")
}
如果想运行这个项目,it's on github.
当鼠标快速拖动退出节点边界时,nodeAtPoint:
返回背景节点。这导致了闪烁(感谢@sangony)。
解决方法是使用NSGestureRecognizer's state值来区分第一次触发(NSGestureRecognizerStateBegan
)、一次更新(NSGestureRecognizerStateChanged
)、鼠标释放时(NSGestureRecognizerStateEnded
)。通过检查这些值,即使鼠标移动到节点边界之外,也可以缓存更新正确的节点。
更新后的动作方法是,
@IBAction func panAction(sender: AnyObject) {
// Get the location in the view from the pan gesture recogniser
let recognizer = (sender as NSPanGestureRecognizer)
let viewPoint = recognizer.locationInView(hostingView)
if let scene = hostingView.scene {
// Convert from view -> scene
let scenePoint = hostingView.convertPoint(viewPoint, toScene:scene)
if let root = self.rootNode {
// Convert from scene -> rootNode
let rootNodePoint = scene.convertPoint(scenePoint, toNode: root)
// Use the recogniser state, this keeps track of the correct node
// even if the mouse has moved outside of the node bounds during
// the drag operation.
switch recognizer.state {
case .Began:
// Cache the clicked node
let node = root.nodeAtPoint(rootNodePoint)
if node != root {
node.position = rootNodePoint
draggedNode = node
return
}
case .Changed:
// Update the cached node position
if let draggedNode = self.draggedNode {
draggedNode.position = rootNodePoint
}
case .Ended:
// Finally update the position and clear the cache
if let draggedNode = self.draggedNode {
draggedNode.position = rootNodePoint
self.draggedNode = nil
}
default:
return
}
}
}
}