|
|
@@ -1,4 +1,5 @@
|
|
|
-import { _decorator, Component, Node, Vec3, instantiate, UITransform, resources, sp, find, JsonAsset } from 'cc';
|
|
|
+import { _decorator, Component, Node, Vec3, tween, Color, Sprite, resources, sp, find } from 'cc';
|
|
|
+import EventBus, { GameEvents } from '../Core/EventBus';
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
/**
|
|
|
@@ -15,11 +16,102 @@ export class BallAni extends Component {
|
|
|
// 当前播放中的特效节点列表
|
|
|
private activeEffects: Node[] = [];
|
|
|
|
|
|
+ // 当前播放中的方块动画列表
|
|
|
+ private activeBlockAnimations: Map<Node, any> = new Map();
|
|
|
+
|
|
|
start() {
|
|
|
// 预加载撞击特效资源
|
|
|
this.preloadImpactEffect();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 播放方块被撞击动画
|
|
|
+ * @param blockNode 方块节点
|
|
|
+ */
|
|
|
+ public playBlockHitAnimation(blockNode: Node) {
|
|
|
+ if (!blockNode || !blockNode.isValid) {
|
|
|
+ console.warn('[BallAni] 方块节点无效');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果该方块已经在播放动画,跳过
|
|
|
+ if (this.activeBlockAnimations.has(blockNode)) {
|
|
|
+ console.log('[BallAni] 方块动画已在播放中,跳过');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否有活跃敌人,只有有敌人时才播放缩放动画
|
|
|
+ const eventBus = EventBus.getInstance();
|
|
|
+ let hasActiveEnemies = false;
|
|
|
+
|
|
|
+ // 通过事件系统检查是否有活跃敌人
|
|
|
+ eventBus.emit(GameEvents.BALL_FIRE_BULLET, {
|
|
|
+ canFire: (canFire: boolean) => {
|
|
|
+ hasActiveEnemies = canFire;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('[BallAni] 开始播放方块撞击动画', blockNode.name, '有敌人:', hasActiveEnemies);
|
|
|
+
|
|
|
+ const sprite = blockNode.getComponent(Sprite);
|
|
|
+ const originalScale = blockNode.scale.clone();
|
|
|
+ const originalColor = sprite ? sprite.color.clone() : Color.WHITE.clone();
|
|
|
+
|
|
|
+ console.log('[BallAni] 原始缩放:', originalScale, '原始颜色:', originalColor);
|
|
|
+
|
|
|
+ if (hasActiveEnemies) {
|
|
|
+ // 有敌人时播放完整动画:收缩到0.5倍 -> 变白发亮 -> 恢复正常
|
|
|
+ const shrinkScale = originalScale.clone().multiplyScalar(0.5);
|
|
|
+ const animationTween = tween(blockNode)
|
|
|
+ .to(0.2, { scale: shrinkScale })
|
|
|
+ .call(() => {
|
|
|
+ console.log('[BallAni] 方块收缩完成,开始变白');
|
|
|
+ // 变白发光效果
|
|
|
+ if (sprite) {
|
|
|
+ sprite.color = Color.WHITE;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .to(0.2, { scale: originalScale })
|
|
|
+ .call(() => {
|
|
|
+ console.log('[BallAni] 方块动画完成,恢复原状');
|
|
|
+ // 恢复原始颜色
|
|
|
+ if (sprite) {
|
|
|
+ sprite.color = originalColor;
|
|
|
+ }
|
|
|
+ // 动画完成,从活动列表中移除
|
|
|
+ this.activeBlockAnimations.delete(blockNode);
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+
|
|
|
+ // 添加到活动动画列表
|
|
|
+ this.activeBlockAnimations.set(blockNode, animationTween);
|
|
|
+ } else {
|
|
|
+ // 没有敌人时只播放白光效果,不缩放
|
|
|
+ const animationTween = tween({})
|
|
|
+ .call(() => {
|
|
|
+ console.log('[BallAni] 无敌人,仅播放白光效果');
|
|
|
+ // 变白发光效果
|
|
|
+ if (sprite) {
|
|
|
+ sprite.color = Color.WHITE;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .delay(0.2) // 保持白光一段时间
|
|
|
+ .call(() => {
|
|
|
+ console.log('[BallAni] 白光效果完成,恢复原状');
|
|
|
+ // 恢复原始颜色
|
|
|
+ if (sprite) {
|
|
|
+ sprite.color = originalColor;
|
|
|
+ }
|
|
|
+ // 动画完成,从活动列表中移除
|
|
|
+ this.activeBlockAnimations.delete(blockNode);
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+
|
|
|
+ // 添加到活动动画列表
|
|
|
+ this.activeBlockAnimations.set(blockNode, animationTween);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 预加载撞击特效资源
|
|
|
*/
|
|
|
@@ -106,6 +198,24 @@ export class BallAni extends Component {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 停止指定方块的动画
|
|
|
+ * @param blockNode 方块节点
|
|
|
+ */
|
|
|
+ public stopBlockAnimation(blockNode: Node) {
|
|
|
+ const animation = this.activeBlockAnimations.get(blockNode);
|
|
|
+ if (animation) {
|
|
|
+ animation.stop();
|
|
|
+ this.activeBlockAnimations.delete(blockNode);
|
|
|
+
|
|
|
+ // 恢复原始状态
|
|
|
+ const sprite = blockNode.getComponent(Sprite);
|
|
|
+ if (sprite) {
|
|
|
+ sprite.color = Color.WHITE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 清理所有活动的特效
|
|
|
*/
|
|
|
@@ -118,23 +228,45 @@ export class BallAni extends Component {
|
|
|
this.activeEffects = [];
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 清除所有方块动画
|
|
|
+ */
|
|
|
+ public clearAllBlockAnimations() {
|
|
|
+ // 停止所有方块动画
|
|
|
+ for (const [blockNode, animation] of this.activeBlockAnimations) {
|
|
|
+ if (animation) {
|
|
|
+ animation.stop();
|
|
|
+ }
|
|
|
+ // 恢复方块状态
|
|
|
+ const sprite = blockNode.getComponent(Sprite);
|
|
|
+ if (sprite) {
|
|
|
+ sprite.color = Color.WHITE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.activeBlockAnimations.clear();
|
|
|
+ }
|
|
|
+
|
|
|
onDestroy() {
|
|
|
- // 组件销毁时清理所有特效
|
|
|
+ // 组件销毁时清理所有特效和动画
|
|
|
this.clearAllEffects();
|
|
|
+ this.clearAllBlockAnimations();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取单例实例(如果需要全局访问)
|
|
|
+ * 获取BallAni实例
|
|
|
+ * @returns BallAni实例
|
|
|
*/
|
|
|
public static getInstance(): BallAni | null {
|
|
|
const gameArea = find('Canvas/GameLevelUI/GameArea');
|
|
|
if (!gameArea) {
|
|
|
+ console.warn('[BallAni] 未找到GameArea节点');
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- let ballAni = gameArea.getComponent(BallAni);
|
|
|
+ const ballAni = gameArea.getComponent(BallAni);
|
|
|
if (!ballAni) {
|
|
|
- ballAni = gameArea.addComponent(BallAni);
|
|
|
+ console.warn('[BallAni] GameArea节点上未找到BallAni组件');
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
return ballAni;
|