[BUG] 又轮到 AudioSource 出事了...

版本: 3.3.2

重现代码:

    // 随便挂个按钮, TOUCH_START 绑上这个方法
    $testBtn_ts() {
        const asc: AudioSource = window["asc"] || (window["asc"] = this.node.addComponent(AudioSource));
        asc.loop = asc.playOnAwake = false;
        console.log("[testBtn_ts]");
        asc.clip = this.clip; // 随便挂一个clip, 这里是个大概2秒的音效
        asc.play();
    }
    // 随便挂个按钮, TOUCH_END 绑上这个方法
    $testBtn_te() {
        const asc: AudioSource = window["asc"] || (window["asc"] = this.node.addComponent(AudioSource));
        asc.loop = asc.playOnAwake = false;
        console.log("[testBtn_te]");
        asc.stop();
        asc.clip = null;
    }

期望结果: 按下按钮播放音效, 抬起按钮停止

运行结果: 无论长按短按, 音效只会播放第一次

我这调用也没有很过分吧…
扫了一眼源码…里面各种换源/异步回调…没头发看了…你们自个玩吧…
反正显然是有一堆回调卡住了…
image

对了还有个和上文无关的音频播放小问题…

第一个音效经常性的会延迟/丢失…
通常是进场景悄悄来个playOneShot(clip, 0.01)才好解决…

没怎么看懂,你设置的是不循环,只播放一次不是正常结果吗?

没看懂就多看几眼…不着急回复的…
一共才10行代码…还有3行是重复的…

换clip似乎是重新加载吧,你需要关注下network…

忍不住又debug了一下…
这里一进来就把标记给干了…
然后又各种理由给赶出去…
image
这明显就有语义问题啊…
还没正式开始 load 就把 _isLoaded 给干了…
这算是语文没学好还是代码没写好…

强行扭回来勉强行了…剩下你们研究吧…

你都看源码了,那里的设置不是异步的吗?你同一帧去执行,自然return了

真奇怪啊…你是来解决问题还是来质疑问题的呢…?
代码列出来了…有跑过吗…?
源码搬出来了…有断点看过吗…?
请问你在这里指点江山是打算干嘛呢…?
问题是经过你质疑楼主之后就不存在了吗…?

我是来质疑问题的
没有
没有
质疑问题
有可能


import { _decorator, Component, Node, AudioClip, AudioSource } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('Btn')
export class Btn extends Component {

    @property({
        type: [AudioClip]
    })
    acs: AudioClip[] = [];

    private index: number = 0;

    onLoad() {
        this.node.on(Node.EventType.TOUCH_START, this.onBtnStart, this)
        this.node.on(Node.EventType.TOUCH_END, this.onBtnEnd, this)
    }

    onBtnStart() {
        if (this.acs.length === 0) {
            return;
        }
        const as = this.node.getComponent(AudioSource);
        as.loop = false;
        as.playOnAwake = false;
        if (this.index >= this.acs.length) {
            this.index = 0;
        }
        as.clip = this.acs[this.index];
        as.play();
        this.index++;
    }

    onBtnEnd() {
        const as = this.node.getComponent(AudioSource);
        as.loop = false;
        as.playOnAwake = false;
        as.stop();
        // as.clip = null;
    }
}

你要的尝试,如果是重复一个音效是有问题,那你完全可以把置空那一步不要就可以实现了

一开始这样讨论不就好好的…

你的结论没错…
重复赋值相同的clip才会有问题…
为何会这样呢…?

因为源码里缓存了一个叫 _lastSetClip 的属性…
大概是用于核实异步 play 的时间内 clip 是否有改动…
可是很明显…对于 _lastSetClip 和 _isLoaded 的赋值时机出了问题…
导致 null 和同一个 clip 交叉赋值时…
既不成立 _lastSetClip 也不成立 _isLoaded …
触发了死锁…

但是这些都是引擎内部操作…原则上调用者是不需要关注的…
如果有特别情况…应当在api上说明…
而目前的api说明上…clip 是可以赋 null 的…
image

所以 as.clip = null;
这在引擎api使用者的层面是完全合理的…

而合理的使用…导致了不合理的情况…

这叫BUG

所以这就是为什么我来发帖子…而不是自个找偏方来让它变正常…

1赞

:pensive:你要一开始说不能赋值两个相同的音效不就好了,我理解能力比较差。

我提供的示例代码里…this.acs[48]就是一个常量…

好像有类似的问题,楼主怎么弄的

1赞

把提出问题的人解决掉

1赞