import { _decorator, Camera, Component, EventMouse, EventTouch, Input, input, Vec2, view, } from 'cc'; import { CAMERA_ORTHO_HALF, DESIGN_WIDTH } from '../core/GridConstants'; import { getEmbeddedOrthoHalf } from '../core/EmbeddedView'; const { ccclass } = _decorator; /** 对齐 Unity ViewController:Orthographic 缩放与拖拽 */ @ccclass('ViewController') export class ViewController extends Component { static instance: ViewController | null = null; /** Unity zoomSpeed=2 → 世界半高步进 200 */ zoomSpeed = 200; /** Unity minZoom=3, maxZoom=10(×100 世界单位) */ minOrtho = 300; maxOrtho = 1000; private camera: Camera | null = null; private dragOrigin = new Vec2(); private dragging = false; onLoad() { if (ViewController.instance && ViewController.instance !== this) { this.destroy(); return; } ViewController.instance = this; this.camera = this.getComponent(Camera); if (this.camera && this.camera.orthoHeight <= 0) { this.camera.orthoHeight = CAMERA_ORTHO_HALF; } input.on(Input.EventType.TOUCH_START, this.onTouchStart, this); input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this); input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this); input.on(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this); input.on(Input.EventType.MOUSE_DOWN, this.onMouseDown, this); input.on(Input.EventType.MOUSE_MOVE, this.onMouseMove, this); input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this); } onDestroy() { if (ViewController.instance === this) ViewController.instance = null; input.off(Input.EventType.TOUCH_START, this.onTouchStart, this); input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this); input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this); input.off(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this); input.off(Input.EventType.MOUSE_DOWN, this.onMouseDown, this); input.off(Input.EventType.MOUSE_MOVE, this.onMouseMove, this); input.off(Input.EventType.MOUSE_UP, this.onMouseUp, this); } zoomIn() { const cam = this.camera; if (!cam || cam.orthoHeight <= this.minOrtho) return; cam.orthoHeight = Math.max(this.minOrtho, cam.orthoHeight - this.zoomSpeed); } zoomOut() { const cam = this.camera; if (!cam || cam.orthoHeight >= this.maxOrtho) return; cam.orthoHeight = Math.min(this.maxOrtho, cam.orthoHeight + this.zoomSpeed); } resetZoom() { const cam = this.camera; if (!cam) return; cam.orthoHeight = getEmbeddedOrthoHalf(); cam.node.setPosition(0, 0, cam.node.position.z); } private onTouchStart(e: EventTouch) { if (this.isPointerOnUI(e.getLocation())) return; this.dragging = true; e.getLocation(this.dragOrigin); } private onTouchEnd() { this.dragging = false; } private onTouchMove(e: EventTouch) { if (!this.dragging) return; const cur = new Vec2(); e.getLocation(cur); this.applyDrag(cur); e.getLocation(this.dragOrigin); } private onMouseDown(e: EventMouse) { if (this.isPointerOnUI(new Vec2(e.getLocationX(), e.getLocationY()))) return; this.dragging = true; this.dragOrigin.set(e.getLocationX(), e.getLocationY()); } private onMouseUp() { this.dragging = false; } private onMouseMove(e: EventMouse) { if (!this.dragging) return; this.applyDrag(new Vec2(e.getLocationX(), e.getLocationY())); this.dragOrigin.set(e.getLocationX(), e.getLocationY()); } private applyDrag(cur: Vec2) { if (!this.camera) return; const delta = cur.subtract(this.dragOrigin); const ortho = this.camera.orthoHeight; const { width, height } = view.getVisibleSize(); const worldPerPixelX = (2 * ortho * (width / height)) / width; const worldPerPixelY = (2 * ortho) / height; const pos = this.camera.node.position; let nx = pos.x - delta.x * worldPerPixelX; let ny = pos.y - delta.y * worldPerPixelY; const limit = ortho - 20; if (Math.abs(nx) > limit) nx = pos.x; if (Math.abs(ny) > limit) ny = pos.y; this.camera.node.setPosition(nx, ny, pos.z); } /** 右侧 UIMain 区域不拖拽镜头(与 UIMain 边距一致) */ private isPointerOnUI(loc: Vec2): boolean { const vis = view.getVisibleSize(); const margin = Math.max(96, (DESIGN_WIDTH * 0.5) * 0.14); const right = vis.width > DESIGN_WIDTH ? DESIGN_WIDTH * 0.5 : vis.width * 0.5; return loc.x >= right - margin; } }