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.
604 lines
22 KiB
604 lines
22 KiB
|
|
//*********************
|
|
// create by 流云
|
|
// time: Wed Oct 07 2026
|
|
// desc: 宝石镶嵌 / 页签仓库 / 一键合成
|
|
//*********************
|
|
import { _decorator, EventMouse, EventTouch, Input, input, instantiate, Label, Node, find, sp, Sprite, UIOpacity, UITransform, Vec2, Vec3 } from 'cc';
|
|
import { SpriteLoad } from 'db://assets/mx/components/SpriteLoad';
|
|
import { ensureSpineSkeletonDataRuntime } from 'db://assets/mx/module/lang/spineRuntimePatch';
|
|
import { GemGrid } from '../../com/GemGrid';
|
|
import { FrameFlowHost } from '../../game/FrameFlowHost';
|
|
import { GBundle, UIID } from '../../game/ConfigRes';
|
|
import { GEM_SLOT_COUNT, IGemBagEntry } from '../../game/GameDataEnums';
|
|
import { Auto_PanelGemstone } from './Auto_PanelGemstone';
|
|
const { ccclass } = _decorator;
|
|
|
|
const LOG = '[PanelGemstone]';
|
|
/** 按下后移动超过此值开始拖 */
|
|
const DRAG_THRESHOLD = 18;
|
|
const GHOST_OPACITY = 180;
|
|
const ELEMENT_COUNT = 5;
|
|
const ELEMENT_SKINS = ['', '金', '木', '水', '火', '土'];
|
|
/** 仓库每帧实例化数量 */
|
|
const BAG_PER_FRAME = 6;
|
|
/** 默认页签:通用 Weapon.type=1 */
|
|
const DEFAULT_FILTER = 1;
|
|
/** 默认展示五行:金 */
|
|
const DEFAULT_ELEMENT = 1;
|
|
|
|
/**
|
|
* 宝石页:左右切五行镶嵌 + 页签仓库 + 拖拽镶嵌/卸下 + 一键合成。
|
|
* 页签 btn0~btn5 → type 1~6(通用/金/木/水/火/土),默认通用。
|
|
*/
|
|
@ccclass('UIPanelGemstone')
|
|
export class UIPanelGemstone extends Auto_PanelGemstone {
|
|
|
|
/** 镶嵌格模板 */
|
|
private _itemTpl: Node | null = null;
|
|
/** 仓库格子模板 */
|
|
private _bagTpl: Node | null = null;
|
|
/** 当前五行的 4 个镶嵌格 */
|
|
private _slotItems: Node[] = [];
|
|
/** 仓库动态格 */
|
|
private _bagItems: Node[] = [];
|
|
/** 当前展示五行 1~5 */
|
|
private _currentElement = DEFAULT_ELEMENT;
|
|
/** 顶部五行数字 Spine */
|
|
private _skSkin: sp.Skeleton | null = null;
|
|
/** 当前筛选:1 通用;2~6 金木水火土 */
|
|
private _filterType = DEFAULT_FILTER;
|
|
/** 仓库数据 */
|
|
private _bagList: IGemBagEntry[] = [];
|
|
/** 仓库分帧 */
|
|
private _flow: FrameFlowHost | null = null;
|
|
/** 仓库填充代数 */
|
|
private _bagToken = 0;
|
|
/** 已分帧填充下标 */
|
|
private _bagFillIndex = 0;
|
|
|
|
private _pressing = false;
|
|
private _dragging = false;
|
|
private _dragStart = new Vec2();
|
|
private _hitPos = new Vec2();
|
|
private _ghostPos = new Vec3();
|
|
private _ghost: Node | null = null;
|
|
private _dragListening = false;
|
|
/** 拖中的宝石 id */
|
|
private _dragGemId = 0;
|
|
/** 从槽拖出:五行 1~5;0=仓库 */
|
|
private _dragFromElement = 0;
|
|
/** 从槽拖出:槽下标 0~3;-1=仓库 */
|
|
private _dragFromSlot = -1;
|
|
|
|
onLoad(): void {
|
|
super.onLoad();
|
|
this._itemTpl = this.ui_list?.getChildByName('itemTemplate') ?? null;
|
|
if (this._itemTpl) this._itemTpl.active = false;
|
|
this._bagTpl = this.ui_content?.getChildByName('bagItemTemplate') ?? null;
|
|
if (this._bagTpl) this._bagTpl.active = false;
|
|
this._skSkin = find('ui_center/top/sk_skin', this.node)?.getComponent(sp.Skeleton) ?? null;
|
|
this._bindDrag(true);
|
|
}
|
|
|
|
onEnable(): void {
|
|
super.onEnable();
|
|
this._bindDrag(true);
|
|
}
|
|
|
|
onDisable(): void {
|
|
this._bindDrag(false);
|
|
this._endDrag();
|
|
this._stopBagFill();
|
|
super.onDisable();
|
|
}
|
|
|
|
onInit(): void {
|
|
this._filterType = DEFAULT_FILTER;
|
|
this._currentElement = DEFAULT_ELEMENT;
|
|
this._selectTag(this.btn0);
|
|
void this._refresh();
|
|
}
|
|
|
|
click_btnClose(): void {
|
|
void this.close(2);
|
|
}
|
|
|
|
click_btnLeft(): void {
|
|
const next = this._currentElement <= 1 ? ELEMENT_COUNT : this._currentElement - 1;
|
|
this._setElement(next);
|
|
}
|
|
|
|
click_btnRight(): void {
|
|
const next = this._currentElement >= ELEMENT_COUNT ? 1 : this._currentElement + 1;
|
|
this._setElement(next);
|
|
}
|
|
|
|
click_btn0(): void { this._onTag(1, this.btn0); }
|
|
click_btn1(): void { this._onTag(2, this.btn1); }
|
|
click_btn2(): void { this._onTag(3, this.btn2); }
|
|
click_btn3(): void { this._onTag(4, this.btn3); }
|
|
click_btn4(): void { this._onTag(5, this.btn4); }
|
|
click_btn5(): void { this._onTag(6, this.btn5); }
|
|
|
|
click_btnFuse(): void {
|
|
const gains = gg.gem.fuseAll();
|
|
this._rebuildBag();
|
|
this._refreshSlots();
|
|
if (!gains.length) {
|
|
gg.ui.showToast('没有可合成的宝石');
|
|
return;
|
|
}
|
|
void gg.ui.openPanel(UIID.PopGetGem, { data: gains });
|
|
}
|
|
|
|
/** 页签切换 */
|
|
private _onTag(filterType: number, btn: Node): void {
|
|
if (this._filterType === filterType) return;
|
|
this._filterType = filterType;
|
|
this._selectTag(btn);
|
|
this._rebuildBag();
|
|
}
|
|
|
|
/** 标签底移到当前按钮 */
|
|
private _selectTag(btn: Node | null): void {
|
|
if (!this.ui_tagBtnBg?.isValid || !btn?.isValid) return;
|
|
this.ui_tagBtnBg.setWorldPosition(btn.worldPosition);
|
|
}
|
|
|
|
/** 全量刷新 */
|
|
private async _refresh(): Promise<void> {
|
|
await gg.gem.ensureTable();
|
|
if (!this.isValid) return;
|
|
this._ensureSlotItems();
|
|
this._applyElementVisual();
|
|
this._refreshSlots();
|
|
this._rebuildBag();
|
|
}
|
|
|
|
/**
|
|
* 切换当前五行。
|
|
* @param element 1~5
|
|
*/
|
|
private _setElement(element: number): void {
|
|
const e = Math.floor(Number(element) || 0);
|
|
if (e < 1 || e > ELEMENT_COUNT) {
|
|
console.warn(LOG, '五行非法', element);
|
|
return;
|
|
}
|
|
if (this._currentElement === e) return;
|
|
this._currentElement = e;
|
|
this._applyElementVisual();
|
|
this._refreshSlots();
|
|
}
|
|
|
|
/** 标题图 + 数字皮肤 */
|
|
private _applyElementVisual(): void {
|
|
this._applyTitle();
|
|
this._applySkin();
|
|
}
|
|
|
|
/** sp_title 加载 title_1~5 */
|
|
private _applyTitle(): void {
|
|
const spNode = this.sp_title?.node;
|
|
if (!spNode?.isValid) {
|
|
console.warn(LOG, 'sp_title 缺失');
|
|
return;
|
|
}
|
|
const path = `texture/title_${this._currentElement}`;
|
|
if (!spNode.getComponent(Sprite)) spNode.addComponent(Sprite);
|
|
spNode.getOrAddComponent(SpriteLoad).setSprite(path, GBundle.Gemstone);
|
|
}
|
|
|
|
/** sk_skin 切五行皮肤 */
|
|
private _applySkin(): void {
|
|
const sk = this._skSkin;
|
|
if (!sk?.isValid) {
|
|
console.warn(LOG, 'sk_skin Skeleton 缺失');
|
|
return;
|
|
}
|
|
const skin = ELEMENT_SKINS[this._currentElement] || '';
|
|
if (!skin) {
|
|
console.warn(LOG, '五行皮肤名无效', this._currentElement);
|
|
return;
|
|
}
|
|
if (sk.skeletonData) ensureSpineSkeletonDataRuntime(sk.skeletonData);
|
|
try {
|
|
sk.setSkin(skin);
|
|
sk.setSlotsToSetupPose();
|
|
if (sk.findAnimation('待机')) sk.setAnimation(0, '待机', true);
|
|
} catch (err) {
|
|
console.warn(LOG, 'setSkin 失败', skin, err);
|
|
}
|
|
}
|
|
|
|
/** 打开时初始化 4 个镶嵌格(只建一次) */
|
|
private _ensureSlotItems(): void {
|
|
if (!this.ui_list?.isValid || !this._itemTpl?.isValid) {
|
|
console.warn(LOG, 'ui_list/itemTemplate 缺失');
|
|
return;
|
|
}
|
|
if (this._slotItems.length === GEM_SLOT_COUNT) return;
|
|
for (let i = 0; i < this._slotItems.length; i++) {
|
|
const n = this._slotItems[i];
|
|
if (n?.isValid) n.destroy();
|
|
}
|
|
this._slotItems.length = 0;
|
|
for (let s = 0; s < GEM_SLOT_COUNT; s++) {
|
|
const node = instantiate(this._itemTpl);
|
|
node.parent = this.ui_list;
|
|
node.active = true;
|
|
node.name = `slot_${s}`;
|
|
(node as any)._slot = s;
|
|
this._slotItems.push(node);
|
|
}
|
|
}
|
|
|
|
/** 刷新当前五行 4 槽 */
|
|
private _refreshSlots(): void {
|
|
this._ensureSlotItems();
|
|
const slots = gg.gem.getElementSlots(this._currentElement);
|
|
for (let s = 0; s < this._slotItems.length; s++) {
|
|
const node = this._slotItems[s];
|
|
if (!node?.isValid) continue;
|
|
(node as any)._element = this._currentElement;
|
|
(node as any)._slot = s;
|
|
this._paintSlot(node, slots[s] || 0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 画单个镶嵌格:空位 qbg=宝石框小0、icon 空;有宝石写 qbg/icon/lbName。
|
|
* @param slotNode itemTemplate 实例
|
|
* @param gemId 宝石 id;0=空
|
|
*/
|
|
private _paintSlot(slotNode: Node, gemId: number): void {
|
|
const qbg = slotNode.getChildByName('qbg');
|
|
const icon = slotNode.getChildByName('icon');
|
|
const lbName = slotNode.getChildByName('lbName')?.getComponent(Label);
|
|
const conf = gemId > 0 ? gg.gem.getGem(gemId) : null;
|
|
if (!conf) {
|
|
this._setWeaponSprite(qbg, 'weapon/宝石框小0');
|
|
this._setWeaponSprite(icon, '');
|
|
if (icon?.isValid) icon.active = false;
|
|
if (lbName?.isValid) lbName.string = '';
|
|
return;
|
|
}
|
|
const quality = Math.floor(Number(conf.quality) || 0);
|
|
this._setWeaponSprite(qbg, `weapon/宝石框小${Math.max(0, Math.min(5, quality))}`);
|
|
const iconName = String(conf.icon || '').trim();
|
|
if (!iconName) console.warn(LOG, 'icon 缺失', gemId);
|
|
this._setWeaponSprite(icon, iconName ? `weapon/${iconName}` : '');
|
|
if (icon?.isValid) icon.active = !!iconName;
|
|
if (lbName?.isValid) lbName.string = String(conf.name ?? '').trim();
|
|
}
|
|
|
|
/**
|
|
* 重建当前页签仓库(打开 / 切页签 / 合成)。
|
|
* 镶嵌成败勿调用。
|
|
*/
|
|
private _rebuildBag(): void {
|
|
if (!this.ui_content?.isValid || !this._bagTpl?.isValid) {
|
|
console.warn(LOG, 'ui_content/bagItemTemplate 缺失');
|
|
return;
|
|
}
|
|
this._stopBagFill();
|
|
for (let i = 0; i < this._bagItems.length; i++) {
|
|
const n = this._bagItems[i];
|
|
if (n?.isValid) n.destroy();
|
|
}
|
|
this._bagItems.length = 0;
|
|
this._bagList = gg.gem.getBagList(this._filterType);
|
|
this._bagFillIndex = 0;
|
|
this._bagToken++;
|
|
this._pumpBagFill(this._bagToken);
|
|
}
|
|
|
|
/** 停掉仓库分帧 */
|
|
private _stopBagFill(): void {
|
|
this._bagToken++;
|
|
this._flow?.dispose();
|
|
this._flow = null;
|
|
}
|
|
|
|
/** 分帧填充仓库格 */
|
|
private _pumpBagFill(token: number): void {
|
|
if (!this.isValid || token !== this._bagToken) return;
|
|
if (!this.ui_content?.isValid || !this._bagTpl?.isValid) return;
|
|
const end = Math.min(this._bagFillIndex + BAG_PER_FRAME, this._bagList.length);
|
|
for (let i = this._bagFillIndex; i < end; i++) {
|
|
this._bagItems.push(this._spawnBagItem(this._bagList[i]));
|
|
}
|
|
this._bagFillIndex = end;
|
|
if (this._bagFillIndex >= this._bagList.length) return;
|
|
if (!this._flow) this._flow = new FrameFlowHost();
|
|
this._flow.waitFrames(1, () => this._pumpBagFill(token));
|
|
}
|
|
|
|
/** 创建一格仓库项 */
|
|
private _spawnBagItem(entry: IGemBagEntry): Node {
|
|
const node = instantiate(this._bagTpl!);
|
|
node.parent = this.ui_content;
|
|
node.active = true;
|
|
const grid = node.getComponent(GemGrid) || node.addComponent(GemGrid);
|
|
grid.setData(gg.gem.getGem(entry.gemId), entry.count);
|
|
(node as any)._gemId = entry.gemId;
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* 镶嵌/卸下后局部同步仓库数量。
|
|
* @param gemIds 涉及的宝石 id
|
|
*/
|
|
private _patchBagGems(gemIds: readonly number[]): void {
|
|
for (let i = 0; i < gemIds.length; i++) {
|
|
const gemId = Math.floor(Number(gemIds[i]) || 0);
|
|
if (gemId <= 0) continue;
|
|
const free = gg.gem.getFreeCount(gemId);
|
|
const conf = gg.gem.getGem(gemId);
|
|
const matchFilter = this._matchFilter(conf);
|
|
const idx = this._findBagItemIndex(gemId);
|
|
if (free <= 0 || !matchFilter) {
|
|
if (idx >= 0) this._removeBagItemAt(idx);
|
|
continue;
|
|
}
|
|
if (idx >= 0) {
|
|
const node = this._bagItems[idx];
|
|
node.getComponent(GemGrid)?.setData(conf, free);
|
|
this._bagList[idx] = { gemId, count: free };
|
|
continue;
|
|
}
|
|
const entry: IGemBagEntry = { gemId, count: free };
|
|
this._bagList.push(entry);
|
|
this._bagItems.push(this._spawnBagItem(entry));
|
|
}
|
|
}
|
|
|
|
/** 当前页签是否应展示该宝石 */
|
|
private _matchFilter(conf: ITableWeapon | null): boolean {
|
|
if (!conf) return false;
|
|
return Math.floor(Number(conf.type) || 0) === this._filterType;
|
|
}
|
|
|
|
/** 查找仓库格下标 */
|
|
private _findBagItemIndex(gemId: number): number {
|
|
for (let i = 0; i < this._bagItems.length; i++) {
|
|
if (Number((this._bagItems[i] as any)._gemId) === gemId) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/** 移除一格仓库 */
|
|
private _removeBagItemAt(idx: number): void {
|
|
const node = this._bagItems[idx];
|
|
if (node?.isValid) node.destroy();
|
|
this._bagItems.splice(idx, 1);
|
|
this._bagList.splice(idx, 1);
|
|
}
|
|
|
|
/** icons/weapon */
|
|
private _setWeaponSprite(node: Node | null, path: string): void {
|
|
if (!node?.isValid) return;
|
|
if (!path) {
|
|
node.getComponent(SpriteLoad)?.clear();
|
|
const spComp = node.getComponent(Sprite);
|
|
if (spComp) spComp.spriteFrame = null;
|
|
return;
|
|
}
|
|
if (!node.getComponent(Sprite)) node.addComponent(Sprite);
|
|
node.getOrAddComponent(SpriteLoad).setSprite(path, GBundle.Items);
|
|
}
|
|
|
|
// ---------- 拖拽镶嵌 ----------
|
|
|
|
private _bindDrag(on: boolean): void {
|
|
if (this._dragListening === on) return;
|
|
this._dragListening = on;
|
|
if (on) {
|
|
this.node.on(Node.EventType.TOUCH_START, this._onTouchStart, this, true);
|
|
this.node.on(Node.EventType.TOUCH_MOVE, this._onTouchMove, this, true);
|
|
this.node.on(Node.EventType.TOUCH_END, this._onTouchEnd, this, true);
|
|
this.node.on(Node.EventType.TOUCH_CANCEL, this._onTouchEnd, this, true);
|
|
input.on(Input.EventType.MOUSE_DOWN, this._onMouseDown, this);
|
|
input.on(Input.EventType.MOUSE_MOVE, this._onMouseMove, this);
|
|
input.on(Input.EventType.MOUSE_UP, this._onMouseUp, this);
|
|
} else {
|
|
this.node.off(Node.EventType.TOUCH_START, this._onTouchStart, this, true);
|
|
this.node.off(Node.EventType.TOUCH_MOVE, this._onTouchMove, this, true);
|
|
this.node.off(Node.EventType.TOUCH_END, this._onTouchEnd, this, true);
|
|
this.node.off(Node.EventType.TOUCH_CANCEL, this._onTouchEnd, this, true);
|
|
input.off(Input.EventType.MOUSE_DOWN, this._onMouseDown, this);
|
|
input.off(Input.EventType.MOUSE_MOVE, this._onMouseMove, this);
|
|
input.off(Input.EventType.MOUSE_UP, this._onMouseUp, this);
|
|
}
|
|
}
|
|
|
|
private _onTouchStart(e: EventTouch): void { this._pointerStart(e.getUILocation()); }
|
|
private _onTouchMove(e: EventTouch): void { this._pointerMove(e.getUILocation()); }
|
|
private _onTouchEnd(e: EventTouch): void { this._pointerEnd(e.getUILocation()); }
|
|
|
|
private _onMouseDown(e: EventMouse): void {
|
|
if (e.getButton() !== EventMouse.BUTTON_LEFT) return;
|
|
this._pointerStart(e.getUILocation());
|
|
}
|
|
private _onMouseMove(e: EventMouse): void { this._pointerMove(e.getUILocation()); }
|
|
private _onMouseUp(e: EventMouse): void { this._pointerEnd(e.getUILocation()); }
|
|
|
|
private _pointerStart(loc: Vec2): void {
|
|
if (this._pressing || this._dragging) return;
|
|
const bag = this._hitBag(loc);
|
|
if (bag) {
|
|
const gemId = Number((bag as any)._gemId) || 0;
|
|
if (gemId <= 0) return;
|
|
this._resetDrag();
|
|
this._pressing = true;
|
|
this._dragStart.set(loc);
|
|
this._dragGemId = gemId;
|
|
this._dragFromElement = 0;
|
|
this._dragFromSlot = -1;
|
|
return;
|
|
}
|
|
const slot = this._hitSlot(loc);
|
|
if (!slot) return;
|
|
const element = Number((slot as any)._element) || 0;
|
|
const si = Number((slot as any)._slot);
|
|
if (element <= 0 || si < 0) return;
|
|
const gemId = gg.gem.getSlotGem(element, si);
|
|
if (gemId <= 0) return;
|
|
this._resetDrag();
|
|
this._pressing = true;
|
|
this._dragStart.set(loc);
|
|
this._dragGemId = gemId;
|
|
this._dragFromElement = element;
|
|
this._dragFromSlot = si;
|
|
}
|
|
|
|
private _pointerMove(loc: Vec2): void {
|
|
if (this._dragging) {
|
|
this._moveGhost(loc);
|
|
return;
|
|
}
|
|
if (!this._pressing || this._dragGemId <= 0) return;
|
|
const dx = loc.x - this._dragStart.x;
|
|
const dy = loc.y - this._dragStart.y;
|
|
if (dx * dx + dy * dy < DRAG_THRESHOLD * DRAG_THRESHOLD) return;
|
|
this._beginDrag(loc);
|
|
}
|
|
|
|
private _pointerEnd(loc: Vec2): void {
|
|
if (!this._pressing && !this._dragging) return;
|
|
if (this._dragging) {
|
|
this._finishDrag(loc);
|
|
return;
|
|
}
|
|
const gemId = this._dragGemId;
|
|
const fromSlot = this._dragFromElement > 0 && this._dragFromSlot >= 0;
|
|
this._endDrag();
|
|
if (fromSlot && gemId > 0) GemGrid.openInfo(gemId);
|
|
}
|
|
|
|
private _beginDrag(loc: Vec2): void {
|
|
this._dragging = true;
|
|
this._spawnGhost(loc);
|
|
this._moveGhost(loc);
|
|
}
|
|
|
|
private _finishDrag(loc: Vec2): void {
|
|
const gemId = this._dragGemId;
|
|
const fromE = this._dragFromElement;
|
|
const fromS = this._dragFromSlot;
|
|
const toSlot = this._hitSlot(loc);
|
|
const toBag = this._hitBagArea(loc);
|
|
this._endDrag();
|
|
if (gemId <= 0) return;
|
|
|
|
if (toSlot) {
|
|
const te = Number((toSlot as any)._element) || 0;
|
|
const ts = Number((toSlot as any)._slot);
|
|
if (te <= 0 || ts < 0) return;
|
|
if (fromE > 0 && fromS >= 0) {
|
|
if (fromE === te && fromS === ts) return;
|
|
if (!gg.gem.swapSlots(fromE, fromS, te, ts)) {
|
|
gg.ui.showToast('无法镶嵌到该位置');
|
|
return;
|
|
}
|
|
this._refreshSlots();
|
|
return;
|
|
}
|
|
const before = gg.gem.getSlotGem(te, ts);
|
|
if (!gg.gem.wearFromBag(te, ts, gemId)) {
|
|
gg.ui.showToast('无法镶嵌到该位置');
|
|
return;
|
|
}
|
|
this._refreshSlots();
|
|
const patch = [gemId];
|
|
if (before > 0 && before !== gemId) patch.push(before);
|
|
this._patchBagGems(patch);
|
|
return;
|
|
}
|
|
|
|
if (fromE > 0 && fromS >= 0 && toBag) {
|
|
const worn = gg.gem.getSlotGem(fromE, fromS);
|
|
if (worn <= 0) return;
|
|
if (!gg.gem.unequip(fromE, fromS)) return;
|
|
this._refreshSlots();
|
|
this._patchBagGems([worn]);
|
|
}
|
|
}
|
|
|
|
private _spawnGhost(loc: Vec2): void {
|
|
this._clearGhost();
|
|
const tpl = this._bagTpl;
|
|
if (!tpl?.isValid) return;
|
|
const conf = gg.gem.getGem(this._dragGemId);
|
|
if (!conf) return;
|
|
const ghost = instantiate(tpl);
|
|
ghost.parent = this.node;
|
|
ghost.active = true;
|
|
const grid = ghost.getComponent(GemGrid) || ghost.addComponent(GemGrid);
|
|
grid.canClick = false;
|
|
grid.setData(conf, -1);
|
|
const op = ghost.getComponent(UIOpacity) || ghost.addComponent(UIOpacity);
|
|
op.opacity = GHOST_OPACITY;
|
|
const ut = ghost.getComponent(UITransform);
|
|
if (ut) ut.hitTest = () => false;
|
|
this._ghost = ghost;
|
|
this._moveGhost(loc);
|
|
}
|
|
|
|
private _moveGhost(loc: Vec2): void {
|
|
if (this._ghost?.isValid) {
|
|
this._ghost.setWorldPosition(this._ghostPos.set(loc.x, loc.y, 0));
|
|
}
|
|
}
|
|
|
|
private _clearGhost(): void {
|
|
if (this._ghost?.isValid) this._ghost.destroy();
|
|
this._ghost = null;
|
|
}
|
|
|
|
private _endDrag(): void {
|
|
this._clearGhost();
|
|
this._resetDrag();
|
|
}
|
|
|
|
private _resetDrag(): void {
|
|
this._pressing = false;
|
|
this._dragging = false;
|
|
this._dragGemId = 0;
|
|
this._dragFromElement = 0;
|
|
this._dragFromSlot = -1;
|
|
}
|
|
|
|
private _hitBag(loc: Vec2): Node | null {
|
|
if (!this.ui_content?.isValid) return null;
|
|
this._hitPos.set(loc.x, loc.y);
|
|
for (let i = this._bagItems.length - 1; i >= 0; i--) {
|
|
const child = this._bagItems[i];
|
|
if (!child?.activeInHierarchy) continue;
|
|
const ut = child.getComponent(UITransform);
|
|
if (ut?.getBoundingBoxToWorld().contains(this._hitPos)) return child;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private _hitSlot(loc: Vec2): Node | null {
|
|
this._hitPos.set(loc.x, loc.y);
|
|
for (let i = 0; i < this._slotItems.length; i++) {
|
|
const item = this._slotItems[i];
|
|
if (!item?.activeInHierarchy) continue;
|
|
const ut = item.getComponent(UITransform);
|
|
if (ut?.getBoundingBoxToWorld().contains(this._hitPos)) return item;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** 是否落在仓库区(卸下) */
|
|
private _hitBagArea(loc: Vec2): boolean {
|
|
const root = this.ui_content;
|
|
if (!root?.isValid) return false;
|
|
this._hitPos.set(loc.x, loc.y);
|
|
const ut = root.getComponent(UITransform);
|
|
return !!ut?.getBoundingBoxToWorld().contains(this._hitPos);
|
|
}
|
|
}
|
|
|