如何确保AR App中同一时间仅播放一个视频?
解决方案:AR图像锚点视频互斥播放
核心问题
每次扫描新图像时,旧的视频节点未被停止或销毁,导致多个视频同时播放。需要在播放新视频前,终止所有已存在的视频播放实例。
具体实现步骤
1. 添加视频节点跟踪属性
在你的AR视图控制器类中,添加数组记录当前活跃的视频节点:
var activeVideoNodes: [SKVideoNode] = []
2. 重构视频节点创建逻辑
将重复的视频节点创建代码抽成通用方法,减少冗余:
private func createVideoNode(for videoFileName: String, with imageAnchor: ARImageAnchor) -> SCNNode { // 创建视频节点并播放 let videoNode = SKVideoNode(fileNamed: videoFileName) videoNode.play() activeVideoNodes.append(videoNode) // 配置视频场景 let videoScene = SKScene(size: CGSize(width: 480, height: 360)) videoNode.position = CGPoint(x: videoScene.size.width / 2, y: videoScene.size.height / 2) videoNode.yScale = -1.0 videoScene.addChild(videoNode) // 创建匹配图像尺寸的平面节点 let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height) plane.firstMaterial?.diffuse.contents = videoScene let planeNode = SCNNode(geometry: plane) planeNode.eulerAngles.x = -.pi / 2 return planeNode }
3. 修改锚点节点创建方法
生成新锚点节点前,先停止并清理所有旧视频:
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? { let node = SCNNode() guard let imageAnchor = anchor as? ARImageAnchor else { return node } // 停止所有活跃视频并清理 activeVideoNodes.forEach { videoNode in videoNode.pause() videoNode.removeFromParent() } activeVideoNodes.removeAll() // 根据图像名称创建对应视频节点 switch imageAnchor.referenceImage.name { case "harrypotter": let videoPlane = createVideoNode(for: "harrypotter.mp4", with: imageAnchor) node.addChildNode(videoPlane) case "deatheater": let videoPlane = createVideoNode(for: "deatheater.mp4", with: imageAnchor) node.addChildNode(videoPlane) default: break } return node }
4. 处理图像消失场景(可选)
当图像锚点从场景中移除时,同步停止对应视频:
func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) { node.enumerateChildNodes { childNode, _ in guard let plane = childNode.geometry as? SCNPlane, let videoScene = plane.firstMaterial?.diffuse.contents as? SKScene else { return } videoScene.enumerateChildNodes { skNode, _ in guard let videoNode = skNode as? SKVideoNode else { return } videoNode.pause() videoNode.removeFromParent() if let index = activeVideoNodes.firstIndex(of: videoNode) { activeVideoNodes.remove(at: index) } } } }
原理说明
通过activeVideoNodes数组跟踪所有正在播放的视频实例,每次创建新视频前先终止旧实例的播放并从父节点移除,确保同一时间只有一个视频在播放。同时重构代码减少重复逻辑,提升可维护性。
内容的提问来源于stack exchange,提问作者Ankur Batta
相关产品推荐
相关产品推荐

