You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift游戏开发:如何禁用touchesBegan保留touchesMoved或反之?

解决SKNode滑动抖动:根据控制模式禁用对应触摸函数

嘿,这个问题我在开发2D触控游戏时也遇到过——滑动操作被touchesBegan误判成点击,导致节点来回跳,确实挺烦人的。下面是我亲测有效的几种实现方案,你可以根据自己的需求选:

方案一:用状态变量控制触摸函数的执行

这是最直接且易维护的方式,核心思路是用一个状态标记当前激活的控制模式,在每个触摸回调里先判断模式,不符合就直接返回。

步骤1:定义控制模式枚举

先创建一个枚举来明确支持的操作模式:

enum GameControlMode {
    case tap // 点击模式
    case swipe // 滑动模式
}

// 全局/场景内维护当前模式,默认可以设为点击
var currentControlMode: GameControlMode = .tap

步骤2:在触摸函数中加入模式判断

修改你的touchesBegan和touchesMoved函数,只有匹配当前模式时才执行逻辑:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // 如果当前是滑动模式,直接跳过点击逻辑
    guard currentControlMode == .tap else { return }
    
    // 原来的点击响应逻辑(比如节点定位、触发动作等)
    if let touch = touches.first {
        let location = touch.location(in: self)
        if yourNode.contains(location) {
            // 处理点击事件
        }
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    // 如果当前是点击模式,直接跳过滑动逻辑
    guard currentControlMode == .swipe else { return }
    
    // 原来的滑动响应逻辑(比如节点跟随触摸移动)
    if let touch = touches.first {
        let location = touch.location(in: self)
        yourNode.position = location
    }
}

步骤3:切换控制模式

当用户在设置界面选择操作方式时,更新currentControlMode即可:

// 比如用户选择滑动控制
currentControlMode = .swipe

方案二:动态移除/添加触摸识别器(进阶)

如果你觉得在每个触摸函数里加判断不够优雅,可以用UITapGestureRecognizer和UIPanGestureRecognizer替代系统的触摸回调,通过启用/禁用手势识别器来切换模式:

// 初始化手势识别器
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))

// 添加到场景视图
view.addGestureRecognizer(tapGesture)
view.addGestureRecognizer(panGesture)

// 默认启用点击,禁用滑动
tapGesture.isEnabled = true
panGesture.isEnabled = false

// 切换模式的方法
func switchToControlMode(_ mode: GameControlMode) {
    tapGesture.isEnabled = (mode == .tap)
    panGesture.isEnabled = (mode == .swipe)
}

// 点击和滑动的处理函数
@objc func handleTap(_ gesture: UITapGestureRecognizer) {
    let location = gesture.location(in: view)
    // 转换为场景坐标
    let sceneLocation = convertPoint(fromView: location)
    if yourNode.contains(sceneLocation) {
        // 处理点击
    }
}

@objc func handlePan(_ gesture: UIPanGestureRecognizer) {
    let translation = gesture.translation(in: view)
    let sceneTranslation = convertVector(translation, fromView: view)
    yourNode.position.x += sceneTranslation.x
    yourNode.position.y += sceneTranslation.y
    gesture.setTranslation(.zero, in: view)
}

这种方式的好处是把触摸逻辑和模式控制完全分离,代码结构更清晰,适合复杂的触控场景。

为什么之前会抖动?

本质原因是滑动操作时,touchesBegan会先触发,执行了点击的节点移动逻辑,紧接着touchesMoved又触发滑动逻辑,两种逻辑交替作用就导致了节点抖动。通过禁用对应模式下的触摸函数,就能彻底避免这个问题。

内容的提问来源于stack exchange,提问作者James Taga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:52:45