feat: 百人赛
This commit is contained in:
parent
8fb2ef1be8
commit
2fe6c9fb62
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "34338d87-8ed5-4847-bdb5-cc0e0085901b",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -137,7 +137,6 @@ export default class CloudRiseView extends cc.Component {
|
|||
this.entry.active = !this.map && CloudRiseService.homeEntryVisible(ActivityScheduleService.active("cloudRise"),
|
||||
ActivityScheduleService.hasSchedule(), ActivityScheduleService.now());
|
||||
this.updateEntryCountdown();
|
||||
this.layoutEntry();
|
||||
if (!this.map && this.displayedCoin !== cc.fx.GameConfig.GM_INFO.coin) {
|
||||
this.displayedCoin = cc.fx.GameConfig.GM_INFO.coin;
|
||||
const home: any = this.host.getComponent("JiaZai");
|
||||
|
|
@ -317,14 +316,6 @@ export default class CloudRiseView extends cc.Component {
|
|||
this.entryCountdown.string = [Math.floor(seconds / 3600), Math.floor(seconds / 60) % 60, seconds % 60]
|
||||
.map(pad).join(":");
|
||||
}
|
||||
private layoutEntry(): void {
|
||||
if (this.map || !this.entry.active || !this.entry.parent) return;
|
||||
const top = this.entry.parent, first = top.getChildByName("shop");
|
||||
if (!first) return;
|
||||
const visible = ["shop", "yicon", "redeemBtn", "passBtn", "jungle", "xinshou"]
|
||||
.map(name => top.getChildByName(name)).filter(node => node && node.active);
|
||||
this.entry.setPosition(first.x, visible.length ? Math.min(...visible.map(node => node.y)) - 220 : first.y);
|
||||
}
|
||||
onDestroy(): void {
|
||||
cc.game.off(cc.game.EVENT_SHOW, this.onShow, this);
|
||||
this.unschedule(this.tick);
|
||||
|
|
|
|||
52
assets/Script/HomeActivityEntryLayout.ts
Normal file
52
assets/Script/HomeActivityEntryLayout.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/** One owner for home activity positions; visibility is still decided by each activity. */
|
||||
export default class HomeActivityEntryLayout {
|
||||
private static signatures = new WeakMap<cc.Node, string>();
|
||||
private static leftNames = ["shop", "yicon", "redeemBtn", "passBtn", "jungle", "xinshou", "chengxu", "cloudRise"];
|
||||
private static rightNames = ["rank", "gacha", "day", "hammer"];
|
||||
|
||||
static refresh(top: cc.Node): void {
|
||||
if (!top || !top.parent) return;
|
||||
const first = top.getChildByName("shop"), right = top.getChildByName("rank");
|
||||
const footer = top.parent.getChildByName("shezhiBtn");
|
||||
if (!first || !right || !footer) return;
|
||||
const left = this.leftNames.map(name => top.getChildByName(name)).filter(node => !!node);
|
||||
const fixedRight = this.rightNames.map(name => top.getChildByName(name)).filter(node => !!node);
|
||||
// Adaptation sets the same steady scale on Load and the side buttons. Ignore temporary button press zoom.
|
||||
const scale = Math.abs(top.parent.scaleY) || 1;
|
||||
const signature = JSON.stringify([first.x, first.y, right.x, top.y, scale, footer.y, footer.height,
|
||||
...left.map(n => [n.name, n.active, n.width, n.height]),
|
||||
...fixedRight.map(n => [n.name, n.active, n.x, n.y, n.width, n.height])]);
|
||||
if (this.signatures.get(top) === signature) return;
|
||||
this.signatures.set(top, signature);
|
||||
|
||||
const footerTop = footer.y + footer.height * (1 - footer.anchorY) * scale - top.y + 16;
|
||||
let leftY = first.y + 220, leftBottom = Infinity;
|
||||
const occupiedRight = fixedRight.filter(n => n.active);
|
||||
let rightY = occupiedRight.length ? Math.min(...occupiedRight.map(n => n.y)) : first.y + 220;
|
||||
let rightBottom = occupiedRight.length
|
||||
? Math.min(...occupiedRight.map(n => n.y + this.extent(n).bottom * scale)) : Infinity;
|
||||
for (const node of left.filter(n => n.active)) {
|
||||
const extent = this.extent(node), above = extent.top * scale, below = extent.bottom * scale;
|
||||
const y = Math.min(leftY - 220, leftBottom - 16 - above);
|
||||
if (y + below >= footerTop) {
|
||||
node.setPosition(first.x, y); leftY = y; leftBottom = y + below;
|
||||
} else {
|
||||
// Use the free lower right slots instead of covering the bottom-left Settings button.
|
||||
const nextY = Math.min(rightY - 220, rightBottom - 16 - above);
|
||||
node.setPosition(right.x, nextY); rightY = nextY; rightBottom = nextY + below;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Include clocks and labels below icons so the next entry cannot cover them. */
|
||||
private static extent(node: cc.Node): { top: number; bottom: number } {
|
||||
let top = node.height * (1 - node.anchorY), bottom = -node.height * node.anchorY;
|
||||
for (const child of node.children) {
|
||||
if (!child.active) continue;
|
||||
const bounds = this.extent(child), scale = Math.abs(child.scaleY);
|
||||
top = Math.max(top, child.y + bounds.top * scale);
|
||||
bottom = Math.min(bottom, child.y + bounds.bottom * scale);
|
||||
}
|
||||
return { top, bottom };
|
||||
}
|
||||
}
|
||||
10
assets/Script/HomeActivityEntryLayout.ts.meta
Normal file
10
assets/Script/HomeActivityEntryLayout.ts.meta
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "79848e7c-3bbb-4cff-b60b-ec1748b22be4",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import ActivityScheduleService from "./module/Config/ActivityScheduleService";
|
||||
import HomeActivityEntryLayout from "./HomeActivityEntryLayout";
|
||||
|
||||
const { ccclass } = cc._decorator;
|
||||
|
||||
|
|
@ -6,6 +7,10 @@ const { ccclass } = cc._decorator;
|
|||
@ccclass
|
||||
export default class HomeActivitySchedule extends cc.Component {
|
||||
private visibility = 0;
|
||||
lateUpdate(): void {
|
||||
const load = this.node.getChildByName("Load");
|
||||
HomeActivityEntryLayout.refresh(load && load.getChildByName("Top"));
|
||||
}
|
||||
onEnable(): void {
|
||||
cc.game.on(cc.game.EVENT_SHOW, this.onShow, this);
|
||||
cc.game.on(cc.game.EVENT_HIDE, this.onHide, this);
|
||||
|
|
|
|||
|
|
@ -86,10 +86,8 @@ export default class JiaZai extends cc.Component {
|
|||
private jungleSettlementRequestId: number = 0;
|
||||
private jungleSettlementRequestTimeout: any = null;
|
||||
private pendingJungleSettlement: any = null;
|
||||
private starterPackDefaultPosition: cc.Vec2 = null;
|
||||
private starterPackOpening = false;
|
||||
private starterPackChecking = false;
|
||||
private benefitsEntryOffset: cc.Vec2 = null;
|
||||
|
||||
// 缓存 reward 预制体
|
||||
private static cachedRewardPrefab: cc.Prefab | null = null;
|
||||
|
|
@ -1397,6 +1395,9 @@ export default class JiaZai extends cc.Component {
|
|||
"shop",
|
||||
"yicon",
|
||||
"passBtn",
|
||||
"chengxu",
|
||||
"cloudRise",
|
||||
"redeemBtn",
|
||||
"xinshou",
|
||||
"jungle",
|
||||
"avatar",
|
||||
|
|
@ -3144,37 +3145,8 @@ export default class JiaZai extends cc.Component {
|
|||
return top && top.getChildByName("xinshou");
|
||||
}
|
||||
|
||||
/** 新手礼包补位时,福利入口保持场景中配置的相对间距。 */
|
||||
/** Visibility is owned here; HomeActivitySchedule arranges all entries before rendering. */
|
||||
private refreshHomeActivityEntryLayout(): void {
|
||||
let starterPackButton = this.getStarterPackHomeButton();
|
||||
let jungleButton = this.getJungleTreasureHomeButton();
|
||||
if (!starterPackButton || !jungleButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.starterPackDefaultPosition) {
|
||||
this.starterPackDefaultPosition = cc.v2(starterPackButton.x, starterPackButton.y);
|
||||
}
|
||||
|
||||
const benefitsButton = starterPackButton.parent.getChildByName("chengxu");
|
||||
if (benefitsButton && !this.benefitsEntryOffset) {
|
||||
this.benefitsEntryOffset = cc.v2(
|
||||
benefitsButton.x - this.starterPackDefaultPosition.x,
|
||||
benefitsButton.y - this.starterPackDefaultPosition.y,
|
||||
);
|
||||
}
|
||||
|
||||
let targetPosition = starterPackButton.active && !jungleButton.active
|
||||
? cc.v2(jungleButton.x, jungleButton.y)
|
||||
: this.starterPackDefaultPosition;
|
||||
starterPackButton.setPosition(targetPosition);
|
||||
if (benefitsButton && this.benefitsEntryOffset) {
|
||||
// Hidden activities do not reserve slots above the benefits entry.
|
||||
const benefitsPosition = starterPackButton.active
|
||||
? cc.v2(targetPosition.x + this.benefitsEntryOffset.x, targetPosition.y + this.benefitsEntryOffset.y)
|
||||
: jungleButton.active ? this.starterPackDefaultPosition : cc.v2(jungleButton.x, jungleButton.y);
|
||||
benefitsButton.setPosition(benefitsPosition);
|
||||
}
|
||||
MiniProgramBenefitsBridge.instance.refreshEntry();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<key>offset</key>
|
||||
<string>{-1,-7}</string>
|
||||
<key>rotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{3,19},{196,180}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
<key>offset</key>
|
||||
<string>{-1,-7}</string>
|
||||
<key>rotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{5,19},{192,180}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
@ -103,7 +103,6 @@
|
|||
<string>{0,-3}</string>
|
||||
<key>rotated</key>
|
||||
<false/>
|
||||
<false/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{11,11},{182,188}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
@ -116,7 +115,7 @@
|
|||
<key>offset</key>
|
||||
<string>{0,-7}</string>
|
||||
<key>rotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{4,19},{196,180}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
@ -142,7 +141,7 @@
|
|||
<key>offset</key>
|
||||
<string>{0,0}</string>
|
||||
<key>rotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{0,0},{188,190}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
@ -156,7 +155,6 @@
|
|||
<string>{0,0}</string>
|
||||
<key>rotated</key>
|
||||
<true/>
|
||||
<true/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{0,5},{204,194}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
@ -182,7 +180,7 @@
|
|||
<key>offset</key>
|
||||
<string>{-5,-8}</string>
|
||||
<key>rotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{2,21},{190,178}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
@ -196,7 +194,6 @@
|
|||
<string>{0,0}</string>
|
||||
<key>rotated</key>
|
||||
<false/>
|
||||
<false/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{0,0},{146,160}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
@ -209,7 +206,7 @@
|
|||
<key>offset</key>
|
||||
<string>{0,-8}</string>
|
||||
<key>rotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>sourceColorRect</key>
|
||||
<string>{{11,21},{182,178}}</string>
|
||||
<key>sourceSize</key>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"rawTextureUuid": "b45f4eaf-4250-449a-81ea-a7ca1e534a02",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": -1,
|
||||
"offsetY": -7,
|
||||
"trimX": 198,
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
"rawTextureUuid": "b45f4eaf-4250-449a-81ea-a7ca1e534a02",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": -1,
|
||||
"offsetY": -7,
|
||||
"trimX": 380,
|
||||
|
|
@ -178,7 +178,6 @@
|
|||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -3,
|
||||
"trimX": 390,
|
||||
|
|
@ -201,7 +200,7 @@
|
|||
"rawTextureUuid": "b45f4eaf-4250-449a-81ea-a7ca1e534a02",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -7,
|
||||
"trimX": 192,
|
||||
|
|
@ -247,7 +246,7 @@
|
|||
"rawTextureUuid": "b45f4eaf-4250-449a-81ea-a7ca1e534a02",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 2,
|
||||
|
|
@ -271,7 +270,6 @@
|
|||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 2,
|
||||
|
|
@ -317,7 +315,7 @@
|
|||
"rawTextureUuid": "b45f4eaf-4250-449a-81ea-a7ca1e534a02",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": -5,
|
||||
"offsetY": -8,
|
||||
"trimX": 562,
|
||||
|
|
@ -341,7 +339,6 @@
|
|||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 342,
|
||||
|
|
@ -364,7 +361,7 @@
|
|||
"rawTextureUuid": "b45f4eaf-4250-449a-81ea-a7ca1e534a02",
|
||||
"trimType": "auto",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -8,
|
||||
"trimX": 825,
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 158 KiB |
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "4970b759-7a17-4559-84a3-9bbe73489173",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "e159bf60-8e51-4dca-85dd-8bec167c9036",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "dbde4bfd-0b20-45aa-8c9c-139722aabc64",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "7a2e5485-be73-4ed1-af4a-6a00ab845cce",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "a78cb4f0-a528-4a3e-9470-01100e4c24d1",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "d0d45606-9a70-4a8b-a213-540cc0100e9d",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "4572f582-ceb9-419d-b453-44d48b3ac622",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
||||
|
|
@ -57,4 +57,4 @@
|
|||
"cloud-function"
|
||||
],
|
||||
"assets-sort-type": "name"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ function fixture(storage = new Map()) {
|
|||
return {service, cc, storage, requests, events, setNow: n => now = n, setEnv: e => environment = e,
|
||||
failStorage: () => storageFails = true,
|
||||
loadHome: () => load('assets/Script/HomeActivitySchedule.ts', cc,
|
||||
{'./module/Config/ActivityScheduleService': {default: service}}, () => now),
|
||||
{'./module/Config/ActivityScheduleService': {default: service}, './HomeActivityEntryLayout': {default: {refresh(){}}}}, () => now),
|
||||
emit: name => {const event = events.get(name); event.fn.call(event.target);}};
|
||||
}
|
||||
const flush = async () => {for (let i = 0; i < 12; i++) await Promise.resolve();};
|
||||
|
|
|
|||
65
tools/test-home-activity-entry-layout.cjs
Normal file
65
tools/test-home-activity-entry-layout.cjs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
const test=require('node:test'),assert=require('node:assert/strict'),fs=require('node:fs'),vm=require('node:vm'),ts=require('typescript');
|
||||
const left=['shop','yicon','redeemBtn','passBtn','jungle','xinshou','chengxu','cloudRise'];
|
||||
const right=['rank','gacha','day','hammer'];
|
||||
function fixture(){
|
||||
const exports={};
|
||||
vm.runInNewContext(ts.transpileModule(fs.readFileSync('assets/Script/HomeActivityEntryLayout.ts','utf8'),{
|
||||
compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2017}}).outputText,{exports});
|
||||
const a=JSON.parse(fs.readFileSync('assets/Scene/HomeScene.fire')),nodes=new Map();let writes=0;
|
||||
for(let i=0;i<a.length;i++)if(a[i].__type__==='cc.Node'){
|
||||
const n=a[i];nodes.set(i,{name:n._name,active:n._active,x:n._trs.array[0],y:n._trs.array[1],
|
||||
width:n._contentSize.width,height:n._contentSize.height,anchorY:n._anchorPoint.y,scaleY:n._trs.array[8],children:[],
|
||||
getChildByName(name){return this.children.find(n=>n.name===name);},setPosition(x,y){this.x=x;this.y=y;writes++;}});
|
||||
}
|
||||
for(const [i,n]of nodes){n.children=a[i]._children.map(r=>nodes.get(r.__id__));n.parent=nodes.get(a[i]._parent?.__id__);}
|
||||
const top=[...nodes.values()].find(n=>n.name==='Top'&&n.parent.name==='Load');
|
||||
const gift=top.getChildByName('xinshou');
|
||||
const frame=JSON.parse(fs.readFileSync('assets/UI/UI/start/startUI2.plist.meta')).subMetas['cloudRise.png'];
|
||||
const cloud={...gift,name:'cloudRise',width:frame.rawWidth,height:frame.rawHeight,children:gift.children.filter(n=>['New Sprite','time'].includes(n.name))};
|
||||
top.children.push(cloud);
|
||||
const layout=exports.default;
|
||||
function box(n){const b=layout.extent(n),scale=top.parent.scaleY;return {top:n.y+b.top*scale,bottom:n.y+b.bottom*scale};}
|
||||
function check(){
|
||||
const all=[...left,...right].map(n=>top.getChildByName(n)).filter(n=>n.active);
|
||||
for(let i=0;i<all.length;i++)for(let j=i+1;j<all.length;j++){
|
||||
const p=all[i],q=all[j];if(Math.abs(p.x-q.x)>300)continue;
|
||||
const a=box(p),b=box(q);assert(a.bottom>=b.top+15.99||b.bottom>=a.top+15.99,`${p.name} overlaps ${q.name}`);
|
||||
}
|
||||
const footer=top.parent.getChildByName('shezhiBtn'),bound=footer.y+footer.height*(1-footer.anchorY)*top.parent.scaleY-top.y;
|
||||
for(const n of all)assert(box(n).bottom>=bound+15.99,`${n.name} covers footer: ${box(n).bottom} < ${bound+16}`);
|
||||
}
|
||||
return {layout,top,check,get writes(){return writes;}};
|
||||
}
|
||||
test('every visibility combination fits without overlap, including both columns and bottom controls',()=>{
|
||||
const f=fixture();
|
||||
for(const scale of [1,0.85]){
|
||||
f.top.parent.scaleY=scale;
|
||||
for(let mask=0;mask<4096;mask++){
|
||||
[...left,...right].forEach((name,i)=>f.top.getChildByName(name).active=!!(mask&(1<<i)));
|
||||
f.layout.refresh(f.top);f.check();
|
||||
}
|
||||
}
|
||||
});
|
||||
test('benefits and cloudRise occupy distinct slots and async hide/show immediately compacts the layout',()=>{
|
||||
const f=fixture();[...left,...right].forEach(name=>f.top.getChildByName(name).active=name!=='redeemBtn');
|
||||
f.layout.refresh(f.top);f.check();
|
||||
const benefit=f.top.getChildByName('chengxu'),cloud=f.top.getChildByName('cloudRise');
|
||||
assert.notDeepEqual([benefit.x,benefit.y],[cloud.x,cloud.y]);
|
||||
assert.equal(cloud.x,f.top.getChildByName('rank').x,'overflow uses the free right slot');
|
||||
const old={x:benefit.x,y:benefit.y};benefit.active=false;f.layout.refresh(f.top);f.check();
|
||||
// The countdown makes CloudRise taller than benefits; only reclaim a slot if the whole entry fits.
|
||||
f.top.getChildByName('xinshou').active=false;f.layout.refresh(f.top);f.check();
|
||||
assert.equal(cloud.x,old.x);assert(cloud.y>old.y);
|
||||
const writes=f.writes;for(let i=0;i<20;i++)f.layout.refresh(f.top);assert.equal(f.writes,writes,'unchanged frames do not reposition buttons');
|
||||
benefit.active=true;f.layout.refresh(f.top);f.check();
|
||||
});
|
||||
|
||||
test('home lays out late in the frame after asynchronous entry visibility changes',()=>{
|
||||
const source=fs.readFileSync('assets/Script/HomeActivitySchedule.ts','utf8');let arranged;
|
||||
const exports={},cc={Component:class{},_decorator:{ccclass:c=>c}};
|
||||
vm.runInNewContext(ts.transpileModule(source,{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2017,experimentalDecorators:true}}).outputText,
|
||||
{exports,cc,require:name=>({default:name.endsWith('HomeActivityEntryLayout')?{refresh:top=>arranged=top}:{}})});
|
||||
const f=fixture(),home=new exports.default();home.node={getChildByName:()=>f.top.parent};home.lateUpdate();assert.equal(arranged,f.top);
|
||||
assert(!fs.readFileSync('assets/Script/CloudRiseView.ts','utf8').includes('private layoutEntry()'),'CloudRise no longer writes competing positions');
|
||||
assert(!fs.readFileSync('assets/Script/JiaZai.ts','utf8').includes('benefitsEntryOffset'),'benefits no longer follows a separate layout');
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user