207 lines
11 KiB
TypeScript
207 lines
11 KiB
TypeScript
import SevenApiPanel from "./SevenApiPanel";
|
||
|
||
const { ccclass } = cc._decorator;
|
||
|
||
/** 仅编辑器预览使用。通过真实 Prefab 的视图接口模拟,不调用正式 Runtime。 */
|
||
@ccclass
|
||
export default class TestSeven extends cc.Component {
|
||
private gift: cc.Node = null;
|
||
private view: any = null;
|
||
private info: any = null;
|
||
private status: cc.Label = null;
|
||
private busy = false;
|
||
private failNext = false;
|
||
|
||
// 仅在编辑器预览加载真实活动 Prefab,并创建测试按钮。
|
||
start() {
|
||
if (!CC_PREVIEW) {
|
||
cc.error("[testSeven] 仅允许编辑器预览,请从构建中排除 testSeven。");
|
||
return;
|
||
}
|
||
this.status = this.label("正在加载 seven_day_gift…", 0, 850, 26);
|
||
this.button("临时打开 JungleTreasure", 0, 645, () => this.openJunglePreview());
|
||
const apiPanel = this.node.addComponent(SevenApiPanel);
|
||
apiPanel.preview = info => {
|
||
if (!this.view || this.busy) return this.report("请等待活动资源加载或奖励动画结束");
|
||
this.info = info;
|
||
this.open();
|
||
this.report("接口数据模拟 | 点击当天奖励领取,或点击外部只领取,本次不关闭(不增加资产)");
|
||
};
|
||
cc.assetManager.loadBundle("seven_day_gift", (error, bundle) => {
|
||
if (!cc.isValid(this.node, true)) return;
|
||
if (error) return this.report("分包加载失败:" + error.message);
|
||
bundle.load("prefab/sevenDayGift", cc.Prefab, (loadError, prefab: cc.Prefab) => {
|
||
if (!cc.isValid(this.node, true)) return;
|
||
if (loadError) return this.report("Prefab 加载失败:" + loadError.message);
|
||
this.gift = cc.instantiate(prefab);
|
||
this.node.addChild(this.gift);
|
||
this.gift.setPosition(0, 0);
|
||
this.view = this.gift.getComponent("SevenDayGift");
|
||
if (!this.view) return this.report("缺少 SevenDayGift 组件");
|
||
this.view.setCloseHandler(() => this.report("已关闭,可选择状态重新打开"));
|
||
// 控制面板在遮罩上方,使用与活动一致的 1080 × 1920 设计尺寸。
|
||
for (let day = 1; day <= 7; day++) {
|
||
this.button("第" + day + "天", (day - 4) * 140, -670, () => this.select(day));
|
||
}
|
||
this.button("今日已领", -330, -755, () => this.select(this.info.nextRewardDay, "claimed"));
|
||
this.button("全部完成", -110, -755, () => this.select(7, "completed"));
|
||
this.button("已过期", 110, -755, () => this.select(3, "expired"));
|
||
this.button("点击外部", 330, -755, () => {
|
||
if (this.gift.active) this.view.close();
|
||
else this.report("弹窗已关闭,请先重新打开");
|
||
});
|
||
this.button("下次失败", -220, -840, () => {
|
||
this.failNext = true;
|
||
this.report("下一次领取模拟失败,可再次点击重试");
|
||
});
|
||
this.button("重新打开", 0, -840, () => this.open());
|
||
this.button("重置", 220, -840, () => { this.failNext = false; this.select(1); });
|
||
this.button("预览弹出上浮(不领取)", 0, 730, () => {
|
||
if (!this.gift.active) this.open();
|
||
const reward = this.info.rewards.find(item => Number(item.day) === Number(this.info.nextRewardDay));
|
||
if (!reward) return;
|
||
this.busy = true;
|
||
this.view.playRewardEffect(reward.items, reward.day, () => { this.busy = false; });
|
||
});
|
||
this.select(1);
|
||
});
|
||
});
|
||
}
|
||
|
||
// 临时查看真实丛林活动界面;使用内存样例和原有动画预览模式。
|
||
private openJunglePreview() {
|
||
if (!CC_PREVIEW || this.busy) return;
|
||
this.busy = true;
|
||
this.report("正在加载 JungleTreasure…");
|
||
cc.assetManager.loadBundle("jungle_treasure", (error, bundle) => {
|
||
if (!cc.isValid(this.node, true)) return;
|
||
if (error) { this.busy = false; return this.report("丛林分包加载失败:" + error.message); }
|
||
bundle.load("prefab/jungle", cc.Prefab, (loadError, prefab: cc.Prefab) => {
|
||
if (!cc.isValid(this.node, true)) return;
|
||
if (loadError) { this.busy = false; return this.report("丛林界面加载失败:" + loadError.message); }
|
||
const node = cc.instantiate(prefab);
|
||
node.active = false;
|
||
const manager: any = node.getComponent("jungle_Manager");
|
||
if (!manager) {
|
||
node.destroy();
|
||
this.busy = false;
|
||
return this.report("丛林界面缺少 jungle_Manager 组件");
|
||
}
|
||
manager.previewAnimationOnly = true;
|
||
// 独立预览场景没有主页音频管理器,当前实例关闭音效。
|
||
manager.anniuMusic = manager.unLockMusic = manager.rewardMusic = null;
|
||
this.node.addChild(node);
|
||
node.setPosition(0, 0);
|
||
node.zIndex = 3000;
|
||
const close = () => {
|
||
node.destroy();
|
||
this.busy = false;
|
||
this.report("已关闭 JungleTreasure,可继续七日活动测试");
|
||
};
|
||
node.on("jungle-close", close, this);
|
||
node.on("jungle-complete", close, this);
|
||
node.active = true;
|
||
const types = ["coin", "freeze", "hammer", "magic_wand", "infinite_health"];
|
||
const config = {
|
||
activityId: "testSeven-jungle-preview", endAt: Date.now() + 86400000,
|
||
tiers: types.map((type, index) => ({
|
||
id: index + 1, price: index === 2 ? 6 : 0,
|
||
rewards: [{ type, count: type === "coin" ? 500 : type === "infinite_health" ? 1800 : 2 }],
|
||
})),
|
||
};
|
||
if (!manager.setServerData(config, [1, 1, 0, 1, 1])) {
|
||
close();
|
||
return this.report("丛林预览数据初始化失败");
|
||
}
|
||
manager.openActivity();
|
||
this.report("JungleTreasure 本地界面预览,不发奖、不支付");
|
||
});
|
||
});
|
||
}
|
||
|
||
// 生成指定天数和状态的内存样例,不修改账号资产。
|
||
private select(day: number, state: string = "active") {
|
||
if (this.busy) return;
|
||
const claimedCount = state === "completed" ? 7 : state === "claimed" ? day : day - 1;
|
||
const items = [
|
||
[{ type: "coin", count: 100 }],
|
||
[{ type: "hammer", count: 2 }],
|
||
[{ type: "freeze", count: 2 }, { type: "coin", count: 200 }],
|
||
[{ type: "magic_wand", count: 2 }],
|
||
[{ type: "infinite_health", count: 1800 }], // 秒:30 分钟,效果显示 +1800秒。
|
||
[{ type: "hammer", count: 1 }, { type: "freeze", count: 1 }], // 第六天移除魔法棒。
|
||
[{ type: "infinite_health", count: 1800 }, { type: "cat_skin", count: 1, itemId: 1 }],
|
||
];
|
||
this.info = {
|
||
serverNow: Date.now(), activityId: "testSeven-memory", status: state === "claimed" ? "active" : state,
|
||
triggerLevel: 23, triggerReached: true, startAt: Date.now() - 86400000,
|
||
endAt: Date.now() + (state === "expired" ? -1 : 7 * 86400000),
|
||
claimedCount, todayClaimed: state === "claimed" || state === "completed",
|
||
canClaim: state === "active", nextRewardDay: day,
|
||
rewards: items.map((reward, index) => ({ day: index + 1, items: reward, claimed: index < claimedCount })),
|
||
};
|
||
this.open();
|
||
}
|
||
|
||
// 用当前模拟状态重新打开弹窗。
|
||
private open() {
|
||
if (this.busy || !this.view || !this.info) return;
|
||
this.bindData();
|
||
this.view.show();
|
||
this.report("本地模拟 | 第" + this.info.nextRewardDay + "天 | " + this.info.status + " | 已领 " + this.info.claimedCount + "/7");
|
||
}
|
||
|
||
// 本地领取立即响应,支持一次失败;成功后使用正式视图的领取效果。
|
||
private bindData() {
|
||
this.view.setData(this.info, (done: (success: boolean) => void) => {
|
||
if (this.busy || !this.info.canClaim) return done(false);
|
||
const reward = this.info.rewards.find(item => Number(item.day) === Number(this.info.nextRewardDay));
|
||
if (!reward || reward.claimed || !Array.isArray(reward.items) || reward.items.length === 0) {
|
||
done(false);
|
||
return this.report("当前数据没有可领取奖励,请重新选择模拟天数或查询接口");
|
||
}
|
||
if (this.failNext) {
|
||
this.failNext = false;
|
||
done(false);
|
||
return this.report("模拟领取失败,弹窗保留;可点击当天奖励或外部重试");
|
||
}
|
||
this.busy = true;
|
||
reward.claimed = true;
|
||
this.info.claimedCount++;
|
||
this.info.todayClaimed = true;
|
||
this.info.canClaim = false;
|
||
if (this.info.claimedCount === 7) this.info.status = "completed";
|
||
// 更新视图仍沿用本地回调,不调用 initializeRuntime。
|
||
this.bindData();
|
||
this.view.playRewardEffect(reward.items, reward.day, () => { this.busy = false; done(true); });
|
||
this.report("模拟领取成功(不写入资产):" + reward.items.map(item => item.type + " × " + item.count).join(" / "));
|
||
});
|
||
}
|
||
|
||
// 更新测试状态提示。
|
||
private report(message: string) { this.status.string = message; }
|
||
|
||
// 创建测试面板文字,放在活动遮罩上方。
|
||
private label(text: string, x: number, y: number, size: number): cc.Label {
|
||
const node = new cc.Node("testSevenLabel");
|
||
this.node.addChild(node);
|
||
node.setPosition(x, y);
|
||
node.zIndex = 1000;
|
||
const label = node.addComponent(cc.Label);
|
||
label.string = text;
|
||
label.fontSize = size;
|
||
label.lineHeight = size + 6;
|
||
return label;
|
||
}
|
||
|
||
// 创建测试按钮,忙碌时忽略操作,避免切换正在播放的数据。
|
||
private button(text: string, x: number, y: number, action: () => void) {
|
||
const label = this.label(text, x, y, 28);
|
||
label.node.color = cc.color(110, 225, 255);
|
||
label.node.on(cc.Node.EventType.TOUCH_END, (event: cc.Event) => {
|
||
event.stopPropagation();
|
||
if (!this.busy) action();
|
||
});
|
||
}
|
||
}
|