feat(card): 添加长按放大功能并调整卡牌布局

- 在 CardComp 中实现长按触发卡牌放大,优化触摸交互逻辑
- 调整 MissionCardComp 中卡牌位置数组顺序,修复布局错位
- 修改 card.prefab 中多个 UI 元素的坐标和对齐方式,优化视觉呈现
- 移除卡牌种类标识的显示逻辑,简化卡牌 UI
This commit is contained in:
walkpan
2026-04-20 23:59:38 +08:00
parent 033fd44560
commit 0829b0bc9d
3 changed files with 135 additions and 29 deletions

View File

@@ -123,6 +123,12 @@ export class CardComp extends CCComp {
private iconVisualToken: number = 0;
/** 是否处于放大状态 */
private isEnlarged: boolean = false;
/** 长按定时器标记 */
private longPressTimer: any = null;
/** 是否触发了长按 */
private isLongPressed: boolean = false;
/** 长按触发时间(秒) */
private readonly LONG_PRESS_DURATION: number = 0.5;
// ======================== 生命周期 ========================
@@ -502,6 +508,20 @@ export class CardComp extends CCComp {
if (!this.cardData || this.isUsing) return;
this.touchStartY = event.getUILocation().y;
this.isDragging = true;
this.isLongPressed = false;
// 开启长按定时器
this.unschedule(this.onLongPress);
this.scheduleOnce(this.onLongPress, this.LONG_PRESS_DURATION);
}
/** 长按触发逻辑 */
private onLongPress() {
if (!this.isDragging || this.isUsing) return;
this.isLongPressed = true;
this.isEnlarged = true;
this.applyCardUI();
this.playReboundAnim();
}
/**
@@ -512,6 +532,15 @@ export class CardComp extends CCComp {
const currentY = event.getUILocation().y;
const deltaY = Math.max(0, currentY - this.touchStartY);
// 拖拽距离超过一定阈值,取消长按
if (deltaY > 10) {
this.unschedule(this.onLongPress);
if (this.isLongPressed && !this.isEnlarged) {
// 如果已经触发了长按但想取消放大(比如拖拽时恢复),视情况处理
// 这里我们认为一旦拖动就取消未触发的长按,如果已经触发放大则保持放大直到松手
}
}
let baseX = this.restPosition.x;
let baseY = this.restPosition.y;
if (this.isEnlarged) {
@@ -529,31 +558,45 @@ export class CardComp extends CCComp {
/**
* 触摸结束:
* - 上拉距离 >= dragUseThreshold → 视为"使用卡牌"
* - 否则视为"点击",切换放大缩小状态并回弹
* - 否则视为"点击"或者"长按结束"
*/
private onCardTouchEnd(event: EventTouch) {
this.unschedule(this.onLongPress);
if (!this.isDragging || !this.cardData || this.isUsing) return;
const endY = event.getUILocation().y;
const deltaY = endY - this.touchStartY;
this.isDragging = false;
if (deltaY >= this.dragUseThreshold) {
this.useCard();
// 使用卡牌后恢复非放大状态
this.isEnlarged = false;
this.isLongPressed = false;
return;
}
this.toggleEnlarge();
// 无论是点击还是长按松手,都恢复正常大小
if (this.isEnlarged) {
this.isEnlarged = false;
this.applyCardUI();
}
this.isLongPressed = false;
this.playReboundAnim();
}
/** 切换卡牌的放大/缩小状态 */
private toggleEnlarge() {
this.isEnlarged = !this.isEnlarged;
this.applyCardUI();
}
/** 触摸取消:回弹至原位 */
private onCardTouchCancel() {
this.unschedule(this.onLongPress);
if (!this.isDragging || this.isUsing) return;
this.isDragging = false;
if (this.isEnlarged) {
this.isEnlarged = false;
this.applyCardUI();
}
this.isLongPressed = false;
this.playReboundAnim();
}
@@ -619,12 +662,12 @@ export class CardComp extends CCComp {
this.node.setPosition(targetX, targetY, this.restPosition.z);
// ---- 卡牌种类标识(近战 / 远程 / 辅助等) ----
if (this.Ckind_node) {
const kindName = CKind[this.cardData.kind];
this.Ckind_node.children.forEach(child => {
child.active = (child.name === kindName);
});
}
// if (this.Ckind_node) {
// const kindName = CKind[this.cardData.kind];
// this.Ckind_node.children.forEach(child => {
// child.active = (child.name === kindName);
// });
// }
// ---- 背景底框(按卡池等级显示对应子节点) ----
const cardLvStr = `lv${this.cardData.pool_lv}`;
@@ -653,6 +696,40 @@ export class CardComp extends CCComp {
if (uiTrans) {
uiTrans.setContentSize(this.isEnlarged ? 230 : 170, this.isEnlarged ? 300 : 230);
}
// 同时修改背景节点和边框节点的尺寸
if (this.BG_node) {
const bgTrans = this.BG_node.getComponent(UITransform);
if (bgTrans) bgTrans.setContentSize(this.isEnlarged ? 230 : 170, this.isEnlarged ? 300 : 230);
this.BG_node.children.forEach(child => {
const childTrans = child.getComponent(UITransform);
if (childTrans) childTrans.setContentSize(this.isEnlarged ? 230 : 170, this.isEnlarged ? 300 : 230);
});
}
if (this.HF_node) {
const hfTrans = this.HF_node.getComponent(UITransform);
if (hfTrans) hfTrans.setContentSize(this.isEnlarged ? 230 : 170, this.isEnlarged ? 300 : 230);
this.HF_node.children.forEach(child => {
const childTrans = child.getComponent(UITransform);
if (childTrans) childTrans.setContentSize(this.isEnlarged ? 230 : 170, this.isEnlarged ? 300 : 230);
});
}
if (this.NF_node) {
const nfTrans = this.NF_node.getComponent(UITransform);
if (nfTrans) nfTrans.setContentSize(this.isEnlarged ? 230 : 170, this.isEnlarged ? 300 : 230);
this.NF_node.children.forEach(child => {
const childTrans = child.getComponent(UITransform);
if (childTrans) childTrans.setContentSize(this.isEnlarged ? 230 : 170, this.isEnlarged ? 300 : 230);
});
}
const hbNode = this.node.getChildByName("HB");
if (hbNode) {
const hbTrans = hbNode.getComponent(UITransform);
if (hbTrans) hbTrans.setContentSize(this.isEnlarged ? 230 : 170, this.isEnlarged ? 300 : 230);
}
if(this.card_type===CardType.Hero){
// 英雄卡:显示英雄名 + 星级 + AP/HP
@@ -801,16 +878,45 @@ export class CardComp extends CCComp {
if (uiTrans) {
uiTrans.setContentSize(170, 230);
}
if (this.BG_node) {
const bgTrans = this.BG_node.getComponent(UITransform);
if (bgTrans) bgTrans.setContentSize(170, 230);
this.BG_node.children.forEach(child => {
const childTrans = child.getComponent(UITransform);
if (childTrans) childTrans.setContentSize(170, 230);
});
}
if (this.HF_node) {
const hfTrans = this.HF_node.getComponent(UITransform);
if (hfTrans) hfTrans.setContentSize(170, 230);
this.HF_node.children.forEach(child => {
const childTrans = child.getComponent(UITransform);
if (childTrans) childTrans.setContentSize(170, 230);
});
}
if (this.NF_node) {
const nfTrans = this.NF_node.getComponent(UITransform);
if (nfTrans) nfTrans.setContentSize(170, 230);
this.NF_node.children.forEach(child => {
const childTrans = child.getComponent(UITransform);
if (childTrans) childTrans.setContentSize(170, 230);
});
}
const hbNode = this.node.getChildByName("HB");
if (hbNode) {
const hbTrans = hbNode.getComponent(UITransform);
if (hbTrans) hbTrans.setContentSize(170, 230);
}
this.iconVisualToken += 1;
this.setLabel(this.name_node, "");
this.setLabel(this.cost_node, "");
if (this.info_node) this.info_node.active = false;
if (this.oinfo_node) this.oinfo_node.active = false;
if (this.Ckind_node) {
this.Ckind_node.children.forEach(child => {
child.active = false;
});
}
// if (this.Ckind_node) {
// this.Ckind_node.children.forEach(child => {
// child.active = false;
// });
// }
if (this.BG_node) {
this.BG_node.children.forEach(child => child.active = false);
}