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.
 
 
 
 
AdLike2048/assets/script/ui/BattleGame/BattleDigChestFxPresenter.ts

115 lines
3.6 KiB

import { isValid, Node, Tween, tween, UIOpacity, UITransform, Vec3 } from 'cc';
import { GBundle } from '../../game/ConfigRes';
/** 宝箱预制路径 */
const CHEST_TIP_PATH = 'prefab/';
/** 宝箱预制名 */
const CHEST_TIP_NAME = '宝箱';
/** 飞入时长(秒) */
const FLY_SEC = 0.55;
/** 终点缩放 */
const FLY_END_SCALE = 10;
/** 复用世界坐标 */
const _world = new Vec3();
/** 复用本地坐标 */
const _local = new Vec3();
/** 飞向层本地中心 */
const _endLocal = new Vec3(0, 0, 0);
/**
* 开挖宝箱飞向屏幕中央放大渐隐。
*/
export class BattleDigChestFxPresenter {
private _layer: Node | null = null;
private _flying: Node | null = null;
private _gen = 0;
/**
* @param layer 飞行层(ui_fly)
*/
bind(layer: Node | null): void {
this.clear();
this._layer = layer;
}
/** 停止并回收进行中的飞入 */
clear(): void {
this._gen++;
this._recycleFlying();
this._layer = null;
}
/**
* 宝箱从起点飞向屏中,放大到 10 倍并渐隐,结束后回调。
* @param worldPos 起点世界坐标
* @param onDone 结束回调
*/
playFly(worldPos: Vec3 | null, onDone: () => void): void {
this._recycleFlying();
const layer = this._layer;
if (!layer?.isValid || !worldPos) {
console.warn('[BattleDigChestFx] 飞入层或起点无效,跳过飞入');
onDone();
return;
}
if (typeof gg === 'undefined' || !gg.res?.getNode) {
console.warn('[BattleDigChestFx] gg.res 未就绪,跳过飞入');
onDone();
return;
}
const tip = gg.res.getNode(CHEST_TIP_PATH, CHEST_TIP_NAME, GBundle.BattleGame);
if (!tip?.isValid) {
console.warn('[BattleDigChestFx] 缺少宝箱,跳过飞入');
onDone();
return;
}
const fly = tip;
fly.parent = layer;
fly.setSiblingIndex(layer.children.length - 1);
fly.active = true;
fly.setScale(1, 1, 1);
let opacity = fly.getComponent(UIOpacity);
if (!opacity) opacity = fly.addComponent(UIOpacity);
opacity.opacity = 255;
_world.set(worldPos.x, worldPos.y, worldPos.z);
const ut = layer.getComponent(UITransform);
if (ut) {
ut.convertToNodeSpaceAR(_world, _local);
fly.setPosition(_local);
} else {
fly.setWorldPosition(_world);
}
this._flying = fly;
const gen = ++this._gen;
// ui_fly 居中锚点时本地 (0,0) 即屏中
const endPos = _endLocal.clone();
Tween.stopAllByTarget(fly);
tween(fly)
.to(FLY_SEC, { position: endPos, scale: new Vec3(FLY_END_SCALE, FLY_END_SCALE, 1) }, { easing: 'sineOut' })
.start();
tween(opacity)
.to(FLY_SEC, { opacity: 0 }, { easing: 'sineIn' })
.call(() => {
if (gen !== this._gen) return;
this._recycleFlying();
onDone();
})
.start();
}
private _recycleFlying(): void {
const fly = this._flying;
this._flying = null;
if (!fly || !isValid(fly)) return;
Tween.stopAllByTarget(fly);
const op = fly.getComponent(UIOpacity);
if (op) Tween.stopAllByTarget(op);
fly.setScale(1, 1, 1);
if (op) op.opacity = 255;
if (fly['resKey'] && typeof gg !== 'undefined' && gg.res?.putNode) {
gg.res.putNode(fly);
} else {
fly.destroy();
}
}
}