疑难杂症:Can Hear Object 无法监听到声音

但是 BD 并不完全是一个无代码的行为控制插件,在部分时候还是需要根据自己项目的实际情况进行微改造的,比如现在我说到的就是 Can Hear Object 遇到的一些问题。

Can Hear Object 是一个侦听 Audio Source 的组件,如果侦听的 Transform 上不包含 Audio Source 组件则不会生效。

这在某些动态生成的 Transform 例如:枪械中,就很难简单的通过无代码的方式去设计,但我们可以修改其源码,让获取 Audio Source 的代码对所有 Children 生效。

但为了提高遍历的效率,尽可能地原子化到最接近动态 Transform 的那个对象上。

具体修改的源码如下,打开 Can Hear Object Task 类,找到相关代码,其核心是 MovementUtility.WithinHearingRange 函数。

查看该函数的代码,可以发现,默认的侦听逻辑是只针对 Transform 本身,我们只需要注释掉原来的代码,改成成包含子对象即可:

public static GameObject WithinHearingRange(Transform transform, Vector3 positionOffset, float audibilityThreshold, GameObject targetObject, ref float audibility)
{
    AudioSource[] colliderAudioSource;
    // Check to see if the hit agent has an audio source and that audio source is playing
    // if ((colliderAudioSource = GetComponentsForType<AudioSource>(targetObject)) != null) {
    if ((colliderAudioSource = targetObject.GetComponentsInChildren<AudioSource>(targetObject)) != null) {
        for (int i = 0; i < colliderAudioSource.Length; ++i) {
            if (colliderAudioSource[i].isPlaying) {
                var distance = Vector3.Distance(transform.position, targetObject.transform.position);
                if (distance >= colliderAudioSource[i].maxDistance) {
                    audibility = 0;
                } else {
                    if (colliderAudioSource[i].rolloffMode == AudioRolloffMode.Logarithmic) {
                        audibility = 1 / (1 + colliderAudioSource[i].maxDistance * (distance - 1));
                    } else { // linear
                        audibility = colliderAudioSource[i].volume * Mathf.Clamp01((distance - colliderAudioSource[i].minDistance) / (colliderAudioSource[i].maxDistance - colliderAudioSource[i].minDistance));
                    }
                }
                if (audibility > audibilityThreshold) {
                    return targetObject;
                }
            }
        }
    }
    return null;
}

这样,针对子对象的动态侦听就实现了。