You need to enable JavaScript to run this app. SwiftUI下SpriteView承载的SKScene touchesBegan仅识别首次触摸问题
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI下SpriteView承载的SKScene touchesBegan仅识别首次触摸问题

SwiftUI 中 SpriteView 承载 SKScene 无法处理多点触控的解决方案

问题根源

  • 系统默认的SpriteView底层封装的SKView实例默认未开启多点触控(isMultipleTouchEnabled属性为false),系统只会将单个触摸事件传递给场景的touchesBegan方法,因此多手指同时触摸时只有第一个手指的操作会被响应;而你在UIKit的UIViewController中使用原生SKView时通常会手动开启该属性,因此功能正常。
  • 原代码中scene是计算属性,每次视图body刷新都会重新创建GameScene实例,会导致场景被意外重建,属于冗余隐患。

解决方案

步骤1:自定义支持多点触控的SpriteView包装器

SwiftUI没有提供直接修改SpriteView内部SKView配置的原生方法,我们通过UIViewRepresentable包装原生SKView,手动开启多点触控能力:

import SwiftUI
import SpriteKit

struct MultiTouchSpriteView: UIViewRepresentable {
    let scene: SKScene
    
    func makeUIView(context: Context) -> SKView {
        let skView = SKView()
        // 核心配置:开启多点触控
        skView.isMultipleTouchEnabled = true
        // 加载场景
        skView.presentScene(scene)
        return skView
    }
    
    func updateUIView(_ uiView: SKView, context: Context) {
        // 场景无动态更新时无需额外处理
    }
}

步骤2:修改ContentView的场景初始化逻辑

将原计算属性的scene改为仅初始化一次的状态属性,避免场景被反复重建,同时替换原系统SpriteView为自定义包装器:

struct ContentView: View {
    // 仅初始化一次的游戏场景,避免body刷新时重建
    @State private var gameScene: GameScene = {
        let scene = GameScene()
        scene.size = CGSize(width: 500, height: 350)
        scene.scaleMode = .fill
        return scene
    }()
    
    var body: some View {
        MultiTouchSpriteView(scene: gameScene)
            .frame(width: 500, height: 350)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

说明

  • 原GameScene的代码无需修改,其touchesBegan逻辑本身适配多点触控,和UIKit下的表现一致。
  • 修改后同时触摸左右半区时,会分别生成对应颜色的方块,完全符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.31 20:36:01