feat: 支持新版的关卡页面
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,18 @@ export class PageLevel extends BaseView {
|
|||||||
@property(Node)
|
@property(Node)
|
||||||
mainImage: Node | null = null;
|
mainImage: Node | null = null;
|
||||||
|
|
||||||
|
@property(Node)
|
||||||
|
mainImage2: Node | null = null;
|
||||||
|
|
||||||
|
@property(Label)
|
||||||
|
image1DescLabel: Label | null = null;
|
||||||
|
|
||||||
|
@property(Label)
|
||||||
|
image2DescLabel: Label | null = null;
|
||||||
|
|
||||||
|
@property(Label)
|
||||||
|
punchlineLabel: Label | null = null;
|
||||||
|
|
||||||
@property(Node)
|
@property(Node)
|
||||||
tipsItem1: Node | null = null;
|
tipsItem1: Node | null = null;
|
||||||
|
|
||||||
@@ -268,8 +280,17 @@ export class PageLevel extends BaseView {
|
|||||||
this._isTimeUp = false;
|
this._isTimeUp = false;
|
||||||
this._countdown = 60;
|
this._countdown = 60;
|
||||||
|
|
||||||
// 设置主图
|
// 设置主图(图片1)
|
||||||
this.setMainImage(config.spriteFrame);
|
this.setMainImage(config.spriteFrame1);
|
||||||
|
|
||||||
|
// 设置图片2
|
||||||
|
this.setMainImage2(config.spriteFrame2);
|
||||||
|
|
||||||
|
// 设置图片描述
|
||||||
|
this.setImageDescriptions(config.image1Description, config.image2Description);
|
||||||
|
|
||||||
|
// 隐藏谐音梗说明(通关后才显示)
|
||||||
|
this.setPunchline(null);
|
||||||
|
|
||||||
// 设置线索1(默认解锁,如果有的话)
|
// 设置线索1(默认解锁,如果有的话)
|
||||||
if (config.clue1) {
|
if (config.clue1) {
|
||||||
@@ -618,7 +639,7 @@ export class PageLevel extends BaseView {
|
|||||||
// ========== 主图相关方法 ==========
|
// ========== 主图相关方法 ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置主图
|
* 设置主图(图片1)
|
||||||
*/
|
*/
|
||||||
private setMainImage(spriteFrame: SpriteFrame | null): void {
|
private setMainImage(spriteFrame: SpriteFrame | null): void {
|
||||||
if (!this.mainImage) return;
|
if (!this.mainImage) return;
|
||||||
@@ -626,7 +647,47 @@ export class PageLevel extends BaseView {
|
|||||||
const sprite = this.mainImage.getComponent(Sprite);
|
const sprite = this.mainImage.getComponent(Sprite);
|
||||||
if (sprite && spriteFrame) {
|
if (sprite && spriteFrame) {
|
||||||
sprite.spriteFrame = spriteFrame;
|
sprite.spriteFrame = spriteFrame;
|
||||||
console.log('[PageLevel] 设置主图');
|
console.log('[PageLevel] 设置主图1');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置图片2
|
||||||
|
*/
|
||||||
|
private setMainImage2(spriteFrame: SpriteFrame | null): void {
|
||||||
|
if (!this.mainImage2) return;
|
||||||
|
|
||||||
|
const sprite = this.mainImage2.getComponent(Sprite);
|
||||||
|
if (sprite && spriteFrame) {
|
||||||
|
sprite.spriteFrame = spriteFrame;
|
||||||
|
console.log('[PageLevel] 设置主图2');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置图片描述文本
|
||||||
|
*/
|
||||||
|
private setImageDescriptions(desc1: string | null, desc2: string | null): void {
|
||||||
|
if (this.image1DescLabel) {
|
||||||
|
this.image1DescLabel.string = desc1 ?? '';
|
||||||
|
}
|
||||||
|
if (this.image2DescLabel) {
|
||||||
|
this.image2DescLabel.string = desc2 ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置谐音梗说明(通关后展示,未通关时传 null 隐藏)
|
||||||
|
*/
|
||||||
|
private setPunchline(punchline: string | null): void {
|
||||||
|
if (!this.punchlineLabel) return;
|
||||||
|
|
||||||
|
if (punchline) {
|
||||||
|
this.punchlineLabel.node.active = true;
|
||||||
|
this.punchlineLabel.string = punchline;
|
||||||
|
} else {
|
||||||
|
this.punchlineLabel.node.active = false;
|
||||||
|
this.punchlineLabel.string = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,6 +880,11 @@ export class PageLevel extends BaseView {
|
|||||||
// 播放成功音效
|
// 播放成功音效
|
||||||
this.playSuccessSound();
|
this.playSuccessSound();
|
||||||
|
|
||||||
|
// 通关后展示谐音梗说明
|
||||||
|
if (this._currentConfig?.punchline) {
|
||||||
|
this.setPunchline(this._currentConfig.punchline);
|
||||||
|
}
|
||||||
|
|
||||||
const levelId = this._currentConfig?.id ?? '';
|
const levelId = this._currentConfig?.id ?? '';
|
||||||
const timeSpent = Math.max(0, Math.round((Date.now() - this._levelStartTime) / 1000));
|
const timeSpent = Math.max(0, Math.round((Date.now() - this._levelStartTime) / 1000));
|
||||||
|
|
||||||
|
|||||||
@@ -204,8 +204,8 @@ export class PagePreviewLevels extends BaseView {
|
|||||||
const levelCover = item.getChildByName('LevelCover');
|
const levelCover = item.getChildByName('LevelCover');
|
||||||
if (levelCover) {
|
if (levelCover) {
|
||||||
const sprite = levelCover.getComponent(Sprite);
|
const sprite = levelCover.getComponent(Sprite);
|
||||||
if (sprite && config.spriteFrame) {
|
if (sprite && config.spriteFrame1) {
|
||||||
sprite.spriteFrame = config.spriteFrame;
|
sprite.spriteFrame = config.spriteFrame1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -326,8 +326,8 @@ export class PageWriteLevels extends BaseView {
|
|||||||
const levelCover = item.getChildByName('LevelCover');
|
const levelCover = item.getChildByName('LevelCover');
|
||||||
if (levelCover) {
|
if (levelCover) {
|
||||||
const sprite = levelCover.getComponent(Sprite);
|
const sprite = levelCover.getComponent(Sprite);
|
||||||
if (sprite && config.spriteFrame) {
|
if (sprite && config.spriteFrame1) {
|
||||||
sprite.spriteFrame = config.spriteFrame;
|
sprite.spriteFrame = config.spriteFrame1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export interface ApiEnvelope<T> {
|
|||||||
export interface StaminaInfo {
|
export interface StaminaInfo {
|
||||||
/** 当前体力值(已计算恢复) */
|
/** 当前体力值(已计算恢复) */
|
||||||
current: number;
|
current: number;
|
||||||
/** 体力上限,固定为 5 */
|
/** 体力上限,固定为 50 */
|
||||||
max: number;
|
max: number;
|
||||||
/** 下一点体力恢复的时间(ISO 8601),满体力时为 null */
|
/** 下一点体力恢复的时间(ISO 8601),满体力时为 null */
|
||||||
nextRecoverAt: string | null;
|
nextRecoverAt: string | null;
|
||||||
@@ -50,8 +50,12 @@ export interface GameData {
|
|||||||
export interface LevelListItem {
|
export interface LevelListItem {
|
||||||
id: string;
|
id: string;
|
||||||
level: number;
|
level: number;
|
||||||
imageUrl: string;
|
image1Url: string;
|
||||||
|
image1Description: string | null;
|
||||||
|
image2Url: string;
|
||||||
|
image2Description: string | null;
|
||||||
answer: string | null;
|
answer: string | null;
|
||||||
|
punchline: string | null;
|
||||||
hint1: string | null;
|
hint1: string | null;
|
||||||
hint2: string | null;
|
hint2: string | null;
|
||||||
hint3: string | null;
|
hint3: string | null;
|
||||||
@@ -69,8 +73,12 @@ export interface LevelListData {
|
|||||||
export interface EnterLevelData {
|
export interface EnterLevelData {
|
||||||
id: string;
|
id: string;
|
||||||
level: number;
|
level: number;
|
||||||
imageUrl: string;
|
image1Url: string;
|
||||||
|
image1Description: string | null;
|
||||||
|
image2Url: string;
|
||||||
|
image2Description: string | null;
|
||||||
answer: string;
|
answer: string;
|
||||||
|
punchline: string | null;
|
||||||
hint1: string | null;
|
hint1: string | null;
|
||||||
hint2: string | null;
|
hint2: string | null;
|
||||||
hint3: string | null;
|
hint3: string | null;
|
||||||
@@ -95,8 +103,12 @@ export interface CreateShareData {
|
|||||||
export interface ShareLevelData {
|
export interface ShareLevelData {
|
||||||
id: string;
|
id: string;
|
||||||
level: number;
|
level: number;
|
||||||
imageUrl: string;
|
image1Url: string;
|
||||||
|
image1Description: string | null;
|
||||||
|
image2Url: string;
|
||||||
|
image2Description: string | null;
|
||||||
answer: string;
|
answer: string;
|
||||||
|
punchline: string | null;
|
||||||
hint1: string | null;
|
hint1: string | null;
|
||||||
hint2: string | null;
|
hint2: string | null;
|
||||||
hint3: string | null;
|
hint3: string | null;
|
||||||
|
|||||||
@@ -8,8 +8,16 @@ export interface ApiLevelData {
|
|||||||
id: string;
|
id: string;
|
||||||
/** 关卡序号 */
|
/** 关卡序号 */
|
||||||
level: number;
|
level: number;
|
||||||
/** 主图 URL */
|
/** 图片1 URL */
|
||||||
imageUrl: string;
|
image1Url: string;
|
||||||
|
/** 图片1 文本说明 */
|
||||||
|
image1Description: string | null;
|
||||||
|
/** 图片2 URL */
|
||||||
|
image2Url: string;
|
||||||
|
/** 图片2 文本说明 */
|
||||||
|
image2Description: string | null;
|
||||||
|
/** 谐音梗说明(仅通关后返回,未通关为 null) */
|
||||||
|
punchline: string | null;
|
||||||
/** 线索1(未通关时为 null) */
|
/** 线索1(未通关时为 null) */
|
||||||
hint1: string | null;
|
hint1: string | null;
|
||||||
/** 线索2(未通关时为 null) */
|
/** 线索2(未通关时为 null) */
|
||||||
@@ -47,8 +55,16 @@ export interface RuntimeLevelConfig {
|
|||||||
id: string;
|
id: string;
|
||||||
/** 关卡名称 */
|
/** 关卡名称 */
|
||||||
name: string;
|
name: string;
|
||||||
/** 主图 SpriteFrame(可能为 null 如果加载失败) */
|
/** 图片1 SpriteFrame(可能为 null 如果加载失败) */
|
||||||
spriteFrame: SpriteFrame | null;
|
spriteFrame1: SpriteFrame | null;
|
||||||
|
/** 图片2 SpriteFrame(可能为 null 如果加载失败) */
|
||||||
|
spriteFrame2: SpriteFrame | null;
|
||||||
|
/** 图片1 文本说明 */
|
||||||
|
image1Description: string | null;
|
||||||
|
/** 图片2 文本说明 */
|
||||||
|
image2Description: string | null;
|
||||||
|
/** 谐音梗说明 */
|
||||||
|
punchline: string | null;
|
||||||
/** 线索1(未通关时为 null,进入关卡后由 enter 接口获取) */
|
/** 线索1(未通关时为 null,进入关卡后由 enter 接口获取) */
|
||||||
clue1: string | null;
|
clue1: string | null;
|
||||||
/** 线索2(未通关时为 null) */
|
/** 线索2(未通关时为 null) */
|
||||||
|
|||||||
@@ -78,10 +78,11 @@ export class LevelDataManager {
|
|||||||
const firstLevel = apiData[0];
|
const firstLevel = apiData[0];
|
||||||
onProgress?.(0.3, '正在加载游戏必备资源...');
|
onProgress?.(0.3, '正在加载游戏必备资源...');
|
||||||
|
|
||||||
const spriteFrame = await this._loadImage(firstLevel.imageUrl);
|
const [spriteFrame1, spriteFrame2] = await Promise.all([
|
||||||
if (spriteFrame) {
|
this._loadImage(firstLevel.image1Url),
|
||||||
this._levelConfigs.set(0, this._createRuntimeConfig(firstLevel, spriteFrame));
|
this._loadImage(firstLevel.image2Url),
|
||||||
}
|
]);
|
||||||
|
this._levelConfigs.set(0, this._createRuntimeConfig(firstLevel, spriteFrame1, spriteFrame2));
|
||||||
|
|
||||||
console.log('[LevelDataManager] 初始化完成,第一关资源已加载');
|
console.log('[LevelDataManager] 初始化完成,第一关资源已加载');
|
||||||
onProgress?.(0.8, '游戏资源加载完成');
|
onProgress?.(0.8, '游戏资源加载完成');
|
||||||
@@ -245,15 +246,18 @@ export class LevelDataManager {
|
|||||||
console.log(`[LevelDataManager] 开始加载关卡 ${index} 资源...`);
|
console.log(`[LevelDataManager] 开始加载关卡 ${index} 资源...`);
|
||||||
|
|
||||||
const data = this._apiData[index];
|
const data = this._apiData[index];
|
||||||
const spriteFrame = await this._loadImage(data.imageUrl);
|
const [spriteFrame1, spriteFrame2] = await Promise.all([
|
||||||
|
this._loadImage(data.image1Url),
|
||||||
|
this._loadImage(data.image2Url),
|
||||||
|
]);
|
||||||
this._loadingLevels.delete(index);
|
this._loadingLevels.delete(index);
|
||||||
|
|
||||||
if (!spriteFrame) {
|
if (!spriteFrame1) {
|
||||||
console.error(`[LevelDataManager] 加载关卡 ${index} 图片失败`);
|
console.error(`[LevelDataManager] 加载关卡 ${index} 图片1失败`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = this._createRuntimeConfig(data, spriteFrame);
|
const config = this._createRuntimeConfig(data, spriteFrame1, spriteFrame2);
|
||||||
this._levelConfigs.set(index, config);
|
this._levelConfigs.set(index, config);
|
||||||
console.log(`[LevelDataManager] 关卡 ${index} 资源加载完成`);
|
console.log(`[LevelDataManager] 关卡 ${index} 资源加载完成`);
|
||||||
|
|
||||||
@@ -358,13 +362,18 @@ export class LevelDataManager {
|
|||||||
/**
|
/**
|
||||||
* 创建运行时关卡配置
|
* 创建运行时关卡配置
|
||||||
* @param data API 关卡数据
|
* @param data API 关卡数据
|
||||||
* @param spriteFrame 已加载的精灵帧
|
* @param spriteFrame1 已加载的图片1精灵帧
|
||||||
|
* @param spriteFrame2 已加载的图片2精灵帧
|
||||||
*/
|
*/
|
||||||
private _createRuntimeConfig(data: ApiLevelData, spriteFrame: SpriteFrame | null): RuntimeLevelConfig {
|
private _createRuntimeConfig(data: ApiLevelData, spriteFrame1: SpriteFrame | null, spriteFrame2: SpriteFrame | null): RuntimeLevelConfig {
|
||||||
return {
|
return {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
name: `第${data.level}关`,
|
name: `第${data.level}关`,
|
||||||
spriteFrame: spriteFrame,
|
spriteFrame1: spriteFrame1,
|
||||||
|
spriteFrame2: spriteFrame2,
|
||||||
|
image1Description: data.image1Description,
|
||||||
|
image2Description: data.image2Description,
|
||||||
|
punchline: data.punchline,
|
||||||
clue1: data.hint1,
|
clue1: data.hint1,
|
||||||
clue2: data.hint2,
|
clue2: data.hint2,
|
||||||
clue3: data.hint3,
|
clue3: data.hint3,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class ShareManager {
|
|||||||
/** 分享模式的关卡数据(null 表示正常模式) */
|
/** 分享模式的关卡数据(null 表示正常模式) */
|
||||||
private _shareLevels: RuntimeLevelConfig[] | null = null;
|
private _shareLevels: RuntimeLevelConfig[] | null = null;
|
||||||
|
|
||||||
/** API 返回的原始关卡数据(保留 imageUrl 用于懒加载) */
|
/** API 返回的原始关卡数据(保留 image1Url/image2Url 用于懒加载) */
|
||||||
private _shareApiLevels: ShareLevelData[] = [];
|
private _shareApiLevels: ShareLevelData[] = [];
|
||||||
|
|
||||||
private _shareTitle: string = '';
|
private _shareTitle: string = '';
|
||||||
@@ -91,7 +91,11 @@ export class ShareManager {
|
|||||||
const runtimeLevels: RuntimeLevelConfig[] = levels.map((level) => ({
|
const runtimeLevels: RuntimeLevelConfig[] = levels.map((level) => ({
|
||||||
id: level.id,
|
id: level.id,
|
||||||
name: `第${level.level}关`,
|
name: `第${level.level}关`,
|
||||||
spriteFrame: null,
|
spriteFrame1: null,
|
||||||
|
spriteFrame2: null,
|
||||||
|
image1Description: level.image1Description,
|
||||||
|
image2Description: level.image2Description,
|
||||||
|
punchline: level.punchline,
|
||||||
clue1: level.hint1,
|
clue1: level.hint1,
|
||||||
clue2: level.hint2,
|
clue2: level.hint2,
|
||||||
clue3: level.hint3,
|
clue3: level.hint3,
|
||||||
@@ -99,11 +103,17 @@ export class ShareManager {
|
|||||||
completed: false,
|
completed: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// 预加载首关图片
|
// 预加载首关图片(两张并行加载)
|
||||||
if (levels.length > 0) {
|
if (levels.length > 0) {
|
||||||
const sf = await this._loadImage(levels[0].imageUrl);
|
const [sf1, sf2] = await Promise.all([
|
||||||
if (sf) {
|
this._loadImage(levels[0].image1Url),
|
||||||
runtimeLevels[0].spriteFrame = sf;
|
this._loadImage(levels[0].image2Url),
|
||||||
|
]);
|
||||||
|
if (sf1) {
|
||||||
|
runtimeLevels[0].spriteFrame1 = sf1;
|
||||||
|
}
|
||||||
|
if (sf2) {
|
||||||
|
runtimeLevels[0].spriteFrame2 = sf2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,15 +153,21 @@ export class ShareManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config = this._shareLevels[index];
|
const config = this._shareLevels[index];
|
||||||
if (config.spriteFrame) {
|
if (config.spriteFrame1) {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiLevel = this._shareApiLevels[index];
|
const apiLevel = this._shareApiLevels[index];
|
||||||
if (apiLevel?.imageUrl) {
|
if (apiLevel?.image1Url) {
|
||||||
const sf = await this._loadImage(apiLevel.imageUrl);
|
const [sf1, sf2] = await Promise.all([
|
||||||
if (sf) {
|
this._loadImage(apiLevel.image1Url),
|
||||||
config.spriteFrame = sf;
|
this._loadImage(apiLevel.image2Url),
|
||||||
|
]);
|
||||||
|
if (sf1) {
|
||||||
|
config.spriteFrame1 = sf1;
|
||||||
|
}
|
||||||
|
if (sf2) {
|
||||||
|
config.spriteFrame2 = sf2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ export class StorageManager {
|
|||||||
|
|
||||||
/** 默认体力值 */
|
/** 默认体力值 */
|
||||||
private static readonly DEFAULT_STAMINA: StaminaInfo = {
|
private static readonly DEFAULT_STAMINA: StaminaInfo = {
|
||||||
current: 5,
|
current: 50,
|
||||||
max: 5,
|
max: 50,
|
||||||
nextRecoverAt: null,
|
nextRecoverAt: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user