Browse Source

解决场景移动动画

181404010226 5 months ago
parent
commit
b23c97ff24

File diff suppressed because it is too large
+ 285 - 364
assets/Scenes/GameLevel.scene


+ 9 - 0
assets/scripts/Animations.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "1650c34e-d103-444c-a98e-8a8cb5f465f0",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 94 - 0
assets/scripts/Animations/GameStartMove.ts

@@ -0,0 +1,94 @@
+import { _decorator, Component, Node, Vec3, tween, Tween } from 'cc';
+const { ccclass, property } = _decorator;
+
+/**
+ * GameStartMove
+ *
+ * This component is expected to be attached to the main camera node.
+ * It provides two public helper methods that other scripts can call:
+ *  1. moveDownInstant() – instantly move the camera down by a fixed offset
+ *  2. moveUpSmooth()   – move the camera back up with a smooth tween animation
+ */
+@ccclass('GameStartMove')
+export class GameStartMove extends Component {
+    /** The camera node to move. Defaults to the node the script is attached to. */
+    @property({
+        type: Node,
+        tooltip: 'Camera node to move. Leave empty to use the current node.'
+    })
+    public cameraNode: Node = null;
+
+    /** Offset (in pixels/units) for one step of movement. */
+    @property({ tooltip: 'Vertical offset for the camera movement.' })
+    public offset: number = 182;
+
+    /** Tween duration for the smooth move-up animation. */
+    @property({ tooltip: 'Duration for the smooth move-up tween (seconds).' })
+    public moveDuration: number = 0.4;
+
+    private _originalPos: Vec3 = new Vec3();
+
+    onLoad () {
+        // Use self node if cameraNode not assigned via the editor.
+        if (!this.cameraNode) {
+            this.cameraNode = this.node;
+        }
+        // Save initial position so we can always restore relative to it.
+        this._originalPos.set(this.cameraNode.position);
+    }
+
+    /**
+     * Instantly move the camera down by `offset` units.
+     */
+    public moveDownInstant () {
+        if (!this.cameraNode) return;
+        const pos = this.cameraNode.position.clone();
+        pos.y -= this.offset;
+        this.cameraNode.setPosition(pos);
+    }
+
+    /**
+     * Smoothly move the camera back up by `offset` units using a tween.
+     */
+    public moveUpSmooth () {
+        if (!this.cameraNode) return;
+        const startPos = this.cameraNode.position.clone();
+        const targetPos = new Vec3(startPos.x, startPos.y + this.offset, startPos.z);
+        // Stop any running tweens on this node to avoid conflicting animations.
+        Tween.stopAllByTarget(this.cameraNode);
+        tween(this.cameraNode)
+            .to(this.moveDuration, { position: targetPos }, { easing: 'quadOut' })
+            .start();
+    }
+
+    /* ========= BlockSelectionUI 动画 ========= */
+    /** BlockSelectionUI 根节点(外部在编辑器拖拽赋值) */
+    @property({ type: Node, tooltip: 'BlockSelectionUI 根节点' })
+    public blockSelectionUI: Node = null;
+
+    /** BlockSelectionUI 中需要下滑的 diban 节点(外部拖拽赋值) */
+    @property({ type: Node, tooltip: 'BlockSelectionUI 中的 diban 节点' })
+    public dibanNode: Node = null;
+
+    /**
+     * 下滑 diban 并在动画结束后隐藏 BlockSelectionUI。
+     * @param distance 向下移动距离,默认 300
+     * @param duration 动画时长,默认 0.3s
+     */
+    public slideDibanDownAndHide(distance: number = 300, duration: number = 0.3) {
+        if (!this.dibanNode || !this.blockSelectionUI) return;
+
+        const originalPos = this.dibanNode.position.clone();
+
+        // 停止现有 tween
+        Tween.stopAllByTarget(this.dibanNode);
+
+        tween(this.dibanNode)
+            .to(duration, { position: new Vec3(originalPos.x, originalPos.y - distance, originalPos.z) }, { easing: 'quadIn' })
+            .call(() => {
+                this.blockSelectionUI.active = false;
+                this.dibanNode.setPosition(originalPos);
+            })
+            .start();
+    }
+}

+ 9 - 0
assets/scripts/Animations/GameStartMove.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "703f18d1-b06f-4794-bc7a-1482b6f1bf76",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 16 - 6
assets/scripts/CombatSystem/CoinDrop.ts

