feat: 支持关卡配置分享
This commit is contained in:
@@ -14,8 +14,14 @@ export const API_ENDPOINTS = {
|
||||
USER_ASSETS_EARN: `${API_BASE}/user/assets/earn`,
|
||||
USER_GAME_DATA: `${API_BASE}/user/game-data`,
|
||||
LEVELS: `${API_BASE}/wechat-game/levels`,
|
||||
SHARE_CREATE: `${API_BASE}/share`,
|
||||
} as const;
|
||||
|
||||
/** 构建加入分享的 URL */
|
||||
export function getShareJoinUrl(code: string): string {
|
||||
return `${API_BASE}/share/${code}/join`;
|
||||
}
|
||||
|
||||
/** 积分操作原因 */
|
||||
export const POINT_REASONS = {
|
||||
HINT_UNLOCK: 'hint_unlock',
|
||||
|
||||
@@ -29,3 +29,29 @@ export interface GameData {
|
||||
user: { id: string; points: number };
|
||||
completedLevelIds: string[];
|
||||
}
|
||||
|
||||
/** 创建分享响应 */
|
||||
export interface CreateShareData {
|
||||
shareCode: string;
|
||||
title: string;
|
||||
levelCount: number;
|
||||
}
|
||||
|
||||
/** 分享关卡数据 */
|
||||
export interface ShareLevelData {
|
||||
id: string;
|
||||
level: number;
|
||||
imageUrl: string;
|
||||
answer: string;
|
||||
hint1: string;
|
||||
hint2: string;
|
||||
hint3: string;
|
||||
sortOrder: number;
|
||||
}
|
||||
|
||||
/** 加入分享响应 */
|
||||
export interface JoinShareData {
|
||||
shareCode: string;
|
||||
title: string;
|
||||
levels: ShareLevelData[];
|
||||
}
|
||||
|
||||
167
assets/scripts/utils/ShareManager.ts
Normal file
167
assets/scripts/utils/ShareManager.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import { SpriteFrame, Texture2D, ImageAsset, assetManager } from 'cc';
|
||||
import { HttpUtil } from './HttpUtil';
|
||||
import { WxSDK } from './WxSDK';
|
||||
import { API_ENDPOINTS, getShareJoinUrl, API_TIMEOUT } from '../config/ApiConfig';
|
||||
import { ApiEnvelope, CreateShareData, JoinShareData, ShareLevelData } from '../types/ApiTypes';
|
||||
import { RuntimeLevelConfig } from '../types/LevelTypes';
|
||||
|
||||
/**
|
||||
* 分享管理器
|
||||
* 负责创建分享、加入分享、缓存分享关卡数据
|
||||
*/
|
||||
export class ShareManager {
|
||||
private static _instance: ShareManager | null = null;
|
||||
|
||||
/** 分享模式的关卡数据(null 表示正常模式) */
|
||||
private _shareLevels: RuntimeLevelConfig[] | null = null;
|
||||
|
||||
/** API 返回的原始关卡数据(保留 imageUrl 用于懒加载) */
|
||||
private _shareApiLevels: ShareLevelData[] = [];
|
||||
|
||||
private _shareTitle: string = '';
|
||||
private _shareCode: string | null = null;
|
||||
|
||||
/** 图片缓存:URL -> SpriteFrame */
|
||||
private _imageCache: Map<string, SpriteFrame> = new Map();
|
||||
|
||||
static get instance(): ShareManager {
|
||||
if (!this._instance) {
|
||||
this._instance = new ShareManager();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private constructor() {}
|
||||
|
||||
get isShareMode(): boolean {
|
||||
return this._shareLevels !== null && this._shareLevels.length > 0;
|
||||
}
|
||||
|
||||
async createShare(title: string, levelIds: string[]): Promise<string | null> {
|
||||
try {
|
||||
const response = await HttpUtil.post<ApiEnvelope<CreateShareData>>(
|
||||
API_ENDPOINTS.SHARE_CREATE,
|
||||
{ title, levelIds },
|
||||
API_TIMEOUT.DEFAULT,
|
||||
);
|
||||
|
||||
if (!response.success || !response.data) {
|
||||
console.error('[ShareManager] 创建分享失败:', response.message);
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.data.shareCode;
|
||||
} catch (err) {
|
||||
console.error('[ShareManager] 创建分享异常:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async joinShare(code: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await HttpUtil.post<ApiEnvelope<JoinShareData>>(
|
||||
getShareJoinUrl(code),
|
||||
{},
|
||||
API_TIMEOUT.DEFAULT,
|
||||
);
|
||||
|
||||
if (!response.success || !response.data) {
|
||||
console.error('[ShareManager] 加入分享失败:', response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
const { shareCode, title, levels } = response.data;
|
||||
this._shareCode = shareCode;
|
||||
this._shareTitle = title;
|
||||
this._shareApiLevels = levels;
|
||||
|
||||
const runtimeLevels: RuntimeLevelConfig[] = levels.map((level) => ({
|
||||
id: level.id,
|
||||
name: `第${level.level}关`,
|
||||
spriteFrame: null,
|
||||
clue1: level.hint1,
|
||||
clue2: level.hint2,
|
||||
clue3: level.hint3,
|
||||
answer: level.answer,
|
||||
}));
|
||||
|
||||
// 预加载首关图片
|
||||
if (levels.length > 0) {
|
||||
const sf = await this._loadImage(levels[0].imageUrl);
|
||||
if (sf) {
|
||||
runtimeLevels[0].spriteFrame = sf;
|
||||
}
|
||||
}
|
||||
|
||||
this._shareLevels = runtimeLevels;
|
||||
console.log(`[ShareManager] 加入分享成功: ${title}, ${levels.length} 关`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error('[ShareManager] 加入分享异常:', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async ensureShareLevelReady(index: number): Promise<RuntimeLevelConfig | null> {
|
||||
if (!this._shareLevels || index < 0 || index >= this._shareLevels.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const config = this._shareLevels[index];
|
||||
if (config.spriteFrame) {
|
||||
return config;
|
||||
}
|
||||
|
||||
const apiLevel = this._shareApiLevels[index];
|
||||
if (apiLevel?.imageUrl) {
|
||||
const sf = await this._loadImage(apiLevel.imageUrl);
|
||||
if (sf) {
|
||||
config.spriteFrame = sf;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
getShareLevelCount(): number {
|
||||
return this._shareLevels?.length ?? 0;
|
||||
}
|
||||
|
||||
triggerWxShare(title: string, shareCode: string): void {
|
||||
WxSDK.shareAppMessage({
|
||||
title: title || '来挑战我出的谐音梗吧!',
|
||||
query: `shareCode=${shareCode}`,
|
||||
});
|
||||
}
|
||||
|
||||
clearShareMode(): void {
|
||||
this._shareLevels = null;
|
||||
this._shareApiLevels = [];
|
||||
this._shareTitle = '';
|
||||
this._shareCode = null;
|
||||
this._imageCache.clear();
|
||||
}
|
||||
|
||||
private _loadImage(url: string): Promise<SpriteFrame | null> {
|
||||
const cached = this._imageCache.get(url);
|
||||
if (cached) {
|
||||
return Promise.resolve(cached);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
assetManager.loadRemote<ImageAsset>(url, (err, imageAsset) => {
|
||||
if (err) {
|
||||
console.error('[ShareManager] 加载图片失败:', url, err);
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
const texture = new Texture2D();
|
||||
texture.image = imageAsset;
|
||||
const spriteFrame = new SpriteFrame();
|
||||
spriteFrame.texture = texture;
|
||||
this._imageCache.set(url, spriteFrame);
|
||||
resolve(spriteFrame);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
9
assets/scripts/utils/ShareManager.ts.meta
Normal file
9
assets/scripts/utils/ShareManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "6044a8d5-305c-4b68-8abd-6bde3da0505c",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -216,4 +216,24 @@ export class WxSDK {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 从启动参数中获取分享码
|
||||
* @returns 分享码,不存在则返回 null
|
||||
*/
|
||||
static getShareCodeFromLaunch(): string | null {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return null;
|
||||
|
||||
try {
|
||||
const options = wxApi.getLaunchOptionsSync();
|
||||
if (options?.query?.shareCode) {
|
||||
console.log('[WxSDK] 检测到分享码:', options.query.shareCode);
|
||||
return options.query.shareCode;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[WxSDK] 获取启动参数失败:', err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user