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.
153 lines
5.6 KiB
153 lines
5.6 KiB
import { _decorator, Component, EventTouch, Label, Node, Sprite, Vec2 } from 'cc';
|
|
import { SpriteLoad } from 'db://assets/mx/components/SpriteLoad';
|
|
import { GBundle, UIID } from '../game/ConfigRes';
|
|
const { ccclass } = _decorator;
|
|
|
|
const LOG = '[GemGrid]';
|
|
/** 超过此位移视为拖拽,不弹信息 */
|
|
const TAP_THRESHOLD = 18;
|
|
|
|
/**
|
|
* 宝石格子:仓库 / 获得弹窗共用。
|
|
* bg=宝石框大{quality};icon=Weapon.icon;lbNum=数量;lbName=名称。
|
|
* 轻点打开 PopGemInfo(拖拽不触发)。
|
|
*/
|
|
@ccclass('GemGrid')
|
|
export class GemGrid extends Component {
|
|
|
|
/** 是否响应轻点打开信息 */
|
|
canClick = true;
|
|
/** 品质框 */
|
|
bg: Node = null!;
|
|
/** 宝石图标 */
|
|
icon: Node = null!;
|
|
/** 数量 */
|
|
lbNum: Label = null!;
|
|
/** 宝石名称 */
|
|
lbName: Label = null!;
|
|
/** 当前宝石配表 */
|
|
data: ITableWeapon | null = null;
|
|
|
|
private _pressing = false;
|
|
private _pressStart = new Vec2();
|
|
|
|
protected onLoad(): void {
|
|
this._bindNodes();
|
|
}
|
|
|
|
protected onEnable(): void {
|
|
this.node.on(Node.EventType.TOUCH_START, this._onTouchStart, this);
|
|
this.node.on(Node.EventType.TOUCH_END, this._onTouchEnd, this);
|
|
this.node.on(Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
|
|
}
|
|
|
|
protected onDisable(): void {
|
|
this.node.off(Node.EventType.TOUCH_START, this._onTouchStart, this);
|
|
this.node.off(Node.EventType.TOUCH_END, this._onTouchEnd, this);
|
|
this.node.off(Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
|
|
this._pressing = false;
|
|
}
|
|
|
|
/**
|
|
* 打开宝石信息弹窗。
|
|
* @param gemId Weapon.id
|
|
*/
|
|
static openInfo(gemId: number): void {
|
|
const id = Math.floor(Number(gemId) || 0);
|
|
if (id <= 0) return;
|
|
void gg.ui.openPanel(UIID.PopGemInfo, { data: id });
|
|
}
|
|
|
|
/**
|
|
* 绑定展示数据。
|
|
* @param data Weapon 行;null 表示空
|
|
* @param count 数量;传负数隐藏数量文案
|
|
*/
|
|
setData(data: ITableWeapon | null, count = 0): void {
|
|
this._bindNodes();
|
|
this.data = data;
|
|
const quality = data ? Math.floor(Number(data.quality) || 0) : 0;
|
|
if (!data) {
|
|
this._setSprite(this.bg, '', false);
|
|
this._setSprite(this.icon, '', true);
|
|
if (this.icon?.isValid) this.icon.active = false;
|
|
if (this.lbName?.isValid) this.lbName.string = '';
|
|
} else {
|
|
if (quality < 1 || quality > 5) console.warn(LOG, '品质无对应宝石框大', data.id, quality);
|
|
this._setSprite(this.bg, `weapon/宝石框大${quality}`, false);
|
|
const iconName = String(data.icon || '').trim();
|
|
if (!iconName) console.warn(LOG, 'icon 缺失', data.id);
|
|
this._setSprite(this.icon, iconName ? `weapon/${iconName}` : '', true);
|
|
if (this.icon?.isValid) this.icon.active = !!iconName;
|
|
if (this.lbName?.isValid) this.lbName.string = String(data.name ?? '').trim();
|
|
}
|
|
if (this.lbNum?.isValid) {
|
|
const showNum = count >= 0;
|
|
this.lbNum.node.active = showNum;
|
|
if (showNum) this.lbNum.string = `${Math.max(0, count | 0)}`;
|
|
}
|
|
}
|
|
|
|
/** 按下 */
|
|
private _onTouchStart(e: EventTouch): void {
|
|
this._pressing = true;
|
|
this._pressStart.set(e.getUILocation());
|
|
}
|
|
|
|
/** 抬起:位移未超阈值则打开信息 */
|
|
private _onTouchEnd(e: EventTouch): void {
|
|
if (!this._pressing) return;
|
|
this._pressing = false;
|
|
if (!this.canClick || !this.data) return;
|
|
const loc = e.getUILocation();
|
|
const dx = loc.x - this._pressStart.x;
|
|
const dy = loc.y - this._pressStart.y;
|
|
if (dx * dx + dy * dy >= TAP_THRESHOLD * TAP_THRESHOLD) return;
|
|
GemGrid.openInfo(Number(this.data.id) || 0);
|
|
}
|
|
|
|
/** 取消按下 */
|
|
private _onTouchCancel(): void {
|
|
this._pressing = false;
|
|
}
|
|
|
|
/** 绑定子节点 */
|
|
private _bindNodes(): void {
|
|
if (!this.bg?.isValid) this.bg = this.node.getChildByName('bg')!;
|
|
if (!this.icon?.isValid) this.icon = this.node.getChildByName('icon')!;
|
|
if (!this.lbNum?.isValid) {
|
|
const n = this.node.getChildByName('lbNum');
|
|
this.lbNum = n?.getComponent(Label) ?? null!;
|
|
}
|
|
if (!this.lbName?.isValid) {
|
|
const n = this.node.getChildByName('lbName');
|
|
this.lbName = n?.getComponent(Label) ?? null!;
|
|
}
|
|
if (!this.bg) console.warn(LOG, 'bg 节点缺失', this.node?.name);
|
|
}
|
|
|
|
/**
|
|
* icons/weapon 下图。
|
|
* @param nativeSize true=按贴图原始尺寸(不拉伸);false=铺满节点 UITransform
|
|
*/
|
|
private _setSprite(node: Node | null, path: string, nativeSize: boolean): void {
|
|
if (!node?.isValid) return;
|
|
if (!path) {
|
|
node.active = false;
|
|
node.getComponent(SpriteLoad)?.clear();
|
|
const sp = node.getComponent(Sprite);
|
|
if (sp) sp.spriteFrame = null;
|
|
return;
|
|
}
|
|
node.active = true;
|
|
if (!node.getComponent(Sprite)) node.addComponent(Sprite);
|
|
const sp = node.getComponent(Sprite)!;
|
|
sp.type = Sprite.Type.SIMPLE;
|
|
// icon 用 TRIMMED 跟贴图尺寸,避免 CUSTOM 拉伸变形
|
|
sp.sizeMode = nativeSize ? Sprite.SizeMode.TRIMMED : Sprite.SizeMode.CUSTOM;
|
|
node.getOrAddComponent(SpriteLoad).setSprite(path, GBundle.Items, () => {
|
|
if (!node.isValid || !sp.isValid) return;
|
|
sp.sizeMode = nativeSize ? Sprite.SizeMode.TRIMMED : Sprite.SizeMode.CUSTOM;
|
|
});
|
|
}
|
|
}
|
|
|