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

如何在touchesBegan事件中正确检测SKSpriteNode的触摸?

问题描述

我之前一直专注开发游戏手柄控制的应用,没怎么接触iOS触控类应用。现在遇到一个问题:通过addCreditsButton(_:)方法在GameScene左上角附近生成并添加了名为creditsInfo的SKSpriteNode按钮,但在GameViewController的touchesBegan事件中点击该节点时,控制台打印的节点名称却是位置相距甚远的horse,无法触发showCredits()方法。

相关代码

GameViewController 的 touchesBegan 方法

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    if let ourScene = GameScene(fileNamed: "GameScene") {
        
        if let touch:UITouch = touches.first {
            let location = touch.location(in: view)
            let node:SKNode = ourScene.atPoint(location)
            
            print("node.name = \(node.name!)")   // <== 输出 "horse"
            if (node.name == "creditsInfo") {
                showCredits()
            }
        }
        
    }   // if let ourScene
    
}   // touchesBegan

showScene 函数中添加按钮的代码

if let ourScene = GameScene(fileNamed: "GameScene") {

#if os(iOS)
    addCreditsButton(toScene: ourScene)
#endif

 }

addCreditsButton(_:) 方法代码

func addCreditsButton(toScene: SKScene) {
            
    if thisSceneName == "GameScene" {
                    
        itsCreditsNode.name = "creditsInfo"

        itsCreditsNode.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        
        itsCreditsNode.size = CGSize(width: 2*creditsCircleRadius,
                                     height: 2*creditsCircleRadius)
        itsCreditsNode.zPosition = 3
        creditsCirclePosY = roomHeight/2 - creditsCircleRadius - creditsCircleOffsetY
        creditsCirclePosX = -roomWidth/2 + creditsCircleRadius + creditsCircleOffsetX
        itsCreditsNode.position = CGPoint(x: creditsCirclePosX,
                                          y: creditsCirclePosY)
        
        toScene.addChild(itsCreditsNode)
                    
    }   // if thisSceneName

}   // addCreditsButton
解决方案

问题核心是你在touchesBegan里每次触摸都重新创建了一个全新的GameScene实例,这个新场景和当前屏幕上显示的场景完全是两个独立的对象,节点布局自然不匹配,所以取到的节点肯定不对。另外触摸位置的坐标系转换也有问题,需要修正。

步骤1:保存当前显示的GameScene引用

在GameViewController中添加一个属性来保存当前正在显示的场景实例:

class GameViewController: UIViewController {
    var currentGameScene: GameScene? // 新增属性保存场景引用
    // ... 其他代码
}

然后在showScene函数中,将创建好的场景实例赋值给这个属性(同时确保你把场景呈现到view上的代码也存在):

func showScene() {
    if let ourScene = GameScene(fileNamed: "GameScene") {
#if os(iOS)
        addCreditsButton(toScene: ourScene)
#endif
        currentGameScene = ourScene // 保存当前场景引用
        view.presentScene(ourScene) // 确保场景被呈现到view上
    }
}

步骤2:修正touchesBegan方法

改用保存的currentGameScene实例,同时将触摸位置转换到场景坐标系(而不是view坐标系):

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // 确保有触摸事件且当前场景存在
    guard let touch = touches.first, let ourScene = currentGameScene else {
        return
    }
    // 将触摸位置转换到场景坐标系
    let location = touch.location(in: ourScene)
    let node = ourScene.atPoint(location)
    
    print("node.name = \(node.name ?? "unknown")")
    if node.name == "creditsInfo" {
        showCredits()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:33:25