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(); private _originalDibanPos: 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); // Save diban original position if available if (this.dibanNode) { this._originalDibanPos.set(this.dibanNode.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) { console.log('GameStartMove.slideDibanDownAndHide 开始执行'); if (!this.dibanNode || !this.blockSelectionUI) { console.log('GameStartMove.slideDibanDownAndHide 条件检查失败:', { dibanNode: !!this.dibanNode, blockSelectionUI: !!this.blockSelectionUI }); return; } // 使用存储的原始位置,如果没有存储则使用当前位置 let originalPos: Vec3; if (this._originalDibanPos.equals(Vec3.ZERO)) { // 如果没有存储原始位置,使用当前位置并存储它 originalPos = this.dibanNode.position.clone(); this._originalDibanPos = originalPos.clone(); console.log('GameStartMove.slideDibanDownAndHide 首次使用,存储原始位置:', this._originalDibanPos); } else { // 使用存储的原始位置 originalPos = this._originalDibanPos.clone(); console.log('GameStartMove.slideDibanDownAndHide 使用存储的原始位置:', originalPos); } // 获取当前位置作为动画起始位置 const currentPos = this.dibanNode.position.clone(); console.log('GameStartMove.slideDibanDownAndHide 当前位置:', currentPos); // 停止现有 tween Tween.stopAllByTarget(this.dibanNode); const targetPos = new Vec3(currentPos.x, currentPos.y - distance, currentPos.z); console.log('GameStartMove.slideDibanDownAndHide 目标位置:', targetPos); tween(this.dibanNode) .to(duration, { position: targetPos }, { easing: 'quadIn' }) .call(() => { console.log('GameStartMove.slideDibanDownAndHide 动画完成回调'); // 先隐藏BlockSelectionUI,然后立即重置diban位置到存储的原始位置 // 这样用户就看不到位置重置的过程 this.blockSelectionUI.active = false; this.dibanNode.setPosition(originalPos); console.log('GameStartMove.slideDibanDownAndHide UI已隐藏,位置已重置到:', originalPos); }) .start(); console.log('GameStartMove.slideDibanDownAndHide 动画已启动'); } /** * 从底部上滑显示 diban * @param distance 从下方移动的距离,默认 300 * @param duration 动画时长,默认 0.3s */ public slideUpFromBottom(distance: number = 300, duration: number = 0.3) { console.log('GameStartMove.slideUpFromBottom 开始执行'); if (!this.dibanNode || !this.blockSelectionUI) { console.log('GameStartMove.slideUpFromBottom 条件检查失败:', { dibanNode: !!this.dibanNode, blockSelectionUI: !!this.blockSelectionUI }); return; } // 确保BlockSelectionUI可见 this.blockSelectionUI.active = true; // 使用存储的原始位置作为目标位置 let targetPos: Vec3; if (this._originalDibanPos.equals(Vec3.ZERO)) { // 如果没有存储原始位置,使用当前位置并存储它 targetPos = this.dibanNode.position.clone(); this._originalDibanPos = targetPos.clone(); console.log('GameStartMove.slideUpFromBottom 首次使用,存储原始位置:', this._originalDibanPos); } else { // 使用存储的原始位置 targetPos = this._originalDibanPos.clone(); console.log('GameStartMove.slideUpFromBottom 使用存储的原始位置:', targetPos); } // 设置初始位置(在目标位置下方) const startPos = new Vec3(targetPos.x, targetPos.y - distance, targetPos.z); this.dibanNode.setPosition(startPos); console.log('GameStartMove.slideUpFromBottom 起始位置:', startPos); // 停止现有 tween Tween.stopAllByTarget(this.dibanNode); // 播放上滑动画到目标位置 tween(this.dibanNode) .to(duration, { position: targetPos }, { easing: 'quadOut' }) .call(() => { console.log('GameStartMove.slideUpFromBottom 动画完成'); }) .start(); console.log('GameStartMove.slideUpFromBottom 动画已启动'); } /** * 更新保存的diban原始位置(当diban节点在运行时改变时调用) */ public updateDibanOriginalPosition() { if (this.dibanNode) { this._originalDibanPos.set(this.dibanNode.position); console.log('GameStartMove.updateDibanOriginalPosition 存储原始位置:', this._originalDibanPos); } else { console.log('GameStartMove.updateDibanOriginalPosition dibanNode为空,无法存储位置'); } } }