feat(ui): 为抽卡和升级按钮添加触摸动画效果

- 新增按钮按下、点击和取消的缩放动画,提升交互反馈
- 添加 hero_info_node 和 hero_info_prefab 属性,为后续功能预留
- 引入新的 hnode.prefab 资源文件
- 重构按钮事件监听,从 TOUCH_END 改为多阶段触摸事件
This commit is contained in:
panw
2026-03-25 16:38:14 +08:00
parent b778b6d128
commit 338394f6ff
4 changed files with 4459 additions and 2696 deletions

View File

@@ -1,5 +1,5 @@
import { mLogger } from "../common/Logger";
import { _decorator, Label, Node, NodeEventType, SpriteAtlas } from "cc";
import { _decorator, Label, Node, NodeEventType, Prefab, SpriteAtlas, Tween, tween, Vec3 } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { GameEvent } from "../common/config/GameEvent";
@@ -17,6 +17,9 @@ const { ccclass, property } = _decorator;
export class MissionCardComp extends CCComp {
private debugMode: boolean = true;
private readonly cardWidth: number = 175;
private readonly buttonNormalScale: number = 1;
private readonly buttonPressScale: number = 0.94;
private readonly buttonClickScale: number = 1.06;
/** 四个插卡槽位固定顺序分发1~4 */
@property(Node)
card1:Node = null!
@@ -34,8 +37,10 @@ export class MissionCardComp extends CCComp {
coins_node:Node = null!
@property(Node)
pool_lv_node:Node = null!
// @property(Node)
// coins:Node = null!
@property(Node)
hero_info_node:Node = null!
@property(Prefab)
hero_info_prefab:Prefab=null!
/** 预留图集缓存(后续接入按钮/卡面图标时复用) */
private uiconsAtlas: SpriteAtlas | null = null;
/** 四个槽位对应的单卡控制器缓存 */
@@ -71,6 +76,8 @@ export class MissionCardComp extends CCComp {
if (this.cards_up) {
this.cards_up.active = true;
}
this.resetButtonScale(this.cards_chou);
this.resetButtonScale(this.cards_up);
this.updatePoolLvUI();
this.updateCoinUI();
this.node.active = true;
@@ -106,8 +113,12 @@ export class MissionCardComp extends CCComp {
this.on(GameEvent.CoinAdd, this.onCoinAdd, this);
/** 按钮事件:抽卡与卡池升级 */
this.cards_chou?.on(NodeEventType.TOUCH_END, this.onClickDraw, this);
this.cards_up?.on(NodeEventType.TOUCH_END, this.onClickUpgrade, this);
this.cards_chou?.on(NodeEventType.TOUCH_START, this.onDrawTouchStart, this);
this.cards_chou?.on(NodeEventType.TOUCH_END, this.onDrawTouchEnd, this);
this.cards_chou?.on(NodeEventType.TOUCH_CANCEL, this.onDrawTouchCancel, this);
this.cards_up?.on(NodeEventType.TOUCH_START, this.onUpgradeTouchStart, this);
this.cards_up?.on(NodeEventType.TOUCH_END, this.onUpgradeTouchEnd, this);
this.cards_up?.on(NodeEventType.TOUCH_CANCEL, this.onUpgradeTouchCancel, this);
}
private onCoinAdd(args:any){
const v = typeof args === 'number' ? args : (args?.delta ?? args?.value ?? 0);
@@ -118,8 +129,36 @@ export class MissionCardComp extends CCComp {
/** 解除按钮监听,避免节点销毁后回调泄漏 */
private unbindEvents() {
this.cards_chou?.off(NodeEventType.TOUCH_END, this.onClickDraw, this);
this.cards_up?.off(NodeEventType.TOUCH_END, this.onClickUpgrade, this);
this.cards_chou?.off(NodeEventType.TOUCH_START, this.onDrawTouchStart, this);
this.cards_chou?.off(NodeEventType.TOUCH_END, this.onDrawTouchEnd, this);
this.cards_chou?.off(NodeEventType.TOUCH_CANCEL, this.onDrawTouchCancel, this);
this.cards_up?.off(NodeEventType.TOUCH_START, this.onUpgradeTouchStart, this);
this.cards_up?.off(NodeEventType.TOUCH_END, this.onUpgradeTouchEnd, this);
this.cards_up?.off(NodeEventType.TOUCH_CANCEL, this.onUpgradeTouchCancel, this);
}
private onDrawTouchStart() {
this.playButtonPressAnim(this.cards_chou);
}
private onDrawTouchEnd() {
this.playButtonClickAnim(this.cards_chou, () => this.onClickDraw());
}
private onDrawTouchCancel() {
this.playButtonResetAnim(this.cards_chou);
}
private onUpgradeTouchStart() {
this.playButtonPressAnim(this.cards_up);
}
private onUpgradeTouchEnd() {
this.playButtonClickAnim(this.cards_up, () => this.onClickUpgrade());
}
private onUpgradeTouchCancel() {
this.playButtonResetAnim(this.cards_up);
}
/** 将四个卡槽节点映射为 CardComp形成固定顺序控制数组 */
@@ -215,6 +254,49 @@ export class MissionCardComp extends CCComp {
startX
});
}
private playButtonPressAnim(node: Node | null) {
if (!node || !node.isValid) return;
Tween.stopAllByTarget(node);
tween(node)
.to(0.06, {
scale: new Vec3(this.buttonPressScale, this.buttonPressScale, 1)
})
.start();
}
private playButtonClickAnim(node: Node | null, onComplete: () => void) {
if (!node || !node.isValid) {
onComplete();
return;
}
Tween.stopAllByTarget(node);
tween(node)
.to(0.05, {
scale: new Vec3(this.buttonClickScale, this.buttonClickScale, 1)
})
.call(onComplete)
.to(0.08, {
scale: new Vec3(this.buttonNormalScale, this.buttonNormalScale, 1)
})
.start();
}
private playButtonResetAnim(node: Node | null) {
if (!node || !node.isValid) return;
Tween.stopAllByTarget(node);
tween(node)
.to(0.08, {
scale: new Vec3(this.buttonNormalScale, this.buttonNormalScale, 1)
})
.start();
}
private resetButtonScale(node: Node | null) {
if (!node || !node.isValid) return;
Tween.stopAllByTarget(node);
node.setScale(this.buttonNormalScale, this.buttonNormalScale, 1);
}
private canUpPool() {
if (this.poolLv >= CARD_POOL_MAX_LEVEL) return false;
const currentCoin = this.coin ?? 0;
@@ -259,6 +341,8 @@ export class MissionCardComp extends CCComp {
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.resetButtonScale(this.cards_chou);
this.resetButtonScale(this.cards_up);
this.node.destroy();
}
}