233 lines
6.1 KiB
TypeScript
233 lines
6.1 KiB
TypeScript
import { _decorator, Node, Label, AudioClip, AudioSource, view, UITransform, Size, ProgressBar } from 'cc';
|
||
import { BaseModal } from 'db://assets/scripts/core/BaseModal';
|
||
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
|
||
const { ccclass, property } = _decorator;
|
||
|
||
/**
|
||
* PassModal 回调接口
|
||
*/
|
||
export interface PassModalCallbacks {
|
||
/** 点击下一关回调 */
|
||
onNextLevel?: () => void;
|
||
/** 点击分享回调 */
|
||
onShare?: () => void;
|
||
}
|
||
|
||
export interface PassModalTitleInfo {
|
||
titleText?: string;
|
||
nextTitleProgress?: number;
|
||
progressText?: string;
|
||
}
|
||
|
||
interface PassModalParams {
|
||
levelIndex?: number;
|
||
titleInfo?: PassModalTitleInfo;
|
||
}
|
||
|
||
/**
|
||
* 通关弹窗组件
|
||
* 继承 BaseModal,显示通关成功弹窗,提供"下一关"和"分享给好友"两个按钮
|
||
*/
|
||
@ccclass('PassModal')
|
||
export class PassModal extends BaseModal {
|
||
/** 静态常量:弹窗层级 */
|
||
public static readonly MODAL_Z_INDEX = 999;
|
||
|
||
/** 下一关按钮 */
|
||
@property(Node)
|
||
nextLevelButton: Node | null = null;
|
||
|
||
/** 分享按钮 */
|
||
@property(Node)
|
||
shareButton: Node | null = null;
|
||
|
||
/** 称号文字 */
|
||
@property(Label)
|
||
titleLevelLabel: Label | null = null;
|
||
|
||
/** 距离下一个称号的进度 */
|
||
@property(ProgressBar)
|
||
titleProgressBar: ProgressBar | null = null;
|
||
|
||
/** 进度提示文案 */
|
||
@property(Label)
|
||
progressLabel: Label | null = null;
|
||
|
||
/** 通关音效 */
|
||
@property(AudioClip)
|
||
successAudio: AudioClip | null = null;
|
||
|
||
/** 回调函数 */
|
||
private _callbacks: PassModalCallbacks = {};
|
||
|
||
/** 缓存的屏幕尺寸 */
|
||
private _screenSize: Size | null = null;
|
||
|
||
/** 称号展示数据 */
|
||
private _titleInfo: PassModalTitleInfo = {
|
||
titleText: '冷场小白1级',
|
||
nextTitleProgress: 0,
|
||
progressText: '还差3题获得冷场小白2级'
|
||
};
|
||
|
||
setParams(params: PassModalParams): void {
|
||
super.setParams(params);
|
||
|
||
if (params?.titleInfo) {
|
||
this.setTitleInfo(params.titleInfo);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置回调函数
|
||
*/
|
||
setCallbacks(callbacks: PassModalCallbacks): void {
|
||
this._callbacks = callbacks;
|
||
}
|
||
|
||
/**
|
||
* 设置称号体系展示数据
|
||
*/
|
||
setTitleInfo(titleInfo: PassModalTitleInfo): void {
|
||
this._titleInfo = {
|
||
...this._titleInfo,
|
||
...titleInfo
|
||
};
|
||
this._updateTitleInfo();
|
||
}
|
||
|
||
/**
|
||
* 页面首次加载时调用
|
||
*/
|
||
onViewLoad(): void {
|
||
console.log('[PassModal] onViewLoad');
|
||
this._bindButtonEvents();
|
||
}
|
||
|
||
/**
|
||
* 页面每次显示时调用
|
||
*/
|
||
onViewShow(): void {
|
||
super.onViewShow();
|
||
this._updateWidget();
|
||
this._updateTitleInfo();
|
||
this._playSuccessSound();
|
||
}
|
||
|
||
/**
|
||
* 页面销毁时调用
|
||
*/
|
||
onViewDestroy(): void {
|
||
this._unbindButtonEvents();
|
||
}
|
||
|
||
/**
|
||
* 设置弹窗尺寸为全屏
|
||
* 动态实例化后,手动设置节点尺寸覆盖整个屏幕
|
||
*/
|
||
private _updateWidget(): void {
|
||
// 缓存屏幕尺寸,避免重复计算
|
||
if (!this._screenSize) {
|
||
this._screenSize = view.getVisibleSize();
|
||
}
|
||
|
||
const uiTransform = this.node.getComponent(UITransform);
|
||
if (uiTransform) {
|
||
uiTransform.setContentSize(this._screenSize.width, this._screenSize.height);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 绑定按钮事件
|
||
*/
|
||
private _bindButtonEvents(): void {
|
||
if (this.nextLevelButton) {
|
||
this.nextLevelButton.on(Node.EventType.TOUCH_END, this._onNextLevelClick, this);
|
||
}
|
||
if (this.shareButton) {
|
||
this.shareButton.on(Node.EventType.TOUCH_END, this._onShareClick, this);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解除按钮事件绑定
|
||
*/
|
||
private _unbindButtonEvents(): void {
|
||
// 节点可能在销毁过程中已被置空,需要检查 isValid
|
||
if (this.nextLevelButton && this.nextLevelButton.isValid) {
|
||
this.nextLevelButton.off(Node.EventType.TOUCH_END, this._onNextLevelClick, this);
|
||
}
|
||
if (this.shareButton && this.shareButton.isValid) {
|
||
this.shareButton.off(Node.EventType.TOUCH_END, this._onShareClick, this);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 播放通关音效
|
||
*/
|
||
private _playSuccessSound(): void {
|
||
if (!this.successAudio) {
|
||
return;
|
||
}
|
||
|
||
const audioSource = this.node.getComponent(AudioSource);
|
||
if (audioSource) {
|
||
audioSource.playOneShot(this.successAudio);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新称号体系核心变量
|
||
*/
|
||
private _updateTitleInfo(): void {
|
||
if (this.titleLevelLabel && this._titleInfo.titleText !== undefined) {
|
||
this.titleLevelLabel.string = this._titleInfo.titleText;
|
||
}
|
||
|
||
if (this.titleProgressBar && this._titleInfo.nextTitleProgress !== undefined) {
|
||
this.titleProgressBar.progress = this._normalizeProgress(this._titleInfo.nextTitleProgress);
|
||
}
|
||
|
||
if (this.progressLabel && this._titleInfo.progressText !== undefined) {
|
||
this.progressLabel.string = this._titleInfo.progressText;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 规范化进度值
|
||
* 九宫格 Bar 的 Left+Right border = 240px,totalLength = 925px
|
||
* 当 width < 240px 时圆角会畸变,因此 progress > 0 时强制最小值
|
||
*/
|
||
private _normalizeProgress(progress: number): number {
|
||
if (!Number.isFinite(progress) || progress <= 0) {
|
||
return 0;
|
||
}
|
||
|
||
const MIN_PROGRESS = 240 / 925;
|
||
return Math.max(MIN_PROGRESS, Math.min(1, progress));
|
||
}
|
||
|
||
/**
|
||
* 下一关按钮点击
|
||
*/
|
||
private _onNextLevelClick(): void {
|
||
console.log('[PassModal] 点击下一关');
|
||
this._callbacks.onNextLevel?.();
|
||
}
|
||
|
||
/**
|
||
* 分享按钮点击
|
||
*/
|
||
private _onShareClick(): void {
|
||
console.log('[PassModal] 点击分享');
|
||
|
||
// 调用微信分享
|
||
WxSDK.shareAppMessage({
|
||
title: '快来一起玩这款游戏吧',
|
||
query: `level=${this._params?.levelIndex ?? 1}`
|
||
});
|
||
|
||
this._callbacks.onShare?.();
|
||
}
|
||
}
|