161 lines
7.5 KiB
TypeScript
161 lines
7.5 KiB
TypeScript
import NumberToImage from "../Script/NumberToImage";
|
||
|
||
const { ccclass, property } = cc._decorator;
|
||
|
||
/** 仅编辑器预览使用。通过真实 Prefab 的视图接口模拟,不调用正式 Runtime。 */
|
||
@ccclass
|
||
export default class TestSeven extends cc.Component {
|
||
@property(cc.Prefab) rewardPrefab: cc.Prefab = null;
|
||
@property(cc.SpriteAtlas) rewardFont: cc.SpriteAtlas = null;
|
||
private previousFont: any = null;
|
||
private gift: cc.Node = null;
|
||
private view: any = null;
|
||
private info: any = null;
|
||
private status: cc.Label = null;
|
||
private busy = false;
|
||
private failNext = false;
|
||
|
||
start() {
|
||
if (!CC_PREVIEW) {
|
||
cc.error("[testSeven] 仅允许编辑器预览,请从构建中排除 testSeven。");
|
||
return;
|
||
}
|
||
this.status = this.label("正在加载 seven_day_gift…", 0, 850, 26);
|
||
if (!this.rewardPrefab || !this.rewardFont) return this.report("测试场景缺少奖励弹窗或数字图集引用");
|
||
this.previousFont = NumberToImage.font;
|
||
NumberToImage.font = this.rewardFont;
|
||
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, () => this.open(true));
|
||
this.button("下次失败", -220, -840, () => {
|
||
this.failNext = true;
|
||
this.report("下一次领取将在 1.2 秒后失败,可再次点击重试");
|
||
});
|
||
this.button("重新打开", 0, -840, () => this.open(false));
|
||
this.button("重置", 220, -840, () => { this.failNext = false; this.select(1); });
|
||
this.select(1);
|
||
});
|
||
});
|
||
}
|
||
|
||
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: 30 }],
|
||
[{ type: "coin", count: 300 }, { type: "hammer", count: 2 }, { type: "freeze", count: 2 }],
|
||
[{ 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(false);
|
||
}
|
||
|
||
private open(autoClaim: boolean) {
|
||
if (this.busy || !this.view || !this.info) return;
|
||
this.bindData();
|
||
this.view.show(autoClaim);
|
||
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);
|
||
this.busy = true;
|
||
this.report("模拟领取中…请检查重复点击和关闭拦截");
|
||
this.scheduleOnce(() => {
|
||
this.busy = false;
|
||
if (this.failNext) {
|
||
this.failNext = false;
|
||
done(false);
|
||
return this.report("模拟领取失败,可点击当前奖励重试");
|
||
}
|
||
const reward = this.info.rewards[this.info.nextRewardDay - 1];
|
||
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();
|
||
done(true);
|
||
this.showRewardWindow(reward.items);
|
||
this.report("模拟领取成功(不写入资产):" + reward.items.map(item => item.type + " × " + item.count).join(" / "));
|
||
}, 1.2);
|
||
});
|
||
}
|
||
|
||
private showRewardWindow(items: any[]) {
|
||
const node = cc.instantiate(this.rewardPrefab);
|
||
this.node.addChild(node);
|
||
node.setPosition(0, 0);
|
||
node.zIndex = 1001;
|
||
const reward = node.getComponent("Reward");
|
||
if (!reward) {
|
||
node.destroy();
|
||
this.report("奖励弹窗缺少 Reward 组件");
|
||
return;
|
||
}
|
||
this.busy = true;
|
||
reward.init(items.map(item => ({
|
||
type: item.type === "magic_wand" ? "magic" : item.type,
|
||
count: Math.max(0, Number(item.count !== undefined ? item.count : item.amount) || 0),
|
||
spriteFrame: item.type === "cat_skin" ? this.view.catArt : null,
|
||
})).filter(item => item.count > 0), () => { this.busy = false; });
|
||
}
|
||
|
||
onDestroy() {
|
||
if (CC_PREVIEW && NumberToImage.font === this.rewardFont) NumberToImage.font = this.previousFont;
|
||
}
|
||
|
||
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();
|
||
});
|
||
}
|
||
}
|