cc.AudioSource && cc.Animation

本文详细介绍了cc.AudioSource组件的主要方法和属性,包括播放、停止、暂停等操作及循环播放设置等内容。同时,还深入解析了cc.Animation组件的功能,如动画播放控制、事件监听等,并列举了其主要方法和常用属性。

cc.AudioSource

音频源组件,能对音频剪辑

AudioSource组件面板介绍

面板介绍

主要方法参考功能说明
play()播放音频
stop()停止播放音频
pause()暂停播放音频
resume()恢复播放音频
rewind()重头开始播放
主要属性功能说明
loop是否循环播放
isPlaying是否正在播放
mute是否静音

设置这类属性时应要在start函数内设置,在onload上设置可能导致再次初始化没达到预期效果

cc.Animation

用于播放动画

组件面板介绍:

组件面板介绍

动画编辑器介绍:

介绍

Animation 提供了一系列可注册的事件:

事件功能
play开始播放时
stop停止播放时
pause暂停播放时
resume恢复播放时
lastframe假如动画循环次数大于 1,当动画播放到最后一帧时
finished动画播放完成时

Animation主要方法

主要方法功能
play(name,startTime)播放指定的动画,如果没有制定就播放默认的动画
playAdditive(name,startTime)播放指定的动画(将不会停止当前播放的动画)。如果没有指定动画,则播放默认动画
stop(name)停止指定的动画。如果没有指定名字,则停止当前正在播放的动画
pause(name)暂停当前或者指定的动画。如果没有指定名字,则暂停当前正在播放的动画
resume(name)重新播放指定的动画,如果没有指定名字,则重新播放当前正在播放的动画
getClips()获取动画组件上的所有动画剪辑,返回AnimationClip数组
常用属性说明
defaultClip在勾选自动播放或调用 play() 时默认播放的动画剪辑
currentClip当前播放的动画剪辑
//AudioMgr.ts import { Node, AudioSource, AudioClip, resources, director } from 'cc'; /** * @en * this is a sington class for audio play, can be easily called from anywhere in you project. * @zh * 这是一个用于播放音频的单件类,可以很方便地在项目的任何地方调用。 */ export class AudioMgr { private static _inst: AudioMgr; public static get inst(): AudioMgr { if (this._inst == null) { this._inst = new AudioMgr(); } return this._inst; } private _audioSource: AudioSource; constructor() { //@en create a node as audioMgr //@zh 创建一个节点作为 audioMgr let audioMgr = new Node(); audioMgr.name = '__audioMgr__'; //@en add to the scene. //@zh 添加节点到场景 director.getScene().addChild(audioMgr); //@en make it as a persistent node, so it won't be destroied when scene change. //@zh 标记为常驻节点,这样场景切换的时候就不会被销毁了 director.addPersistRootNode(audioMgr); //@en add AudioSource componrnt to play audios. //@zh 添加 AudioSource 组件,用于播放音频。 this._audioSource = audioMgr.addComponent(AudioSource); } public get audioSource() { return this._audioSource; } /** * @en * play short audio, such as strikes,explosions * @zh * 播放短音频,比如 打击音效,爆炸音效等 * @param sound clip or url for the audio * @param volume */ playOneShot(sound: AudioClip | string, volume: number = 1.0) { if (sound instanceof AudioClip) { this._audioSource.playOneShot(sound, volume); } else { resources.load(sound, (err, clip: AudioClip) => { if (err) { console.log(err); } else { this._audioSource.playOneShot(clip, volume); } }); } } /** * @en * play long audio, such as the bg music * @zh * 播放长音频,比如 背景音乐 * @param sound clip or url for the sound * @param volume */ play(sound: AudioClip | string, volume: number = 1.0) { if (sound instanceof AudioClip) { this._audioSource.stop(); this._audioSource.clip = sound; this._audioSource.play(); this.audioSource.volume = volume; } else { resources.load(sound, (err, clip: AudioClip) => { if (err) { console.log(err); } else { this._audioSource.stop(); this._audioSource.clip = clip; this._audioSource.play(); this.audioSource.volume = volume; } }); } } /** * stop the audio play */ stop() { this._audioSource.stop(); } /** * pause the audio play */ pause() { this._audioSource.pause(); } /** * resume the audio play */ resume(){ this._audioSource.play(); } }在人物等级为1时,循环播放/audio/Grade1,在人物等级为2时,循环播放/audio/Grade2,在人物等级为3时,循环播放/audio/Grade3,当人物和怪兽攻击时播放/audio/Attack
最新发布
07-19
import { _decorator, Label, Node, sp, tween, UITransform, Sprite, SpriteFrame, Component } from 'cc'; import { GameEvent } from '../../GameEvent'; import { MainModel } from '../main/MainModel'; import { oops } from "../../../oops/core/Oops"; import { ProxyRewards } from '../rewards/ProxyRewards'; import ListView from '../../../gamebase/uicore/ListView'; import { JuQing_ZhangJieView } from './JuQing_ZhangJieView'; import { JuQing_ZhangJieModel } from './JuQing_ZhangJieModel'; import { ProxyJuQing_ZhangJie } from './ProxyJuQing_ZhangJie'; import { ResHelper } from '../../../gamebase/helper/ResHepler'; import { RewardsController } from '../rewards/RewardsController'; import { JuQingZhangJie } from '../../../gameproto/config/schema'; import { DataCache } from '../../../gamebase/datacache/DataCache'; import { UIController } from '../../../gamebase/uicore/UIController'; import { ModelManager } from '../../../gamebase/manager/ModelManager'; import { EffectManager } from "../../../gamebase/manager/EffectManager"; import { AudioManager } from '../../../oops/core/common/audio/AudioManager'; import { LocalizationManager } from '../../../gamebase/manager/LocalizationManager'; import { JuQing_ZhangJieItemController } from '../sub/juqing_zhangjieitem/JuQing_ZhangJieItemController'; const { ccclass, property } = _decorator; /** 章节控制器 */ @ccclass('JuQing_ZhangJieController') export class JuQing_ZhangJieController extends UIController<JuQing_ZhangJieView> { //#region 初始化 public static NAME: string = "JuQing_ZhangJieController"; private zhangjieListView: ListView; private zhangjiefgList: JuQingZhangJie[] = []; private audioManager: AudioManager; // 使用getter缓存常用模型引用 private get mainModel(): MainModel { return ModelManager.instance.MainModel; } private get juQing_ZhangJieModel(): JuQing_ZhangJieModel { return ModelManager.instance.JuQing_ZhangJieModel; } // 缓存常用UI组件引用 private _pangbaiLabel: Label; private _zimuLabel: Label; private _changjingBg: Sprite; /** 顺序0 - 此处勿修改 */ protected OnSetView(): void { super.OnSetView(); this.SetView(new JuQing_ZhangJieView(this.node)); // 缓存UI组件引用 this._pangbaiLabel = this.view.pangbaiLabel; this._zimuLabel = this.view.zimuLabel; this._changjingBg = this.view.changjingBg; } /** 顺序1 - 界面初始显示 */ protected OnInit(): void { super.OnInit(); this.audioManager = this.node.getComponent(AudioManager) || this.node.addComponent(AudioManager); this.audioManager.load(); } /** 顺序2 - 在此注册UI控件事件 */ protected OnRegisterUIEvent(): void { super.OnRegisterUIEvent(); this.view.BtnClose?.reg(this.onBtnCloseHandler.bind(this)); } /** 顺序3 - 在此注册全局事件 */ protected OnRegisterMessage(): void { super.OnRegisterMessage(); oops.message.on(GameEvent.RefreshJuJiList, this.updateUI, this); } protected OnDispose(): void { super.OnDispose(); this.view.BtnClose?.unRegAll(); oops.message.off(GameEvent.RefreshJuJiList, this.updateUI, this); this.audioManager.stopAll(); this._juqingEffects.clearAll(); } /** 语言切换时触发 */ protected OnLanguageChanged(): void { super.OnLanguageChanged(); this.updateUI(); } private getPanelViewName(path: string): string { return ProxyJuQing_ZhangJie.PrefixPath + path; } //#endregion //#region events private onBtnCloseHandler() { if (this.isFreeze) return; ProxyJuQing_ZhangJie.Close(); } //#endregion private _gushiId: number; public setJuQingId(gushiId: number): void { this._gushiId = gushiId; this.zhangjiefgList = DataCache.tables.TbJuQingZhangJie.getDataList().filter(item => item.gushiid === this._gushiId); this.zhangjieListView = this.view.listView.getComponent(ListView); this.zhangjieListView.onLoad(); this.zhangjieListView.onItemRender = this.onItemRender.bind(this); this.zhangjieListView.numItems = this.zhangjiefgList.length; this._juqingEffects.setController(this); this.updateUI(); } // 使用私有类替代立即执行函数 private _juqingEffects = new (class extends Component { private _effectMap = new Map<number, Node>(); private _controller: JuQing_ZhangJieController; private _pendingRemoval: number | null = null; private beishu = 1; // 标记是否已显示结束旁白 private isEndPangbaiShown = false; // 文本索引 private pangbaiIndex = 0; private zimuIndex = 0; private eddpangbaiIndex = 0; // 章节ID和剧情ID private zhangjieId: number = 0; private juqingId: number = 0; onLoad() { this._effectMap = new Map(); } setController(controller: JuQing_ZhangJieController) { this._controller = controller; } // 添加剧情特效 addEffect(zhangjieID: number, juqingID: number, beishu: number, parentNode: Node) { this.beishu = beishu; this.zhangjieId = zhangjieID; this.juqingId = juqingID; this.isEndPangbaiShown = false; // 重置标记 this.pangbaiIndex = 0; // 重置旁白索引 this.zimuIndex = 0; // 重置字幕索引 this.eddpangbaiIndex = 0; // 重置结束旁白索引 if (!parentNode) { console.error("剧情特效父节点为空"); return; } const juqingCfg = DataCache.tables.TbJuQingChangGing.get(this.juqingId); if (!juqingCfg) { console.error(`未找到剧情配置,ID: ${this.juqingId}`); return; } EffectManager.instance.loadSpineEffect(juqingCfg.juqingziyuan, parentNode, (eff) => { if (!eff) { console.error("加载剧情动画失败:", juqingCfg.juqingziyuan); return; } if (this._effectMap.has(this.juqingId)) { EffectManager.instance.putSpine(eff); return; } this._effectMap.set(this.juqingId, eff); eff.setSiblingIndex(1); // 确保动画在背景之上 const spine = eff.getComponentInChildren(sp.Skeleton); // 在addEffect方法中添加 if (spine) { spine.timeScale = this.beishu; // 直接应用当前倍速 // 开始播放动画的事件监听 spine.setStartListener(() => this.onSpineStart(spine, parentNode, juqingCfg) ); //用来设置动画播放过程中帧事件的监听 spine.setEventListener((entry: sp.spine.TrackEntry, event: sp.spine.Event,) => { this.handleSpineEvent(entry, event, juqingCfg); }); // 动画播放一次循环结束后的事件监听 spine.setCompleteListener(() => this.onSpineComplete(this.juqingId, parentNode) ); } }, "animation", 1, false); } /** 设置开始播放动画的事件监听 */ private onSpineStart(spine: sp.Skeleton, parent: Node, cfg: any) { this.scheduleOnce(() => { oops.audio.pauseMusic(); // 显示退出按钮 this._controller.view.BtnTuiChu.reg(() => { this.setupTuiChuControl(); }); //显示倍数 设置倍数 this._controller.view.beisuLabel.string = `x${this.beishu}`; // 缓存当前spine实例引用 const currentSpine = spine; currentSpine.timeScale = this.beishu; this._controller.view.BeishuButton.reg(() => { this.setupBeishuControl(currentSpine); }); // 加载并显示背景图 this._controller._changjingBg.node.active = false; if (cfg.juqingchangjingBg) { // 使用 LocalizationManager 加载背景图,调整参数顺序 LocalizationManager.instance.setSpriteFrame(this._controller._changjingBg, `uiatlas/${cfg.juqingchangjingBg}`, (err) => { if (err) { console.error(`加载背景图失败: ${err}`); return; } // 调整背景图大小以适应父节点 const parentSize = parent.getComponent(UITransform)?.contentSize; if (parentSize) { this._controller._changjingBg.getComponent(UITransform)!.setContentSize(parentSize); } // 图片加载完成后显示背景图 this._controller._changjingBg.node.active = true; }); } }); } /** 用来设置动画播放过程中帧事件的监听*/ private handleSpineEvent(entry: sp.spine.TrackEntry, event: sp.spine.Event, cfg: any) { console.log(`[事件触发] 动画:${entry.animation.name} 事件:${event.data.name}`); const audioPath = `audio/bgm/${event.data.name}`; this._controller.audioManager.playMusic(audioPath, false); // 显示开始旁白 this.showNextPangbai(cfg); // }); } /**动画播放一次循环结束后的事件监听 */ private onSpineComplete(juqingId: number, parent: Node) { // 动画结束时停止音乐 oops.audio.stopMusic(); // 隐藏所有标签 this._controller._pangbaiLabel.node.active = false; this._controller._zimuLabel.node.active = false; // 处理结束事件 const changjingCfg = DataCache.tables.TbJuQingChangGing.get(juqingId); if (changjingCfg && changjingCfg.jieshushijian.length > 0) { const condition = changjingCfg.jieshushijian[0]; switch (condition.type) { case 1: const nextId = Number(condition.param); if (nextId > 0) { this.removeEffect(juqingId); this.addEffect(this.zhangjieId, nextId, this.beishu, parent); return; } break; } } // 恢复背景音乐 oops.audio.resumeMusic(); // 最终章节处理逻辑 this.handleFinalChapter(changjingCfg); } /** 退出按钮*/ private setupTuiChuControl() { this.clearAll(); this._controller._changjingBg.node.active = false; oops.audio.resumeMusic(); this._controller.updateUI(); } /** 倍数按钮*/ private setupBeishuControl(spine: sp.Skeleton) { const targetSpeed = this.beishu === 1 ? 2 : 1; // 使用tween实现平滑过渡 tween(spine) .to(0.3, { timeScale: targetSpeed }) .call(() => { this.beishu = targetSpeed; this._controller.view.beisuLabel.string = `x${this.beishu}`; }) .start(); } // 显示下一条旁白 private showNextPangbai(juqingCfg: any) { const pangbaiTexts = juqingCfg.startpangbai?.map(item => LocalizationManager.instance.get(item)) || []; if (this.pangbaiIndex < pangbaiTexts.length) { const pangbaiLabel = this._controller._pangbaiLabel; pangbaiLabel.node.active = true; pangbaiLabel.string = pangbaiTexts[this.pangbaiIndex]; this.pangbaiIndex++; } else { this._controller._pangbaiLabel.node.active = false; this.showNextZimu(juqingCfg) } } // 显示下一条字幕 private showNextZimu(juqingCfg: any) { const zimuTexts = juqingCfg.zimu?.map(item => LocalizationManager.instance.get(item)) || []; if (this.zimuIndex < zimuTexts.length) { const zimuLabel = this._controller._zimuLabel; zimuLabel.node.active = true; zimuLabel.string = zimuTexts[this.zimuIndex]; this.zimuIndex++; } else { this._controller._zimuLabel.node.active = false; this.showEndPangbai(juqingCfg); } } // 显示结束旁白 private showEndPangbai(juqingCfg: any) { const eddpangbaiTexts = juqingCfg.endpangbai?.map(item => LocalizationManager.instance.get(item)) || []; if (this.eddpangbaiIndex < eddpangbaiTexts.length) { const eddpangbaiLabel = this._controller._pangbaiLabel; eddpangbaiLabel.node.active = true; eddpangbaiLabel.string = eddpangbaiTexts[this.eddpangbaiIndex]; this.eddpangbaiIndex++; this.isEndPangbaiShown = true; } else { this._controller._pangbaiLabel.node.active = false; } } // 处理最终章节逻辑 private handleFinalChapter(changjingCfg: any) { // 首次观看时才显示奖励弹窗 const watchedEpisodes = this._controller.mainModel.gameData.juqingData.episodeStoryMap[changjingCfg.gushiid] || []; if (!watchedEpisodes.includes(this.juqingId)) { const rewardDatas = changjingCfg.rewardDatas; if (rewardDatas && rewardDatas.length > 0) { const rewardList = [{ items: rewardDatas }]; this._pendingRemoval = this.juqingId; ProxyRewards.Open((ctrl) => { (ctrl as RewardsController).onRewards(rewardList); ctrl.onClose = () => { if (this._pendingRemoval !== null) { this.clearAll(); this._pendingRemoval = null; this._controller._changjingBg.node.active = false; } oops.message.dispatchEvent(GameEvent.RefreshJuJiList); }; }); } else { this.clearAll(); oops.message.dispatchEvent(GameEvent.RefreshJuJiList); } } else { this.clearAll(); this._controller._changjingBg.node.active = false; oops.message.dispatchEvent(GameEvent.RefreshJuJiList); } // 记录已观看章节到对应故事 if (changjingCfg) { const gushiid = changjingCfg.gushiid; const episodeMap = this._controller.mainModel.gameData.juqingData.episodeStoryMap; if (!episodeMap[gushiid]) { episodeMap[gushiid] = []; } if (!episodeMap[gushiid].includes(this.juqingId)) { episodeMap[gushiid].push(this.juqingId); this._controller.mainModel.saveMainData(); } } // 消耗能量 const episodeCfg = DataCache.tables.TbJuQingZhangJie.get(this.zhangjieId); this._controller.mainModel.consumeEnergyItem(episodeCfg.xiaohaonum); } // 移除剧情特效 removeEffect(zhangjieId: number) { if (this._effectMap.has(zhangjieId)) { let effNode = this._effectMap.get(zhangjieId); EffectManager.instance.put(effNode); this._effectMap.delete(zhangjieId); // 清除旧事件监听 this._controller.view.BeishuButton.unRegAll(); } } // 清除所有剧情特效 clearAll() { this._effectMap.forEach((node) => { node.removeFromParent(); // 从父节点移除 node.destroy(); // 销毁节点 }); this._effectMap.clear(); this._controller.audioManager.stopMusic(); // 重置所有状态 this.isEndPangbaiShown = false; this.pangbaiIndex = 0; this.zimuIndex = 0; this.eddpangbaiIndex = 0; // 取消按钮事件注册 this._controller.view.BtnTuiChu.unRegAll(); this._controller.view.BeishuButton.unRegAll(); } })(); private onItemRender(index: number, item: Node) { let ctrl = item.getComponent(JuQing_ZhangJieItemController); if (!ctrl.view) { ctrl.Setup(); } const zhangjieData = this.zhangjiefgList[index]; ctrl.onInitView(zhangjieData, this); const playButton = ctrl.view.TiLiButton; if (playButton && this.juQing_ZhangJieModel.checkZhangJieUnlockCondition(zhangjieData.id)) { playButton.reg(() => { const episodeCfg = DataCache.tables.TbJuQingZhangJie.get(zhangjieData.id); if (this.mainModel.gameData.rewards[3] < episodeCfg.xiaohaonum) { return oops.gui.toast("货币不足"); } this._juqingEffects.addEffect(zhangjieData.id, zhangjieData.juqingid, 1, this.view.juqing); this.view.juqing.active = true; this.view.TitleBar.active = false; this.view.Bg_1.node.active = false; this.view.Bg_2.node.active = true; }); } } public updateUI() { this.view.juqing.active = false; this.view.Bg_2.node.active = false; this.view.TitleBar.active = true; this.view.Bg_1.node.active = true; // 重置文本标签 this._pangbaiLabel.string = ""; this._zimuLabel.string = ""; const juqingcfg = DataCache.tables.TbJuQing.get(this._gushiId); const maxLength = 61; const storyText = LocalizationManager.instance.get(juqingcfg.gushi) || '未命名'; const displayText = storyText.length > maxLength ? storyText.slice(0, maxLength) + '...' : storyText; this.view.jianjieLabel.string = `剧情简介: ${displayText}`; this.view.titleNameLabel.string = LocalizationManager.instance.get(juqingcfg.gushiname) || '未命名'; // 更新观看进度 const watchedCount = this.juQing_ZhangJieModel.getWatchedEpisodesCountByStory(this._gushiId); const totalCount = this.zhangjiefgList.length; this.view.jinduLabel.string = `观看进度: ${watchedCount}/${totalCount}`; // 图标 let iconPath = ResHelper.getJuQingPath(juqingcfg.icon); LocalizationManager.instance.setSpriteFrame(this.view.icon, iconPath); } }那这个功能怎么实现音频变速
05-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值