feat(map): 优化战斗流程与卡牌系统交互
1. 第一波准备阶段首个英雄召唤后自动开战,移除手动点击开始按钮 2. 重构卡牌交互逻辑,移除上划召唤改为点击召唤 3. 新增英雄卡池显隐切换功能 4. 调整卡牌预制体尺寸与布局 5. 移除特定波次技能卡弹窗逻辑 6. 简化引导流程,不再弹出Guide4
This commit is contained in:
@@ -3,13 +3,13 @@
|
||||
* @description 单张卡牌槽位组件(UI 视图层)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 管理单个卡牌槽位的 **显示** 和 **交互**(触摸拖拽 / 点击使用 / 锁定切换)。
|
||||
* 1. 管理单个卡牌槽位的 **显示** 和 **交互**(点击选中 / 召唤按钮 / 锁定切换)。
|
||||
* 2. 接收来自 MissionCardComp 分发的 CardConfig 数据,渲染对应卡面(英雄 / 技能 / 特殊卡)。
|
||||
* 3. 在玩家触发"使用卡牌"操作时,执行 **费用扣除 → 动画表现 → 效果分发** 的完整流程。
|
||||
*
|
||||
* 关键设计:
|
||||
* - 槽位可 **锁定**:锁定后刷新卡池不会覆盖旧卡,由 `isLocked` 控制。
|
||||
* - 卡牌使用支持 **上划手势** 与 **点击** 两种触发方式。
|
||||
* - 卡牌使用通过 **点击卡牌 → 显示召唤按钮 → 点击召唤按钮** 触发。
|
||||
* - 英雄卡图标使用 AnimationClip 动态加载 idle 动画;技能 / 特殊卡使用 SpriteAtlas 静态图标。
|
||||
* - 通过 `iconVisualToken` 防止异步加载资源回调与当前显示不一致(竞态保护)。
|
||||
*
|
||||
@@ -109,13 +109,7 @@ export class CardComp extends CCComp {
|
||||
private isLocked: boolean = false;
|
||||
/** 当前槽位承载的卡牌数据,null 表示空槽 */
|
||||
private cardData: CardConfig | null = null;
|
||||
/** 上划使用阈值(像素):拖拽距离 >= 此值视为"使用卡牌" */
|
||||
private readonly dragUseThreshold: number = 70;
|
||||
/** 触摸起始 Y 坐标,用于计算拖拽距离 */
|
||||
private touchStartY: number = 0;
|
||||
/** 触摸起始 X 坐标,用于点击判断 */
|
||||
private touchStartX: number = 0;
|
||||
/** 当前是否正在拖拽 */
|
||||
/** 当前是否正在触摸卡牌(用于阻止 setSlotPosition 等重置位置) */
|
||||
private isDragging: boolean = false;
|
||||
/** 当前是否正在执行"使用"流程(防止重复触发) */
|
||||
private isUsing: boolean = false;
|
||||
@@ -135,8 +129,6 @@ export class CardComp extends CCComp {
|
||||
* 防止快速切卡时旧回调错误覆盖新图标。
|
||||
*/
|
||||
private iconVisualToken: number = 0;
|
||||
/** 视为"点击"的最大位移阈值(像素),小于该值视为点击而非拖拽 */
|
||||
private readonly tapMoveThreshold: number = 10;
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
@@ -491,60 +483,35 @@ export class CardComp extends CCComp {
|
||||
|
||||
// ======================== 触摸交互 ========================
|
||||
|
||||
/** 触摸开始:记录起点坐标,进入拖拽状态 */
|
||||
/**
|
||||
* 触摸开始:标记正在触摸。
|
||||
* 注:已移除上划手势召唤,卡牌不跟随手指移动,仅通过点击显示 call_btn 召唤。
|
||||
*/
|
||||
private onCardTouchStart(event: EventTouch) {
|
||||
if (!this.cardData || this.isUsing) return;
|
||||
this.touchStartY = event.getUILocation().y;
|
||||
this.touchStartX = event.getUILocation().x;
|
||||
this.isDragging = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸移动:跟随手指向上偏移卡牌(仅允许向上拖拽,deltaY < 0 被 clamp 为 0)
|
||||
* 触摸移动:不做任何处理。
|
||||
* 卡牌不跟随手指位移,避免点击选中时产生位移。
|
||||
*/
|
||||
private onCardTouchMove(event: EventTouch) {
|
||||
if (!this.isDragging || !this.cardData || this.isUsing) return;
|
||||
const currentY = event.getUILocation().y;
|
||||
const deltaY = Math.max(0, currentY - this.touchStartY);
|
||||
this.node.setPosition(this.restPosition.x, this.restPosition.y + deltaY, this.restPosition.z);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸结束:
|
||||
* - 上拉距离 >= dragUseThreshold → 视为"使用卡牌"
|
||||
* - 位移很小(点击)→ 触发 onCardTap:显示 call_btn / 打开信息面板 / 通知其他卡牌联动
|
||||
* 触摸结束:视为点击,触发 onCardTap(显示召唤按钮 / 打开信息面板 / 通知其他卡牌联动)。
|
||||
*/
|
||||
private onCardTouchEnd(event: EventTouch) {
|
||||
if (!this.isDragging || !this.cardData || this.isUsing) return;
|
||||
const endY = event.getUILocation().y;
|
||||
const endX = event.getUILocation().x;
|
||||
const deltaY = endY - this.touchStartY;
|
||||
const deltaX = endX - this.touchStartX;
|
||||
this.isDragging = false;
|
||||
|
||||
// 英雄卡保持上划使用
|
||||
if (deltaY >= this.dragUseThreshold) {
|
||||
const used = this.useCard();
|
||||
if (!used) {
|
||||
this.playReboundAnim();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 位移小于阈值视为"点击"
|
||||
if (Math.abs(deltaY) < this.tapMoveThreshold && Math.abs(deltaX) < this.tapMoveThreshold) {
|
||||
this.onCardTap();
|
||||
return;
|
||||
}
|
||||
|
||||
this.playReboundAnim();
|
||||
this.onCardTap();
|
||||
}
|
||||
|
||||
/** 触摸取消:回弹至原位 */
|
||||
/** 触摸取消:仅重置触摸状态 */
|
||||
private onCardTouchCancel() {
|
||||
if (!this.isDragging || this.isUsing) return;
|
||||
this.isDragging = false;
|
||||
this.playReboundAnim();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -552,9 +519,10 @@ export class CardComp extends CCComp {
|
||||
* 1. 显示本卡的召唤按钮 call_btn。
|
||||
* 2. 派发 CardSelected 事件,其他卡牌收到后隐藏各自的 call_btn。
|
||||
* 3. 英雄卡打开 HInfo 信息面板(点击查看,替代原长按)。
|
||||
* 注:不重置位置。applyCardUI 中 widget.updateAlignment() 会让节点脱离 restPosition,
|
||||
* 这里若强制 setPosition(restPosition) 会导致可见的跳位。
|
||||
*/
|
||||
private onCardTap() {
|
||||
this.playReboundAnim();
|
||||
this.showCallBtn();
|
||||
oops.message.dispatchEvent(GameEvent.CardSelected, this);
|
||||
// 英雄卡打开信息面板(点击替代长按)
|
||||
@@ -694,7 +662,8 @@ export class CardComp extends CCComp {
|
||||
// ---- 按卡牌类型渲染具体内容 ----
|
||||
const uiTrans = this.node.getComponent(UITransform);
|
||||
if (uiTrans) {
|
||||
uiTrans.setContentSize(170, 230);
|
||||
// 卡牌尺寸由编辑器场景节点决定,不再硬编码
|
||||
// uiTrans.setContentSize(170, 230);
|
||||
const widget = this.node.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
@@ -702,14 +671,14 @@ export class CardComp extends CCComp {
|
||||
if (this.BG_node) {
|
||||
const bgTrans = this.BG_node.getComponent(UITransform);
|
||||
if (bgTrans) {
|
||||
bgTrans.setContentSize(170, 230);
|
||||
// bgTrans.setContentSize(170, 230);
|
||||
const widget = this.BG_node.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
this.BG_node.children.forEach(child => {
|
||||
const childTrans = child.getComponent(UITransform);
|
||||
if (childTrans) {
|
||||
childTrans.setContentSize(170, 230);
|
||||
// childTrans.setContentSize(170, 230);
|
||||
const widget = child.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
@@ -720,7 +689,7 @@ export class CardComp extends CCComp {
|
||||
if (hbNode) {
|
||||
const hbTrans = hbNode.getComponent(UITransform);
|
||||
if (hbTrans) {
|
||||
hbTrans.setContentSize(170, 230);
|
||||
// hbTrans.setContentSize(170, 230);
|
||||
const widget = hbNode.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
@@ -832,12 +801,15 @@ export class CardComp extends CCComp {
|
||||
.start();
|
||||
}
|
||||
|
||||
/** 回弹动画:从当前位置平滑回到静止位并恢复缩放 */
|
||||
/**
|
||||
* 回弹动画:仅恢复缩放到 1,不改变位置。
|
||||
* Why: applyCardUI 中 widget.updateAlignment() 会让节点脱离 restPosition,
|
||||
* 若强行 setPosition(restPosition) 会产生肉眼可见的跳位(如金币不足时反馈)。
|
||||
*/
|
||||
private playReboundAnim() {
|
||||
Tween.stopAllByTarget(this.node);
|
||||
tween(this.node)
|
||||
.to(0.12, {
|
||||
position: new Vec3(this.restPosition.x, this.restPosition.y, this.restPosition.z),
|
||||
scale: new Vec3(1, 1, 1)
|
||||
})
|
||||
.start();
|
||||
@@ -845,14 +817,15 @@ export class CardComp extends CCComp {
|
||||
|
||||
/**
|
||||
* 使用消失动画:
|
||||
* - 节点向上移动 120px 并缩小至 0.8
|
||||
* - 节点从当前位置向上移动 120px(X 轴保持当前值不变,不使用 restPosition.x)
|
||||
* - 同时 UIOpacity 渐隐至 0
|
||||
* - 动画完成后调用 onComplete 回调
|
||||
*
|
||||
* @param onComplete 动画完成后的回调
|
||||
*/
|
||||
private playUseDisappearAnim(onComplete: () => void) {
|
||||
const targetPos = new Vec3(this.restPosition.x, this.restPosition.y + 120, this.restPosition.z);
|
||||
const current = this.node.position;
|
||||
const targetPos = new Vec3(current.x, current.y + 120, current.z);
|
||||
Tween.stopAllByTarget(this.node);
|
||||
if (this.opacityComp) {
|
||||
Tween.stopAllByTarget(this.opacityComp);
|
||||
@@ -863,8 +836,7 @@ export class CardComp extends CCComp {
|
||||
}
|
||||
tween(this.node)
|
||||
.to(0.18, {
|
||||
position: targetPos,
|
||||
scale: new Vec3(0.8, 0.8, 1)
|
||||
position: targetPos
|
||||
})
|
||||
.call(onComplete)
|
||||
.start();
|
||||
@@ -877,21 +849,21 @@ export class CardComp extends CCComp {
|
||||
private applyEmptyUI() {
|
||||
const uiTrans = this.node.getComponent(UITransform);
|
||||
if (uiTrans) {
|
||||
uiTrans.setContentSize(170, 230);
|
||||
// uiTrans.setContentSize(170, 230);
|
||||
const widget = this.node.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
if (this.BG_node) {
|
||||
const bgTrans = this.BG_node.getComponent(UITransform);
|
||||
if (bgTrans) {
|
||||
bgTrans.setContentSize(170, 230);
|
||||
// bgTrans.setContentSize(170, 230);
|
||||
const widget = this.BG_node.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
this.BG_node.children.forEach(child => {
|
||||
const childTrans = child.getComponent(UITransform);
|
||||
if (childTrans) {
|
||||
childTrans.setContentSize(170, 230);
|
||||
// childTrans.setContentSize(170, 230);
|
||||
const widget = child.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
@@ -901,7 +873,7 @@ export class CardComp extends CCComp {
|
||||
if (hbNode) {
|
||||
const hbTrans = hbNode.getComponent(UITransform);
|
||||
if (hbTrans) {
|
||||
hbTrans.setContentSize(170, 230);
|
||||
// hbTrans.setContentSize(170, 230);
|
||||
const widget = hbNode.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user