基于React+MindAR+A-Frame实现目标图片识别触发对应专属音频的功能异常排查
基于React+MindAR+A-Frame实现目标图片识别触发对应专属音频的功能异常排查
嘿,我仔细看了你的代码,立马就发现问题出在哪了——你现在的写法只能固定操作第一个带sound组件的实体(也就是狮子的音频),完全没对应上不同的目标索引来触发专属音频。咱一步步来拆解和修复:
核心问题分析
错误的实体获取方式
你在useEffect里用document.querySelector('a-entity[sound]')只会拿到页面中第一个匹配的实体,也就是狮子对应的那个<a-entity>。所以不管你识别到的是狮子还是猫头鹰,代码都只会去操作狮子的音频组件,猫头鹰的自然不会响应。事件处理没关联目标索引
MindAR的targetFound事件其实会携带目标索引的信息,你完全可以利用这个信息,精准找到对应索引的实体,再触发它的音频。
修复方案
我们需要修改事件监听逻辑,让它根据识别到的目标索引,动态找到对应的音频实体并操作,同时记录当前播放的音频,在目标丢失时暂停。
修复后的完整代码
import React, { useCallback, useEffect, useRef, useState } from 'react'; import 'aframe'; import 'mind-ar/dist/mindar-image-aframe.prod.js'; import { getChildrenByGroup } from './../utils/helpers'; const MindARViewer = ({children_AR_list}) => { const sceneRef = useRef(null); const sceneRefering= useRef([]); const [targetFound, setTargetFound] = useState(""); let [targetFoundCounter,setTargetFoundCounter] = useState(0); const [groupedChildren, setGroupedChildren] = useState([]); // 新增ref记录当前正在播放的音频实体 const currentPlayingSoundRef = useRef(null); useEffect(() => { setGroupedChildren(getChildrenByGroup(children_AR_list)) }, []); useEffect(() => { const sceneEl = sceneRef.current; const arSystem = sceneEl.systems?.["mindar-image-system"]; // Start AR system when scene starts rendering sceneEl.addEventListener('loaded', () => { arSystem.start(); }); // Handle target detection events sceneEl.addEventListener('targetFound', (e) => { const targetIndex = e.detail.targetIndex; // 根据目标索引找到对应的实体 const soundEntity = sceneEl.querySelector(`a-entity[mindar-image-target="targetIndex: ${targetIndex}"]`); if (!soundEntity) return; // 暂停之前可能在播放的音频 if (currentPlayingSoundRef.current) { currentPlayingSoundRef.current.components.sound?.pause(); } // 播放当前目标的音频 soundEntity.components.sound?.playSound(); currentPlayingSoundRef.current = soundEntity; // 更新状态 setTargetFound(soundEntity.components.sound.parsingAttrValue); console.log(`Target found:`, soundEntity.components.sound.parsingAttrValue); setTargetFoundCounter(prev => prev + 1); // 用函数式更新避免闭包问题 }); sceneEl.addEventListener('targetLost', (e) => { const targetIndex = e.detail.targetIndex; const soundEntity = sceneEl.querySelector(`a-entity[mindar-image-target="targetIndex: ${targetIndex}"]`); if (soundEntity && soundEntity === currentPlayingSoundRef.current) { soundEntity.components.sound?.pause(); currentPlayingSoundRef.current = null; } }); return () => { arSystem.stop(); // 组件卸载时暂停所有音频 if (currentPlayingSoundRef.current) { currentPlayingSoundRef.current.components.sound.pause(); } } }, []); return ( <> <a-scene ref={sceneRef} mindar-image={`imageTargetSrc: http://localhost:5000/wild%20nature/wild_nature.mind; autoStart: false; uiLoading: true; uiError: true; uiScanning: true; maxTrack: 3`} color-space="sRGB" embedded renderer="colorManagement: true, physicallyCorrectLights" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false" > <a-assets> <audio id="lion" src="http://localhost:5000/wild%20nature/lion/lion.mp3" preload='auto'></audio> <audio id="owl" src="http://localhost:5000/wild%20nature/owl/owl.mp3" preload='auto'></audio> </a-assets> <a-camera position="0 0 0" look-controls="enabled: true"></a-camera> <a-entity mindar-image-target="targetIndex: 4" geometry="primitive: plane" position=" 0 0 0" sound="src:#lion;" /> <a-entity mindar-image-target="targetIndex: 3" geometry="primitive: plane" position=" 0 0 0" sound="src:#owl;" /> </a-scene> </> ) } export default MindARViewer;
关键修复点说明
- 新增
currentPlayingSoundRef来记录当前正在播放的音频实体,避免多个音频同时播放或者暂停错误的音频 - 在
targetFound事件中,通过e.detail.targetIndex获取当前识别到的目标索引,再用这个索引精准找到对应的实体 - 目标丢失时,只暂停当前正在播放的对应音频
- 用函数式更新
setTargetFoundCounter(prev => prev + 1),避免React闭包导致的状态更新错误
这样修改后,你扫描狮子图片会播放狮子的音频,切换到猫头鹰图片时,会先暂停狮子的音频,再播放猫头鹰的音频,完全符合你的需求啦!
内容来源于stack exchange
相关产品推荐
相关产品推荐

