import { _decorator, isValid, Node, VideoClip, UITransform, Vec3, VideoPlayer, Size, } from "cc"; import Utils from "../../Main/Common/Utils"; import li_BaseView from "../../Main/Common/li_BaseView"; import ResManager from "../../Main/Manager/ResManager"; const { ccclass, property } = _decorator; //场景背景层 - 视频模式 @ccclass("SceneBgVideoLayer") export class SceneBgVideoLayer extends li_BaseView { private _nodeTab: any = {}; private _data; static handle: SceneBgVideoLayer | null = null; private videoPlayer: VideoPlayer = null; private isPlaying: boolean = false; private currentVideoData: any = null; //----重写父类接口--------------------------------------- onLoadCT() { Utils.parseNode(this.node, this._nodeTab); this.videoPlayer = this._nodeTab.videoPlayer.getComponent(VideoPlayer); if (!this.videoPlayer) { console.error("SceneBgVideoLayer: video节点未找到或没有VideoPlayer组件"); } this.initVideoEvents(); SceneBgVideoLayer.handle = this; } openUIDataCT(data: any): void { this._data = data; } /**初始化视频事件监听 */ private initVideoEvents() { if (!this.videoPlayer) return; // 移除之前的事件监听器,避免重复绑定 this.videoPlayer.node.off( VideoPlayer.EventType.READY_TO_PLAY, this.onVideoReadyToPlay, this ); //this.videoPlayer.node.off(VideoPlayer.EventType.VIDEO_PLAYER_EVENT, this.onVideoEvent, this); // 添加新的事件监听 this.videoPlayer.node.on( VideoPlayer.EventType.READY_TO_PLAY, this.onVideoReadyToPlay, this ); // this.videoPlayer.node.on(VideoPlayer.EventType.VIDEO_PLAYER_EVENT, this.onVideoEvent, this); } //================== 公共 API 方法 ================== /** * 播放视频 - 统一的视频播放接口 * @param path 视频路径 * @param options 可选配置项 * @param options.loop 是否循环播放,默认true * @param options.size 视频尺寸 {width, height} * @param options.position 视频位置 {x, y, z} * @param options.scale 视频缩放值 * @param options.autoFill 是否自动填充到指定尺寸 */ playVideo( path: string, options?: { loop?: boolean; size?: { width: number; height: number } | Size; position?: { x: number; y: number; z?: number } | Vec3; scale?: number | Vec3; } ) { if (!this.videoPlayer) { console.error("SceneBgVideoLayer: VideoPlayer未初始化"); return; } // 默认参数 const config = { loop: options?.loop ?? true, size: options?.size, position: options?.position, scale: options?.scale, }; // 先停止当前视频 if (this.isPlaying) { this.stop(); } // 加载本地视频资源 ResManager.I.changeBundleVideo( this.videoPlayer, path, "Girls", (res: VideoClip) => { this.videoPlayer.loop = config.loop; // 设置锚点为中心,确保位置对齐 const uiTransform = this.videoPlayer.node.getComponent(UITransform); if (uiTransform) { uiTransform.setAnchorPoint(0.5, 0.5); } // 应用位置设置(使用世界坐标) if (config.position) { const pos = config.position; if (pos instanceof Vec3) { this.videoPlayer.node.setWorldPosition(pos); } else { this.videoPlayer.node.setWorldPosition(pos.x, pos.y, pos.z || 0); } } // 如果传入了目标尺寸,计算并应用缩放 if (config.size && uiTransform) { // 获取视频的原始尺寸 const videoWidth = uiTransform.contentSize.width; const videoHeight = uiTransform.contentSize.height; if (videoWidth > 0 && videoHeight > 0) { const targetWidth = config.size instanceof Size ? config.size.width : config.size.width; const targetHeight = config.size instanceof Size ? config.size.height : config.size.height; // 计算缩放比例(填满整个区域) const scaleX = targetWidth / videoWidth; const scaleY = targetHeight / videoHeight; const scale = Math.max(scaleX, scaleY); this.videoPlayer.node.setScale(new Vec3(scale, scale, 1)); console.log(`SceneBgVideoLayer: 视频原始尺寸: ${videoWidth}x${videoHeight}, 目标尺寸: ${targetWidth}x${targetHeight}, 缩放: ${scale}`); } else { // 如果视频尺寸还未准备好,延迟重试 this.scheduleOnce(() => { if (config.size && uiTransform) { const videoWidth = uiTransform.contentSize.width; const videoHeight = uiTransform.contentSize.height; if (videoWidth > 0 && videoHeight > 0) { const targetWidth = config.size instanceof Size ? config.size.width : config.size.width; const targetHeight = config.size instanceof Size ? config.size.height : config.size.height; const scaleX = targetWidth / videoWidth; const scaleY = targetHeight / videoHeight; const scale = Math.max(scaleX, scaleY); this.videoPlayer.node.setScale(new Vec3(scale, scale, 1)); console.log(`SceneBgVideoLayer: (延迟) 视频原始尺寸: ${videoWidth}x${videoHeight}, 目标尺寸: ${targetWidth}x${targetHeight}, 缩放: ${scale}`); } } }, 0.1); } } // 如果显式传入了 scale 参数,覆盖自动计算的缩放 else if (config.scale !== undefined) { this.setVideoScale(config.scale); } this.videoPlayer.play(); this.isPlaying = true; console.log(`SceneBgVideoLayer: 播放视频 ${path}, 配置:`, config); } ); } /** * 暂停视频 */ pause() { if (this.videoPlayer && this.isPlaying) { this.videoPlayer.pause(); console.log("SceneBgVideoLayer: 暂停视频"); } } /** * 继续播放视频 */ resume() { if (this.videoPlayer && !this.videoPlayer.isPlaying) { this.videoPlayer.play(); console.log("SceneBgVideoLayer: 继续播放视频"); } } /** * 停止视频 */ stop() { if (this.videoPlayer) { this.videoPlayer.stop(); this.isPlaying = false; console.log("SceneBgVideoLayer: 停止视频"); } } /** * 设置视频缩放 * @param scale 缩放值(数字或Vec3) */ setVideoScale(scale: number | Vec3) { if (this.videoPlayer) { if (typeof scale === "number") { this.videoPlayer.node.setScale(new Vec3(scale, scale, 1)); console.log(`SceneBgVideoLayer: 设置视频缩放 ${scale}`); } else { this.videoPlayer.node.setScale(scale); console.log( `SceneBgVideoLayer: 设置视频缩放 (${scale.x}, ${scale.y}, ${scale.z})` ); } } } /** * 调整视频以填满指定区域 * @param targetSize 目标尺寸 * @param position 可选的位置 */ adjustToFillArea(targetSize: Size, position?: Vec3) { if (!this.videoPlayer) return; const tryAdjust = () => { const uiTransform = this.videoPlayer.node.getComponent(UITransform); if (!uiTransform) return false; const videoSize = uiTransform.contentSize; if (videoSize.width > 0 && videoSize.height > 0) { // 计算宽度和高度的缩放比例 const scaleX = targetSize.width / videoSize.width; const scaleY = targetSize.height / videoSize.height; // 选择较大的缩放比例以填满整个区域 const scale = Math.max(scaleX, scaleY); this.videoPlayer.node.setScale(new Vec3(scale, scale, 1)); if (position) { this.videoPlayer.node.setWorldPosition(position); } console.log(`SceneBgVideoLayer: 自适应填充区域,缩放: ${scale}`); return true; } return false; }; // 立即尝试一次 if (!tryAdjust()) { // 如果失败,延迟尝试 this.scheduleOnce(() => { if (!tryAdjust()) { this.scheduleOnce(() => { tryAdjust(); }, 0.5); } }, 0.1); } } //================== 事件回调 ================== private onVideoReadyToPlay = () => { console.log("SceneBgVideoLayer: 视频准备完成"); this.onVideoReady(); }; private onVideoEvent = (event: any, eventType: string) => { switch (eventType) { case "completed": console.log("SceneBgVideoLayer: 视频播放完成"); this.isPlaying = false; this.onVideoEnd(); break; case "error": console.error("SceneBgVideoLayer: 视频播放错误"); this.isPlaying = false; this.onVideoError(); break; } }; /** * 视频准备完成回调(可重写) */ protected onVideoReady() { // 由子类重写或外部监听 } /** * 视频播放完成回调(可重写) */ protected onVideoEnd() { // 由子类重写或外部监听 } /** * 视频播放错误回调(可重写) */ protected onVideoError() { // 由子类重写或外部监听 } //================== 其他方法 ================== /** * 获取当前播放状态 */ getIsPlaying(): boolean { return this.isPlaying; } /** * 获取VideoPlayer组件引用 */ getVideoPlayer(): VideoPlayer | null { return this.videoPlayer; } /** * 销毁时清理资源 */ onDestroy() { if (this.videoPlayer) { this.videoPlayer.node.off( VideoPlayer.EventType.READY_TO_PLAY, this.onVideoReadyToPlay, this ); //this.videoPlayer.node.off(VideoPlayer.EventType.VIDEO_PLAYER_EVENT, this.onVideoEvent, this); } SceneBgVideoLayer.handle = null; } }