@@ -8,8 +8,12 @@ export class CoinDrop extends Component {
 
   onEnable() {
     // 找到 UI 里金币图标的世界坐标
-    const icon = find('Canvas/GameLevelUI/CoinNode/CoinDrop');
-    if (!icon) { this.node.destroy(); return; }
+    const icon = find('Canvas-001/TopArea/CoinNode/CoinDrop');
+    if (!icon) {
+      console.error('[CoinDrop] ❌ 找不到金币图标节点 Canvas-001/TopArea/CoinNode/CoinDrop');
+      this.node.destroy();
+      return;
+    }
     icon.getWorldPosition(this.targetWorldPos);
 
     // 初始弹跳向上 80px(0.3s)→ 落下 40px(0.2s)→ 飞向目标 (0.4s)
@@ -23,10 +27,16 @@ export class CoinDrop extends Component {
       .to(0.4, { worldPosition: this.targetWorldPos }, { easing: 'quadIn' })
       .call(() => {
          // 飞到图标后 +1 并销毁
-         const lblNode = find('Canvas/GameLevelUI/CoinNode/CoinLabel');
-         const lbl = lblNode?.getComponent(Label);
-         if (lbl) {
-           lbl.string = (parseInt(lbl.string) + 1).toString();
+         const lblNode = find('Canvas-001/TopArea/CoinNode/CoinLabel');
+         if (!lblNode) {
+           console.error('[CoinDrop] ❌ 找不到金币数字标签节点 Canvas-001/TopArea/CoinNode/CoinLabel');
+         } else {
+           const lbl = lblNode.getComponent(Label);
+           if (lbl) {
+             lbl.string = (parseInt(lbl.string) + 1).toString();
+           } else {
+             console.error('[CoinDrop] ❌ CoinLabel 节点缺少 Label 组件');
+           }
          }
          LevelSessionManager.inst.addCoins(1);   // 记账(局内金币)
          this.node.destroy();

+ 16 - 1
assets/scripts/LevelSystem/GameManager.ts

@@ -11,6 +11,7 @@ import { MainUIController } from './MainUIController';
 import { BallController } from '../CombatSystem/BallController';
 import { BlockManager } from '../CombatSystem/BlockManager';
 import { LevelSessionManager } from '../Core/LevelSessionManager';
+import { GameStartMove } from '../Animations/GameStartMove';
 const { ccclass, property } = _decorator;
 
 /**
@@ -763,7 +764,21 @@ export class GameManager extends Component {
 
     // === 原GameManager方法 ===
     public onConfirmButtonClicked() {
-        if (this.blockSelectionUI) this.blockSelectionUI.active = false;
+        if (this.blockSelectionUI) {
+            const cam = find('Main Camera') || find('Camera') || find('Canvas/Camera');
+            const gsm = cam?.getComponent(GameStartMove);
+            if (gsm) {
+                gsm.slideDibanDownAndHide();
+            } else {
+                // Fallback: 若未挂载 GameStartMove,直接关闭
+                this.blockSelectionUI.active = false;
+            }
+        }
+
+        // Camera move back up with smooth animation
+        const camNode = find('Main Camera') || find('Camera') || find('Canvas/Camera');
+        const gsm = camNode?.getComponent(GameStartMove);
+        gsm?.moveUpSmooth();
 
         if (this.preparingNextWave) {
             // 进入下一波

+ 14 - 0
assets/scripts/LevelSystem/MainUIController.ts

@@ -2,6 +2,7 @@
 import { _decorator, Component, Node, Button, Label, find } from 'cc';
 import { SaveDataManager } from './SaveDataManager';
 import { GameManager } from './GameManager';
+import { GameStartMove } from '../Animations/GameStartMove';
 const { ccclass, property } = _decorator;
 
 @ccclass('MainUIController')
@@ -28,6 +29,7 @@ export class MainUIController extends Component {
   @property(Node) navUpgradeBtn: Node = null;        // 底栏 UPGRADE
   @property(Node) navBattleBtn: Node = null;         // 底栏 BATTLE
   @property(Node) navSkillBtn: Node = null;          // 底栏 SKILL
+  @property(Node) topArea: Node = null;              // Canvas-001/TopArea
 
   private sdm: SaveDataManager = null;
 
@@ -37,6 +39,9 @@ export class MainUIController extends Component {
 
     this.bindButtons();
     this.refreshAll();
+
+    // TopArea 默认隐藏,在点击战斗后再显示
+    if (this.topArea) this.topArea.active = false;
   }
 
 
@@ -120,6 +125,15 @@ export class MainUIController extends Component {
     const gm = gmNode?.getComponent(GameManager);
     gm?.restartGame();
     gm?.loadCurrentLevelConfig();
+
+    // 显示 TopArea(拖拽引用),避免使用 find()
+    if (this.topArea) this.topArea.active = true;
+
+    // Camera move down instantly for battle prep
+    // 兼容 "Camera" 或 "Main Camera" 等命名
+    const camNode = find('Main Camera') || find('Camera') || find('Canvas/Camera');
+    const gsm = camNode?.getComponent(GameStartMove);
+    gsm?.moveDownInstant();
   }
 
   private onShop () {

Some files were not shown because too many files changed in this diff