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

如何在RealityKit游戏中同时实现2D HUD与3D内容的交互?

在SwiftUI容器内解决交互冲突

1. 自定义SpriteView的UIViewRepresentable

直接用SwiftUI原生SpriteView无法灵活控制事件传递,需要自定义UIViewRepresentable包装SKView,同时持有RealityView的引用:

import SwiftUI
import SpriteKit
import RealityKit

struct SpriteKitHUDView: UIViewRepresentable {
    @Binding var scene: SKScene
    weak var realityView: ARView?
    
    func makeUIView(context: Context) -> SKView {
        let skView = SKView()
        skView.isUserInteractionEnabled = true
        skView.allowsTransparency = true
        skView.scene = scene
        return skView
    }
    
    func updateUIView(_ uiView: SKView, context: Context) {
        if uiView.scene !== scene {
            uiView.scene = scene
        }
    }
}

2. 在SpriteKit Scene中控制事件转发

在你的SKScene子类里,重写触摸方法,只处理HUD按钮的交互,非按钮区域的事件直接转发给RealityView:

class HUDScene: SKScene {
    weak var realityView: ARView?
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let touchLoc = touch.location(in: self)
        
        // 检查是否点击到HUD按钮
        if let button = atPoint(touchLoc) as? SKButtonNode { // 替换成你的按钮节点类型
            button.triggerAction()
            return
        }
        
        // 非按钮区域,转发事件给RealityView
        realityView?.touchesBegan(touches, with: event)
    }
    
    // 按需重写其他触摸方法,保持事件同步
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        realityView?.touchesMoved(touches, with: event)
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        realityView?.touchesEnded(touches, with: event)
    }
}

3. 在ContentView中关联视图

通过onAppear获取RealityView的引用,传递给HUDScene:

struct ContentView: View {
    @State private var hudScene = HUDScene(size: UIScreen.main.bounds.size)
    @State private var arView: ARView?
    
    var body: some View {
        ZStack {
            RealityView { content in
                // 添加你的3D内容
                let box = ModelEntity(mesh: .generateBox(size: 0.5))
                content.add(box)
            }
            .onAppear {
                // 获取底层ARView实例
                arView = UIApplication.shared.windows.first?.rootViewController?.view.subviews.first(where: { $0 is ARView }) as? ARView
                hudScene.realityView = arView
            }
            
            SpriteKitHUDView(scene: $hudScene, realityView: arView)
                .ignoresSafeArea()
        }
    }
}
脱离SwiftUI容器,直接用UIKit开发

如果完全不想依赖SwiftUI,直接基于UIKit构建ViewController,事件控制更直接:

import UIKit
import RealityKit
import SpriteKit

class GameViewController: UIViewController {
    private var arView: ARView!
    private var skView: SKView!
    private var hudScene: HUDScene!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 初始化RealityView
        arView = ARView(frame: view.bounds)
        view.addSubview(arView)
        
        // 添加3D内容
        let box = ModelEntity(mesh: .generateBox(size: 0.5))
        let anchor = AnchorEntity(world: .zero)
        anchor.addChild(box)
        arView.scene.addAnchor(anchor)
        
        // 初始化SpriteKit HUD
        hudScene = HUDScene(size: view.bounds.size)
        hudScene.realityView = arView
        
        skView = SKView(frame: view.bounds)
        skView.isUserInteractionEnabled = true
        skView.allowsTransparency = true
        skView.scene = hudScene
        view.addSubview(skView)
    }
}
关键注意事项
  • 开启SKView的allowsTransparency = true,确保HUD透明区域不遮挡RealityView的视觉。
  • 非交互的HUD节点(比如背景)设置isUserInteractionEnabled = false,避免无意义拦截事件。
  • 如需HUD完全覆盖时禁用RealityView交互,只需在HUDScene中添加一个全屏可交互背景节点,点击时不转发事件即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 12:12:24