Swift SKSpriteNode:检测 Tap / DoubleTap / LongPress

Posted

技术标签:

【中文标题】Swift SKSpriteNode:检测 Tap / DoubleTap / LongPress【英文标题】:Swift SKSpriteNode: Detect Tap / DoubleTap / LongPress 【发布时间】:2014-09-28 21:01:18 【问题描述】:

我正在尝试创建一个 SKSpriteNode 的子类,它可以检测用户交互(点击、双击和按住),然后遵从委托。在我看来,这似乎是一个相对普遍的需求,但是:

    代码无法在不触发单击的情况下检测到双击。 我还没有找到检测按住/长按操作的方法。

这一切都错了吗?我不禁觉得 SpriteKit 应该有一些标准来处理如此基本的事情。我知道有 UIGestureRecognizer,但它似乎与特定的 SKNodes 而不是 UIViews 兼容。

这是我目前拥有的。根据 Apple 的示例,我在主类文件中有所有非设备特定的代码:

import SpriteKit

enum ActionType: Int 
    case Single
    case Double
    case Hold


protocol EnvironmentElementDelegate 
    func handleActionOnElement(element: EnvironmentElement, actionType: ActionType)


class EnvironmentElement: SKSpriteNode 

    let delegate: EnvironmentElementDelegate!

    init(imageNamed: String, elementNamed: String, delegate: EnvironmentElementDelegate) 
        self.delegate = delegate
        let texture = SKTexture(imageNamed: imageNamed)
        super.init(texture: texture, color: UIColor.clearColor(), size: texture.size())
        self.name = elementNamed
        userInteractionEnabled = true
    

    required init(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
    

...然后将所有 ios 特定代码放在一个单独的扩展文件中:

import SpriteKit

extension EnvironmentElement 

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) 
        for touch: AnyObject in touches 
            if (touch.tapCount >= 2) 
                NSObject.cancelPreviousPerformRequestsWithTarget(self)
            
        
    

    override func touchesEnded(touches: NSSet, withEvent event: UIEvent) 
        for touch: AnyObject in touches 
            if (touch.tapCount == 1) 
                delegate.handleActionOnElement(self, actionType: ActionType.Single)
                // Unable to find Swift equivalent to this: [self performSelector:@selector(onFlip) withObject:nil afterDelay:0.3];
             else 
                delegate.handleActionOnElement(self, actionType: ActionType.Double)
            
        
    

【问题讨论】:

通常当我需要一个必须检测用户点击的对象时,我使用 SKNode,它工作得更好,我在使用 SKSpriteNode 时遇到了很多问题。对于 iOS 特定代码,我将其添加到类本身,这样效果更好。 感谢 Totka 的回复,但您不会在 SKNode 中也遇到同样的问题吗?您如何检测双击和长时间保持而不是单击?我担心的是,我的代码可能与识别此类基本用户输入的最佳实践相去甚远。 我建议您使用内置的 UIGestureRecognizers,因为它们支持长按和双击(单击拒绝)。 谢谢。虽然正如我上面提到的,UIGestureRecognizers 似乎与 SpriteKit 节点不兼容:没有添加它们的函数。这就是为什么我不相信我的设计的原因。一直在阅读有关 MVC 的更多信息,也许我应该研究如何在视图级别添加识别器,然后检测从那里点击了哪个节点? 嗨。感谢您在流行的 uiscrollview 问题上添加 ios,但由于它的编辑太小,您可能很快就会面临其他审阅者的拒绝。最好还审查整个帖子以进行改进和/或在大规模编辑时等待 2000 名。 【参考方案1】:

您可以在touchesBegan: 中简单地使用touch.tapCount

【讨论】:

效果很好。请注意,这不会阻止第一次触摸事件触发,例如tapCount==1 触摸在touchesBegantouchesEnded 上仍然触发。所以你仍然需要锻炼,可能使用定时器,延迟识别它是真正的单击还是双击。【参考方案2】:

我从来不需要检测双击,但如果我有,我会这样做:

1 - 添加一个名为 alreadyTouch 的本地变量,并在类初始化时将其设置为 false

2 - 在 touchesBegin 内部,如果 alreadyTouchfalse 将其设置为 true 否则做你必须做的事情

3 - 设置 0.2 秒的本地 Timer 并将其添加到 if else 以检测触摸是否足够快。所以在你设置alreadyTouch = true的地方启动这个计时器。

希望对你有帮助

【讨论】:

您好 Totka,请您提供一些示例代码行,例如您将如何运行本地 Timer? 你好,很抱歉,我失去了那个项目,或者更好的是,那个项目的高清

以上是关于Swift SKSpriteNode:检测 Tap / DoubleTap / LongPress的主要内容,如果未能解决你的问题,请参考以下文章

未检测到 SKSpriteNode 触摸

在触摸时将动画添加到 SKSpriteNode (Swift)

Swift:检测 bodyAtPoint。总是零

skemitternode 与 skspritenode 碰撞

SKPhysicsContact未检测到categoryBitMask碰撞

如何将 SKSpriteNode 合并到 SKTexture 以在 Swift 3 中形成新的 SKSpriteNode?