/** * @file move.ts * @description 地图背景横向循环滚动组件 * * 职责: * 1. 使挂载的节点在 [minX, maxX] 范围内沿水平方向持续移动。 * 2. 到达边界后停止并发出事件,等待下一轮触发(配合另一个同类组件实现无缝循环)。 * 3. 支持动态改变移动方向。 * * 关键设计: * - sc(direction):1 = 从左到右,-1 = 从右到左。 * - 采用事件驱动的接力机制: * * 当一个 move 组件到达终点后,发出 MAP_MOVE_END_LEFT 或 MAP_MOVE_END_RIGHT, * 同方向的另一个 move 组件收到后从起点开始移动,形成无缝衔接。 * - isMove 控制当前是否处于移动中。 * * 使用场景: * 通常挂载在地图背景层的两个重叠节点上,通过交替移动实现无限滚动效果。 * * 依赖: * - GameEvent.MAP_MOVE_END_LEFT —— 左方向移动结束事件 * - GameEvent.MAP_MOVE_END_RIGHT —— 右方向移动结束事件 */ import { _decorator, CCBoolean, CCInteger, Component, Node } from 'cc'; import { oops } from 'db://oops-framework/core/Oops'; import { GameEvent } from '../common/config/GameEvent'; const { ccclass, property } = _decorator; /** * move —— 背景循环滚动组件 * * 挂载在背景节点上,配合另一个同方向实例实现无缝横向滚动。 */ @ccclass('move') export class move extends Component { /** 移动速度(像素/秒) */ @property({ type: CCInteger }) speed: number = 2; /** 水平移动右边界 */ @property({ type: CCInteger }) maxX: number = 640; /** 水平移动左边界 */ @property({ type: CCInteger }) minX: number = -640; /** * 移动方向: * 1 = 从左到右 * -1 = 从右到左 */ @property({ type: CCInteger }) sc: number = 1; /** 当前是否正在移动 */ @property isMove:boolean=false /** 注册地图移动结束事件 */ protected onLoad(): void { oops.message.on(GameEvent.MAP_MOVE_END_LEFT, this.onMapMoveEndLeft, this); oops.message.on(GameEvent.MAP_MOVE_END_RIGHT, this.onMapMoveEndRight, this); } start() { } /** * 收到"左方向移动结束"事件: * 仅从右到左(sc==-1)的实例响应 → 重置到起点并开始移动。 */ onMapMoveEndLeft() { if(this.sc==-1){ this.isMove=true this.setInitialPosition() } } /** * 收到"右方向移动结束"事件: * 仅从左到右(sc==1)的实例响应 → 重置到起点并开始移动。 */ onMapMoveEndRight() { if(this.sc==1){ this.isMove=true this.setInitialPosition() } } /** 销毁时移除事件监听 */ onDestroy() { oops.message.off(GameEvent.MAP_MOVE_END_LEFT, this.onMapMoveEndLeft, this); oops.message.off(GameEvent.MAP_MOVE_END_RIGHT, this.onMapMoveEndRight, this); } /** * 根据移动方向设置初始位置: * - 从左到右:起点为 minX * - 从右到左:起点为 maxX */ setInitialPosition() { if (this.sc > 0) { this.node.setPosition(this.minX, this.node.position.y); } else if (this.sc < 0) { this.node.setPosition(this.maxX, this.node.position.y); } } /** * 帧更新:按速度和方向更新节点位置。 * 移动中才执行,到达边界后检查是否需要停止。 */ update(dt: number) { if(this.isMove){ const newX = this.node.position.x + dt * this.speed * this.sc; this.node.setPosition(newX, this.node.position.y); this.checkBoundaries(); } } /** * 检查边界并处理到达终点: * - 从左到右:到达 maxX → 停止移动,发出 MAP_MOVE_END_LEFT * - 从右到左:到达 minX → 停止移动,发出 MAP_MOVE_END_RIGHT * * 注意:事件名意味着"该方向的移动已结束", * 接收端的另一个实例会据此开始下一段移动。 */ checkBoundaries() { if (this.sc > 0) { if (this.node.position.x >= this.maxX) { this.node.setPosition(this.minX, this.node.position.y); this.isMove=false oops.message.dispatchEvent(GameEvent.MAP_MOVE_END_LEFT) } } else if (this.sc < 0) { if (this.node.position.x <= this.minX) { this.node.setPosition(this.maxX, this.node.position.y); this.isMove=false oops.message.dispatchEvent(GameEvent.MAP_MOVE_END_RIGHT) } } } /** * 动态改变移动方向并重置到对应起点。 * @param direction 1 = 从左到右,-1 = 从右到左 */ changeDirection(direction: number) { this.sc = direction; this.setInitialPosition(); } }