You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.6 KiB
81 lines
2.6 KiB
|
3 weeks ago
|
import { Node, Vec3 } from 'cc';
|
||
|
|
import { IPopRevealConfig } from './PopAnimTypes';
|
||
|
|
import { popStaggerNode } from './PopAnimStagger';
|
||
|
|
|
||
|
|
const ITEM_GAP = 0.04;
|
||
|
|
const ITEM_DUR = 0.22;
|
||
|
|
const LAST_GAP = 0.05;
|
||
|
|
|
||
|
|
/** 在 root / ui_center 下查找节点 */
|
||
|
|
export function resolvePopNode(root: Node, center: Node | null, name: string): Node | null {
|
||
|
|
if (!name) return null;
|
||
|
|
if (center?.getChildByName(name)) return center.getChildByName(name);
|
||
|
|
if (root.getChildByName(name)) return root.getChildByName(name);
|
||
|
|
if (center) {
|
||
|
|
for (const c of center.children) {
|
||
|
|
const n = c.getChildByName(name);
|
||
|
|
if (n) return n;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
function collectItemNodes(root: Node, center: Node | null, cfg: IPopRevealConfig): Node[] {
|
||
|
|
const out: Node[] = [];
|
||
|
|
if (cfg.itemsNode) {
|
||
|
|
const container = resolvePopNode(root, center, cfg.itemsNode);
|
||
|
|
if (container?.isValid) {
|
||
|
|
for (const c of container.children) {
|
||
|
|
if (c.active) out.push(c);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (cfg.itemNodes) {
|
||
|
|
for (const name of cfg.itemNodes) {
|
||
|
|
const n = resolvePopNode(root, center, name);
|
||
|
|
if (n?.isValid && n.active) out.push(n);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
function hideNode(node: Node): void {
|
||
|
|
node.setScale(Vec3.ZERO);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 上屏前:列表项与尾部按钮默认隐藏 */
|
||
|
|
export function preparePopReveal(root: Node, center: Node | null, cfg: IPopRevealConfig): void {
|
||
|
|
for (const n of collectItemNodes(root, center, cfg)) {
|
||
|
|
hideNode(n);
|
||
|
|
}
|
||
|
|
for (const name of cfg.lastNodes ?? []) {
|
||
|
|
const n = resolvePopNode(root, center, name);
|
||
|
|
if (n?.isValid && n.active) hideNode(n);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 内容区入场完成后:分帧错峰出现 */
|
||
|
|
export function runPopReveal(root: Node, center: Node | null, cfg: IPopRevealConfig): void {
|
||
|
|
const itemPreset = cfg.itemsPreset ?? 'scale';
|
||
|
|
const lastPreset = cfg.lastPreset ?? 'scale';
|
||
|
|
const items = collectItemNodes(root, center, cfg);
|
||
|
|
|
||
|
|
items.forEach((n, i) => {
|
||
|
|
popStaggerNode(n, itemPreset, i * ITEM_GAP);
|
||
|
|
});
|
||
|
|
|
||
|
|
const lastStart = items.length * ITEM_GAP + ITEM_DUR * 0.55;
|
||
|
|
(cfg.lastNodes ?? []).forEach((name, i) => {
|
||
|
|
const n = resolvePopNode(root, center, name);
|
||
|
|
if (n?.isValid && n.active) {
|
||
|
|
popStaggerNode(n, lastPreset, lastStart + i * LAST_GAP);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function estimateRevealDuration(cfg: IPopRevealConfig): number {
|
||
|
|
const itemCount = (cfg.itemNodes?.length ?? 0) + (cfg.itemsNode ? 1 : 0);
|
||
|
|
const lastCount = cfg.lastNodes?.length ?? 0;
|
||
|
|
return itemCount * ITEM_GAP + ITEM_DUR + lastCount * LAST_GAP;
|
||
|
|
}
|