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

Swift(Mac SpriteKit)如何限制鼠标指针不离开窗口?

解决Mac SpriteKit/Swift游戏中鼠标追踪事件不触发的问题

嘿,我来帮你排查这个鼠标追踪的问题!你遇到的mouseEntered/mouseExited不触发,以及光标移出后 paddle 失效的情况,大概率是NSTrackingArea的配置或者SpriteKit的事件传递机制出了小问题,下面给你几个具体的解决思路:


1. 修正NSTrackingArea的核心配置

你的代码里有两个关键问题需要调整:

  • owner设置错误:你把tracking area的owner设为了view,但你是在当前控制器/场景类里重写的鼠标事件方法,应该把owner设为self,这样事件才会发送到正确的接收对象
  • 缺少inVisibleRect选项:如果视图的frame发生变化,原有的rect可能无法覆盖整个可见区域,加上这个选项能确保追踪整个视图的可见范围
  • 开启视图的鼠标移动事件支持:Mac视图默认不接收mouseMoved事件,必须手动开启

修改后的代码示例(如果是在ViewController中):

override func viewDidLoad() {
    super.viewDidLoad()
    
    guard let skView = view as? SKView else { return }
    // 开启鼠标移动事件支持
    skView.acceptsMouseMovedEvents = true
    
    let trackingOptions: NSTrackingArea.Options = [
        .mouseMoved,
        .activeAlways,
        .mouseEnteredAndExited,
        .inVisibleRect // 关键:跟踪整个可见区域
    ]
    // owner设为self,确保事件发送到当前类
    let tracker = NSTrackingArea(rect: skView.bounds, options: trackingOptions, owner: self, userInfo: nil)
    skView.addTrackingArea(tracker)
}

2. 确保鼠标事件方法被正确调用

如果你是在SKScene中处理事件,需要在场景的didMove(to:)方法里配置tracking area,并且确保场景允许用户交互:

override func didMove(to view: SKView) {
    view.acceptsMouseMovedEvents = true
    isUserInteractionEnabled = true // 开启场景的用户交互
    
    let trackingOptions: NSTrackingArea.Options = [
        .mouseMoved,
        .activeAlways,
        .mouseEnteredAndExited,
        .inVisibleRect
    ]
    let tracker = NSTrackingArea(rect: view.bounds, options: trackingOptions, owner: self, userInfo: nil)
    view.addTrackingArea(tracker)
}

此时重写的mouseEntered/mouseExited方法就能正常触发了:

override func mouseExited(with event: NSEvent) {
    print("光标移出窗口啦!")
    // 这里可以添加提示逻辑,比如显示弹窗,或者强制把光标拉回窗口
    if let window = view?.window {
        let center = NSPoint(x: window.frame.midX, y: window.frame.midY)
        CGDisplayMoveCursorToPoint(CGMainDisplayID(), center)
    }
}

override func mouseEntered(with event: NSEvent) {
    print("光标回到窗口内了!")
}

3. 额外方案:直接限制鼠标在窗口内

如果你的核心需求是不让鼠标移出窗口,除了事件提示,还可以用macOS的API直接限制光标范围(macOS 10.13+可用):

if let window = view?.window, let contentView = window.contentView {
    // 把窗口内容区域转换为屏幕坐标
    let screenRect = contentView.convert(contentView.bounds, to: nil)
    window.setRestrictsMousePosition(true)
    window.restrictMousePosition(to: screenRect)
}

4. 排查其他可能的拦截因素

  • 检查是否有其他子视图覆盖在SKView上方,这些视图可能会拦截鼠标事件
  • 确保SKView的ignoresMouseEvents属性没有被设为true

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:06:05