Browse Source

手指动画实现

181404010226 1 month ago
parent
commit
95c926c59d

+ 63 - 50
assets/NewbieGuidePlugin-v1.0.0/NewbieGuidePlugin-v1.0.0/scripts/GuideSteps.ts

@@ -4,6 +4,7 @@
  */
 
 import { GuideStep } from "./GuideStep";
+import { _decorator, Component, Node, Button, Label, find, Vec2, Vec3, UITransform, EventTouch, Sprite, Color, tween, Tween } from 'cc';
 
 /**
  * 点击引导步骤
@@ -11,7 +12,7 @@ import { GuideStep } from "./GuideStep";
  */
 export class ClickGuideStep extends GuideStep {
     private _targetNodePath: string;
-    private _targetNode: cc.Node;
+    private _targetNode: Node;
     private _clickHandler: () => void;
     
     constructor(stepId: string, targetNodePath: string) {
@@ -34,13 +35,15 @@ export class ClickGuideStep extends GuideStep {
             return;
         }
         
-        // 显示手指指向动画
+        // 显示手指指向动画 - 使用步骤索引让GuideUIController使用配置的节点
         const uiController = this._manager.getUIController();
-        const worldPos = this._targetNode.convertToWorldSpaceAR(cc.Vec2.ZERO);
-        uiController.createPointingAnimation("guild_1", worldPos);
+        // 传入步骤索引,让GuideUIController使用配置的fingerStartNodes和fingerTargetNodes
+        // 从stepId中提取数字索引,如果没有数字则使用0
+        const stepIndex = parseInt(this._stepId.replace(/\D/g, '')) || 0;
+        uiController.createPointingAnimation("guild_1", undefined, stepIndex);
         
         // 添加点击监听
-        this._targetNode.on(cc.Node.EventType.TOUCH_END, this._clickHandler, this);
+        this._targetNode.on(Node.EventType.TOUCH_END, this._clickHandler, this);
         
         // 创建高亮效果
         uiController.createHighlightEffect(this._targetNode);
@@ -50,9 +53,8 @@ export class ClickGuideStep extends GuideStep {
         if (this._targetNode) {
             return;
         }
-        
-        // 根据路径查找节点
-        this._targetNode = cc.find(this._targetNodePath);
+        // 使用 find 函数查找节点
+        this._targetNode = find(this._targetNodePath);
     }
     
     private onTargetClick(): void {
@@ -63,7 +65,7 @@ export class ClickGuideStep extends GuideStep {
     protected onComplete(): void {
         // 移除点击监听
         if (this._targetNode) {
-            this._targetNode.off(cc.Node.EventType.TOUCH_END, this._clickHandler, this);
+            this._targetNode.off(Node.EventType.TOUCH_END, this._clickHandler, this);
         }
         
         // 隐藏引导UI
@@ -80,8 +82,8 @@ export class ClickGuideStep extends GuideStep {
 export class DragGuideStep extends GuideStep {
     private _sourceNodePath: string;
     private _targetNodePath: string;
-    private _sourceNode: cc.Node;
-    private _targetNode: cc.Node;
+    private _sourceNode: Node;
+    private _targetNode: Node;
     private _isDragging: boolean = false;
     
     constructor(stepId: string, sourceNodePath: string, targetNodePath: string) {
@@ -113,10 +115,10 @@ export class DragGuideStep extends GuideStep {
     
     private findNodes(): void {
         if (!this._sourceNode) {
-            this._sourceNode = cc.find(this._sourceNodePath);
+            this._sourceNode = find(this._sourceNodePath);
         }
         if (!this._targetNode) {
-            this._targetNode = cc.find(this._targetNodePath);
+            this._targetNode = find(this._targetNodePath);
         }
     }
     
@@ -124,64 +126,69 @@ export class DragGuideStep extends GuideStep {
         const uiController = this._manager.getUIController();
         
         // 在源节点位置显示手指
-        const sourceWorldPos = this._sourceNode.convertToWorldSpaceAR(cc.Vec2.ZERO);
+        const sourceUITransform = this._sourceNode.getComponent(UITransform);
+        const sourceWorldPos = sourceUITransform ? sourceUITransform.convertToWorldSpaceAR(Vec3.ZERO) : this._sourceNode.worldPosition;
         uiController.setGuideUIPosition("guild_1", sourceWorldPos);
         uiController.showGuideUI("guild_1", "tap");
         
         // 创建拖拽路径动画
-        const targetWorldPos = this._targetNode.convertToWorldSpaceAR(cc.Vec2.ZERO);
+        const targetUITransform = this._targetNode.getComponent(UITransform);
+        const targetWorldPos = targetUITransform ? targetUITransform.convertToWorldSpaceAR(Vec3.ZERO) : this._targetNode.worldPosition;
         const guideNode = uiController.getGuideNode("guild_1");
         if (guideNode) {
-            const moveAction = cc.repeatForever(
-                cc.sequence(
-                    cc.moveTo(1.0, targetWorldPos),
-                    cc.moveTo(0.1, sourceWorldPos)
-                )
-            );
-            guideNode.runAction(moveAction);
+            const moveAction = tween(guideNode)
+                .repeatForever(
+                    tween(guideNode)
+                        .to(1.0, { position: targetWorldPos })
+                        .to(0.1, { position: sourceWorldPos })
+                );
+            moveAction.start();
         }
     }
     
     private addDragListeners(): void {
-        this._sourceNode.on(cc.Node.EventType.TOUCH_START, this.onDragStart, this);
-        this._sourceNode.on(cc.Node.EventType.TOUCH_MOVE, this.onDragMove, this);
-        this._sourceNode.on(cc.Node.EventType.TOUCH_END, this.onDragEnd, this);
+        this._sourceNode.on(Node.EventType.TOUCH_START, this.onDragStart, this);
+        this._sourceNode.on(Node.EventType.TOUCH_MOVE, this.onDragMove, this);
+        this._sourceNode.on(Node.EventType.TOUCH_END, this.onDragEnd, this);
     }
     
-    private onDragStart(event: cc.Event.EventTouch): void {
+    private onDragStart(event: EventTouch): void {
         this._isDragging = true;
     }
     
-    private onDragMove(event: cc.Event.EventTouch): void {
+    private onDragMove(event: EventTouch): void {
         if (!this._isDragging) return;
         
         // 检查是否拖拽到目标区域
         const touchPos = event.getLocation();
-        const targetBoundingBox = this._targetNode.getBoundingBoxToWorld();
-        
-        if (targetBoundingBox.contains(touchPos)) {
-            // 拖拽到目标区域,完成引导
-            this.complete();
+        const targetUITransform = this._targetNode.getComponent(UITransform);
+        if (targetUITransform) {
+            const targetBoundingBox = targetUITransform.getBoundingBoxToWorld();
+            
+            if (targetBoundingBox.contains(new Vec2(touchPos.x, touchPos.y))) {
+                // 拖拽到目标区域,完成引导
+                this.complete();
+            }
         }
     }
     
-    private onDragEnd(event: cc.Event.EventTouch): void {
+    private onDragEnd(event: EventTouch): void {
         this._isDragging = false;
     }
     
     protected onComplete(): void {
         // 移除拖拽监听
         if (this._sourceNode) {
-            this._sourceNode.off(cc.Node.EventType.TOUCH_START, this.onDragStart, this);
-            this._sourceNode.off(cc.Node.EventType.TOUCH_MOVE, this.onDragMove, this);
-            this._sourceNode.off(cc.Node.EventType.TOUCH_END, this.onDragEnd, this);
+            this._sourceNode.off(Node.EventType.TOUCH_START, this.onDragStart, this);
+            this._sourceNode.off(Node.EventType.TOUCH_MOVE, this.onDragMove, this);
+            this._sourceNode.off(Node.EventType.TOUCH_END, this.onDragEnd, this);
         }
         
         // 隐藏引导UI
         const uiController = this._manager.getUIController();
         const guideNode = uiController.getGuideNode("guild_1");
         if (guideNode) {
-            guideNode.stopAllActions();
+            Tween.stopAllByTarget(guideNode);
         }
         uiController.hideGuideUI("guild_1");
     }
@@ -245,7 +252,7 @@ export class WaitConditionGuideStep extends GuideStep {
  */
 export class DialogGuideStep extends GuideStep {
     private _dialogText: string;
-    private _dialogNode: cc.Node;
+    private _dialogNode: Node;
     
     constructor(stepId: string, dialogText: string) {
         super(stepId);
@@ -262,31 +269,37 @@ export class DialogGuideStep extends GuideStep {
     
     private showDialog(): void {
         // 创建对话框节点
-        this._dialogNode = new cc.Node("guide_dialog");
-        const canvas = cc.find("Canvas");
+        this._dialogNode = new Node("guide_dialog");
+        const canvas = find("Canvas");
         if (canvas) {
             canvas.addChild(this._dialogNode);
-            this._dialogNode.zIndex = 1001;
+            this._dialogNode.setSiblingIndex(1001);
         }
         
         // 添加背景
-        const bg = new cc.Node("bg");
-        bg.addComponent(cc.Sprite);
-        bg.color = cc.Color.BLACK;
-        bg.opacity = 128;
+        const bg = new Node("bg");
+        const bgSprite = bg.addComponent(Sprite);
+        bg.addComponent(UITransform);
+        bgSprite.color = Color.BLACK;
+        const bgUITransform = bg.getComponent(UITransform);
+        if (bgUITransform) {
+            bgUITransform.setContentSize(800, 600);
+        }
         this._dialogNode.addChild(bg);
         
         // 添加文本
-        const textNode = new cc.Node("text");
-        const label = textNode.addComponent(cc.Label);
+        const textNode = new Node("text");
+        const label = textNode.addComponent(Label);
         label.string = this._dialogText;
         label.fontSize = 24;
+        textNode.addComponent(UITransform);
         this._dialogNode.addChild(textNode);
         
         // 添加确定按钮
-        const btnNode = new cc.Node("btn_ok");
-        const button = btnNode.addComponent(cc.Button);
-        btnNode.on(cc.Node.EventType.TOUCH_END, () => {
+        const btnNode = new Node("btn_ok");
+        const button = btnNode.addComponent(Button);
+        btnNode.addComponent(UITransform);
+        btnNode.on(Node.EventType.TOUCH_END, () => {
             this.complete();
         });
         this._dialogNode.addChild(btnNode);

+ 94 - 20
assets/NewbieGuidePlugin-v1.0.0/NewbieGuidePlugin-v1.0.0/scripts/GuideUIController.ts

@@ -323,17 +323,43 @@ export class GuideUIController extends Component {
 
     /**
      * 创建手指指向动画(3.x 使用 tween)
+     * 优先使用配置的 fingerStartNodes 和 fingerTargetNodes 数组
      */
-    public createPointingAnimation(nodeId: string, targetPosition: Vec3): void {
+    public createPointingAnimation(nodeId: string, targetPosition?: Vec3, stepIndex?: number): void {
         const node = this._guideNodes.get(nodeId);
         if (!node) {
             console.warn(`引导节点未找到: ${nodeId}`);
             return;
         }
 
+        let finalPosition: Vec3;
+
+        // 优先使用配置的节点位置
+        if (stepIndex !== undefined && stepIndex >= 0 && stepIndex < this.fingerTargetNodes.length) {
+            const targetNode = this.fingerTargetNodes[stepIndex];
+            if (targetNode && targetNode.isValid) {
+                const worldPos = this.getNodeWorldPosition(targetNode);
+                // 将世界坐标转换为手指节点的本地坐标
+                finalPosition = this.convertWorldToLocalPosition(worldPos, node.parent || node);
+                console.log(`[GuideUIController] 使用配置的目标节点: ${targetNode.name}, 世界坐标: (${worldPos.x}, ${worldPos.y}), 本地坐标: (${finalPosition.x}, ${finalPosition.y})`);
+            } else if (targetPosition) {
+                finalPosition = targetPosition;
+                console.log(`[GuideUIController] 配置的目标节点无效,使用传入位置`);
+            } else {
+                console.warn(`[GuideUIController] 步骤 ${stepIndex} 目标节点无效且未提供位置参数`);
+                return;
+            }
+        } else if (targetPosition) {
+            finalPosition = targetPosition;
+            console.log(`[GuideUIController] 使用传入的目标位置`);
+        } else {
+            console.warn(`[GuideUIController] 未提供有效的步骤索引或位置参数`);
+            return;
+        }
+
         // 设置位置到目标位置附近
         const offset = new Vec3(50, 50, 0);
-        node.setPosition(new Vec3(targetPosition.x + offset.x, targetPosition.y + offset.y, targetPosition.z + offset.z));
+        node.setPosition(new Vec3(finalPosition.x + offset.x, finalPosition.y + offset.y, finalPosition.z + offset.z));
 
         // 显示节点并播放动画
         this.showGuideUI(nodeId, "tap");
@@ -358,13 +384,42 @@ export class GuideUIController extends Component {
         }
         
         const ui = node.getComponent(UITransform);
-        return ui ? ui.convertToWorldSpaceAR(new Vec3(0, 0, 0)) : node.worldPosition;
+        if (ui) {
+            // 使用UITransform获取世界坐标
+            return ui.convertToWorldSpaceAR(Vec3.ZERO);
+        } else {
+            // 兜底使用node的世界位置
+            return node.worldPosition.clone();
+        }
+    }
+
+    /**
+     * 将世界坐标转换为指定节点的本地坐标
+     */
+    private convertWorldToLocalPosition(worldPos: Vec3, targetNode: Node): Vec3 {
+        if (!targetNode || !targetNode.isValid) {
+            return worldPos.clone();
+        }
+        
+        const ui = targetNode.getComponent(UITransform);
+        if (ui) {
+            return ui.convertToNodeSpaceAR(worldPos);
+        } else {
+            // 兜底:通过父节点转换
+            if (targetNode.parent) {
+                const parentUI = targetNode.parent.getComponent(UITransform);
+                if (parentUI) {
+                    return parentUI.convertToNodeSpaceAR(worldPos);
+                }
+            }
+            return worldPos.clone();
+        }
     }
 
     /**
-     * 创建来回移动动画 - 用于新手引导第一步
+     * 创建来回移动动画 - 用于新手引导拖拽操作
      * 手指从起始位置到目标位置来回移动,指示拖拽操作
-     * 支持使用配置的节点位置或传入的位置参数
+     * 优先使用配置的 fingerStartNodes 和 fingerTargetNodes 数组
      */
     public createDragAnimation(nodeId: string, startPosition?: Vec3, targetPosition?: Vec3, stepIndex?: number): void {
         const node = this._guideNodes.get(nodeId);
@@ -373,34 +428,52 @@ export class GuideUIController extends Component {
             return;
         }
 
-        // 优先使用配置的节点位置
         let startPos: Vec3;
         let targetPos: Vec3;
 
+        // 优先使用配置的节点位置
         if (stepIndex !== undefined && stepIndex >= 0) {
-            // 使用配置的节点位置
-            const startNode = this.fingerStartNodes[stepIndex];
-            const targetNode = this.fingerTargetNodes[stepIndex];
-            
-            if (startNode && startNode.isValid) {
-                startPos = this.getNodeWorldPosition(startNode);
-                console.log(`[GuideUIController] 使用配置的起始节点: ${startNode.name}`);
+            // 检查起始节点配置
+            if (stepIndex < this.fingerStartNodes.length) {
+                const startNode = this.fingerStartNodes[stepIndex];
+                if (startNode && startNode.isValid) {
+                    const worldStartPos = this.getNodeWorldPosition(startNode);
+                    startPos = this.convertWorldToLocalPosition(worldStartPos, node.parent || node);
+                    console.log(`[GuideUIController] 使用配置的起始节点: ${startNode.name}, 世界坐标: (${worldStartPos.x}, ${worldStartPos.y}), 本地坐标: (${startPos.x}, ${startPos.y})`);
+                } else if (startPosition) {
+                    startPos = startPosition;
+                    console.log(`[GuideUIController] 配置的起始节点无效,使用传入的起始位置`);
+                } else {
+                    console.warn(`[GuideUIController] 步骤 ${stepIndex} 起始节点无效且未提供起始位置`);
+                    return;
+                }
             } else if (startPosition) {
                 startPos = startPosition;
-                console.log(`[GuideUIController] 使用传入的起始位置`);
+                console.log(`[GuideUIController] 步骤 ${stepIndex} 超出起始节点数组范围,使用传入的起始位置`);
             } else {
-                console.warn(`[GuideUIController] 步骤 ${stepIndex} 未配置起始节点且未提供起始位置`);
+                console.warn(`[GuideUIController] 步骤 ${stepIndex} 超出起始节点数组范围且未提供起始位置`);
                 return;
             }
 
-            if (targetNode && targetNode.isValid) {
-                targetPos = this.getNodeWorldPosition(targetNode);
-                console.log(`[GuideUIController] 使用配置的目标节点: ${targetNode.name}`);
+            // 检查目标节点配置
+            if (stepIndex < this.fingerTargetNodes.length) {
+                const targetNode = this.fingerTargetNodes[stepIndex];
+                if (targetNode && targetNode.isValid) {
+                    const worldTargetPos = this.getNodeWorldPosition(targetNode);
+                    targetPos = this.convertWorldToLocalPosition(worldTargetPos, node.parent || node);
+                    console.log(`[GuideUIController] 使用配置的目标节点: ${targetNode.name}, 世界坐标: (${worldTargetPos.x}, ${worldTargetPos.y}), 本地坐标: (${targetPos.x}, ${targetPos.y})`);
+                } else if (targetPosition) {
+                    targetPos = targetPosition;
+                    console.log(`[GuideUIController] 配置的目标节点无效,使用传入的目标位置`);
+                } else {
+                    console.warn(`[GuideUIController] 步骤 ${stepIndex} 目标节点无效且未提供目标位置`);
+                    return;
+                }
             } else if (targetPosition) {
                 targetPos = targetPosition;
-                console.log(`[GuideUIController] 使用传入的目标位置`);
+                console.log(`[GuideUIController] 步骤 ${stepIndex} 超出目标节点数组范围,使用传入的目标位置`);
             } else {
-                console.warn(`[GuideUIController] 步骤 ${stepIndex} 未配置目标节点且未提供目标位置`);
+                console.warn(`[GuideUIController] 步骤 ${stepIndex} 超出目标节点数组范围且未提供目标位置`);
                 return;
             }
         } else {
@@ -411,6 +484,7 @@ export class GuideUIController extends Component {
             }
             startPos = startPosition;
             targetPos = targetPosition;
+            console.log(`[GuideUIController] 使用传入的位置参数`);
         }
 
         // 显示节点并播放spine动画

+ 11 - 1
assets/Scenes/GameLevel.scene

@@ -45503,7 +45503,7 @@
     ],
     "value": {
       "__type__": "cc.Vec3",
-      "x": -209.296,
+      "x": -220.296,
       "y": -509.238,
       "z": 0
     }
@@ -46517,6 +46517,16 @@
         "__id__": 1339
       }
     ],
+    "fingerStartNodes": [
+      {
+        "__id__": 1019
+      }
+    ],
+    "fingerTargetNodes": [
+      {
+        "__id__": 1336
+      }
+    ],
     "maskDarkAlpha": 160,
     "maskLightAlpha": 32,
     "autoStepDelay": 1,

+ 8 - 14
assets/scripts/CombatSystem/BlockManager.ts

@@ -280,15 +280,12 @@ export class BlockManager extends Component {
         console.log('[BlockManager] 接收到方块生成事件');
         this.generateRandomBlocksInKuang();
 
-        // 引导:指向可拖拽的方块
+        // 引导:指向可拖拽的方块 - 使用步骤索引让GuideUIController使用配置的节点
         this.scheduleOnce(() => {
             if (this.guideUIController && this.block1Container) {
-                const ui = this.block1Container.getComponent(UITransform);
-                if (ui) {
-                    const worldPos = ui.convertToWorldSpaceAR(new Vec3(0, 0, 0));
-                    this.guideUIController.createPointingAnimation('guild_1', worldPos);
-                    this.guideUIController.createHighlightEffect(this.block1Container);
-                }
+                // 传入步骤索引0,让GuideUIController使用配置的fingerStartNodes和fingerTargetNodes
+                this.guideUIController.createPointingAnimation('guild_1', undefined, 0);
+                this.guideUIController.createHighlightEffect(this.block1Container);
             }
         }, 0);
     }
@@ -304,15 +301,12 @@ export class BlockManager extends Component {
         console.log('[BlockManager] 接收到波次完成事件,生成新方块');
         this.generateRandomBlocksInKuang();
 
-        // 引导:波次结束后新生成方块也展示指引
+        // 引导:波次结束后新生成方块也展示指引 - 使用步骤索引让GuideUIController使用配置的节点
         this.scheduleOnce(() => {
             if (this.guideUIController && this.block1Container) {
-                const ui = this.block1Container.getComponent(UITransform);
-                if (ui) {
-                    const worldPos = ui.convertToWorldSpaceAR(new Vec3(0, 0, 0));
-                    this.guideUIController.createPointingAnimation('guild_1', worldPos);
-                    this.guideUIController.createHighlightEffect(this.block1Container);
-                }
+                // 传入步骤索引0,让GuideUIController使用配置的fingerStartNodes和fingerTargetNodes
+                this.guideUIController.createPointingAnimation('guild_1', undefined, 0);
+                this.guideUIController.createHighlightEffect(this.block1Container);
             }
         }, 0);
     }