设置页、弹窗逻辑、跳转逻辑

视频播放逻辑优化
This commit is contained in:
2025-09-11 00:03:22 +08:00
parent a6b15778a8
commit 7dedbf124c
24 changed files with 2338 additions and 1381 deletions
+333 -245
View File
@@ -1,269 +1,357 @@
import { _decorator, instantiate, isValid, Label, Node,VideoClip, Sprite, UITransform, Vec3, VideoPlayer, view } from 'cc';
import Utils from '../../Main/Common/Utils';
import { InnerMsgCode } from '../../Main/Config/InnerMsgCode';
import li_BaseView from '../../Main/Common/li_BaseView';
import ResManager from '../../Main/Manager/ResManager';
import GlobalValue, { VideoRoleType } from '../../Main/Common/GlobalValue';
import { SDKManager } from '../../Main/Channel/SDKManager';
import { BgVideo } from '../../Main/Channel/BgVideo';
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')
@ccclass("SceneBgVideoLayer")
export class SceneBgVideoLayer extends li_BaseView {
private _nodeTab: any = {};
private _data;
private _nodeTab: any = {};
private _data;
static handle: SceneBgVideoLayer | null = null;
static handle: SceneBgVideoLayer | null = null;
private remoteLoopPath: string = "" //远程循环路径
private curVideoType: VideoRoleType = VideoRoleType.None;
private sceneBg: Sprite = null;
private videoInited: boolean = false; //视频是否初始化完成
private vpWait: BgVideo | null = null; //播表情视频时暂停的背景视频
private emoReady: BgVideo | null = null; //已准备好播放的表情
private videoPlayer: VideoPlayer = null;
private isPlaying: boolean = false;
private currentVideoData: any = null;
private videoPlayer: VideoPlayer = 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;
}
/**获取videoplayer副本 */
getVideoClone() {
let vp = instantiate(this._nodeTab.videoRole)
this.node.addChild(vp)
let bv = vp.getComponent(BgVideo)!
return bv
/**初始化视频事件监听 */
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 loop 是否循环播放
*/
playVideo(path: string, loop: boolean = false) {
if (!this.videoPlayer) {
console.error("SceneBgVideoLayer: VideoPlayer未初始化");
return;
}
//----重写父类接口---------------------------------------
onLoadCT() {
this.registerListenner();
Utils.parseNode(this.node, this._nodeTab)
this.sceneBg = this._nodeTab.sceneBg.getComponent(Sprite)!;
this.videoPlayer = this._nodeTab.videoRole.getComponent(VideoPlayer);
if (GlobalValue.NpcVideoMod) {
this.setVideoInited(true, true)
// 加载本地视频资源
ResManager.I.changeBundleVideo(
this.videoPlayer,
path,
"Girls",
(res: VideoClip) => {
this.videoPlayer.loop = loop;
this.videoPlayer.play();
this.isPlaying = true;
console.log(`SceneBgVideoLayer: 播放视频 ${path}, 循环: ${loop}`);
}
);
}
/**
* 切换视频(停止当前视频并播放新视频)
* @param path 视频路径
* @param loop 是否循环播放
*/
switchVideo(path: string, loop: boolean = false) {
this.stop();
this.playVideo(path, loop);
}
/**
* 暂停视频
*/
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 width 宽度
* @param height 高度
*/
setVideoSize(width: number, height: number) {
if (this.videoPlayer) {
const uiTransform = this.videoPlayer.node.getComponent(UITransform);
if (uiTransform) {
uiTransform.setContentSize(width, height);
console.log(`SceneBgVideoLayer: 设置视频尺寸 ${width}x${height}`);
}
}
}
/**
* 设置视频位置
* @param x X坐标
* @param y Y坐标
* @param z Z坐标
*/
setVideoPosition(x: number, y: number, z: number = 0) {
if (this.videoPlayer) {
this.videoPlayer.node.setPosition(x, y, z);
console.log(`SceneBgVideoLayer: 设置视频位置 (${x}, ${y}, ${z})`);
}
}
/**
* 设置视频世界位置
* @param x X坐标
* @param y Y坐标
* @param z Z坐标
*/
setVideoWorldPosition(x: number, y: number, z: number = 0) {
if (this.videoPlayer) {
this.videoPlayer.node.setWorldPosition(x, y, z);
console.log(`SceneBgVideoLayer: 设置视频世界位置 (${x}, ${y}, ${z})`);
}
}
/**
* 设置视频锚点
* @param anchorX X轴锚点 (0-1)
* @param anchorY Y轴锚点 (0-1)
*/
setVideoAnchor(anchorX: number, anchorY: number) {
if (this.videoPlayer) {
const uiTransform = this.videoPlayer.node.getComponent(UITransform);
if (uiTransform) {
uiTransform.setAnchorPoint(anchorX, anchorY);
console.log(`SceneBgVideoLayer: 设置视频锚点 (${anchorX}, ${anchorY})`);
}
}
}
/**
* 设置视频缩放
* @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.setPosition(position);
}
SceneBgVideoLayer.handle = this;
}
openUIDataCT(data: any): void {
this._data = data
}
console.log(`SceneBgVideoLayer: 自适应填充区域,缩放: ${scale}`);
return true;
}
return false;
};
registerListenner() {
Utils.addInnerEL(InnerMsgCode.SimplePlayVide,this,this.playLocalLoopVideo);
Utils.addInnerEL(InnerMsgCode.SceneLayerBgUp, this, this.resiveBgUp)
Utils.addInnerEL(InnerMsgCode.BgVideo_Ready, this, this.resiveBgVideoReady)
Utils.addInnerEL(InnerMsgCode.BgVideo_End, this, this.resiveBgVideoEnd)
}
//刷新场景背景消息
resiveBgUp(data) {
if (!GlobalValue.NpcVideoMod) {
return
}
if (data) {
if (data.videoPath) {
console.log("bgvideo 收到播放视频消息:", data)
if (data.videoType == VideoRoleType.Idle) {
this.playLoopVideo(data.videoPath, false)
} else {
this.playOnceVideo(data.videoPath)
}
}
if (!this.videoInited && data.bgPath) {
ResManager.I.changeBundleSpriteFrame(this.sceneBg, data.bgPath, "Raw", ()=>{
//调整背景图适配
Utils.adjustBgPixelRatio(this.sceneBg.node, 1)
})
}
}
}
/**视频准备好消息 */
resiveBgVideoReady(data:any) {
if (!this.videoInited) {
this.setVideoInited(true)
}
if (data.compo) {
if (data.compo.vtype == VideoRoleType.emo) {
this.setEmoReadyAudio(data.compo)
if (this.curVideoType == VideoRoleType.emo) {
this.doPlayEmoReadyAudio()
}
} else if (data.compo.vtype == VideoRoleType.Idle) {
this.curVideoType = VideoRoleType.Idle;
}
}
}
/**视频播放完毕消息 */
resiveBgVideoEnd(data:any) {
if (data.compo) {
if (data.compo.vtype == VideoRoleType.emo) {
// this.playLoopVideo(this.remoteLoopPath, true)
this.doEmoFinish()
} else if (data.compo.vtype == VideoRoleType.Idle) {
//主视频播完后,检测一下有没有要播的表情视频
if (this.doPlayEmoReadyAudio()) {
this.setBgAudioPause(data.compo)
}
}
}
}
playLocalLoopVideo(data:any) {
ResManager.I.changeBundleVideo(this.videoPlayer,data.path,"Chat18x",(res:VideoClip)=>{
this.videoPlayer.play();
// 移除之前的事件监听器,避免重复绑定
this.videoPlayer.node.off(VideoPlayer.EventType.READY_TO_PLAY, this.onVideoReadyToPlay, this);
// 添加视频准备完成事件监听
this.videoPlayer.node.on(VideoPlayer.EventType.READY_TO_PLAY, this.onVideoReadyToPlay, this);
// 保存当前数据供回调使用
this.currentVideoData = data;
// 也立即尝试调整(以防已经准备好)
this.adjustVideoToFillFrame(data.size, data.bgFrameNode);
});
}
private currentVideoData: any = null;
private onVideoReadyToPlay = () => {
if (this.currentVideoData) {
this.adjustVideoToFillFrame(this.currentVideoData.size, this.currentVideoData.bgFrameNode);
}
}
adjustVideoToFillFrame(targetSize: any, bgFrameNode?: Node) {
if (!this.videoPlayer) return;
const tryAdjust = () => {
let uiT: UITransform = this.videoPlayer.node.getComponent(UITransform);
const videoSize = uiT.contentSize;
console.log('Video size:', videoSize, 'Target size:', targetSize);
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);
console.log(`Video scaling: scaleX=${scaleX}, scaleY=${scaleY}, final scale=${scale}`);
this.videoPlayer.node.setScale(new Vec3(scale, scale, 1));
// 只有传入bgFrameNode时才调整位置
if (bgFrameNode && isValid(bgFrameNode) && bgFrameNode.position) {
this.videoPlayer.node.setPosition(
bgFrameNode.position.x,
bgFrameNode.position.y,
bgFrameNode.position.z
);
console.log(`Video positioned to bgFrame center: ${bgFrameNode.position}`);
}
return true;
}
return false;
};
// 立即尝试一次
// 立即尝试一次
if (!tryAdjust()) {
// 如果失败,延迟尝试
this.scheduleOnce(() => {
if (!tryAdjust()) {
// 如果失败,延迟尝试
this.scheduleOnce(() => {
if (!tryAdjust()) {
// 再次延迟尝试
this.scheduleOnce(() => {
tryAdjust();
}, 0.5);
}
}, 0.1);
this.scheduleOnce(() => {
tryAdjust();
}, 0.5);
}
}, 0.1);
}
}
/**播放循环视频 */
playLoopVideo(path: string, force = false) {
if (this.remoteLoopPath == path && !force) {
return
}
console.log("bgvideo 播放循环视频", path)
this.remoteLoopPath = path
SDKManager.PlayBgAudio(path, VideoRoleType.Idle, true)
}
//================== 事件回调 ==================
/**播放单次视频 */
playOnceVideo(path: string) {
console.log("bgvideo 播放单次视频", path)
SDKManager.AddEmoAudio(path, VideoRoleType.emo, false)
}
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;
}
};
//设置视频是否初始化完成
setVideoInited(inited: boolean, force: boolean = false) {
if (this.videoInited == inited && !force) {
return
}
console.log("bgvideo setVideoInited", inited)
this.videoInited = inited
this._nodeTab.sceneBg.active = !inited
}
/**
* 视频准备完成回调(可重写)
*/
protected onVideoReady() {
// 由子类重写或外部监听
}
//设置暂停播放的主视频
setBgAudioPause(wait:BgVideo) {
console.log("bgvideo 主视频暂停播放")
this.vpWait = wait
this.vpWait.pauseVideo()
}
replayBgAudioPause() {
console.log("bgvideo 主视频继续播放")
if (this.vpWait) {
this.vpWait.replayVideo()
}
}
/**
* 视频播放完成回调(可重写)
*/
protected onVideoEnd() {
// 由子类重写或外部监听
}
//设置准备好要播放的表情视频
setEmoReadyAudio(au: BgVideo) {
console.log("bgvideo 设置ready视频", au)
if (this.emoReady) {
this.emoReady.recycleVideo()
}
this.emoReady = au;
this.emoReady.pauseVideo()
}
//移除准备好要播放的表情视频
removeEmoReadyAudio() {
console.log("bgvideo 移除ready视频")
if (this.emoReady) {
this.emoReady.recycleVideo()
}
this.emoReady = null
}
//播放准备好要播放的表情视频
doPlayEmoReadyAudio():boolean {
if (this.emoReady) {
console.log("bgvideo 播放ready视频")
this.emoReady.replayVideo()
this.emoReady.moveIn()
this.curVideoType = VideoRoleType.emo
return true
}
return false
}
//表情视频播放结束
doEmoFinish() {
console.log("bgvideo ready视频播放结束")
this.removeEmoReadyAudio()
this.replayBgAudioPause()
this.curVideoType = VideoRoleType.Idle
}
/**
* 视频播放错误回调(可重写)
*/
protected onVideoError() {
// 由子类重写或外部监听
}
//================== 兼容性方法 ==================
/**
* 播放本地循环视频(保留以保证兼容性)
* @deprecated 使用 playVideo(path, true) 替代
*/
playLocalLoopVideo(data: any) {
if (data?.path) {
this.playVideo(data.path, true);
// 保存当前数据供回调使用
this.currentVideoData = data;
// 如果有尺寸和位置信息,进行调整
if (data.size) {
this.adjustToFillArea(data.size, data.bgFrameNode?.position);
}
}
}
/**
* 调整视频填充框架(保留以保证兼容性)
* @deprecated 使用 adjustToFillArea 替代
*/
adjustVideoToFillFrame(targetSize: any, bgFrameNode?: Node) {
let position: Vec3 | undefined;
if (bgFrameNode && isValid(bgFrameNode) && bgFrameNode.position) {
position = bgFrameNode.position;
}
this.adjustToFillArea(targetSize, position);
}
//================== 其他方法 ==================
/**
* 获取当前播放状态
*/
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;
}
}