Complete Cocos Creator port with level bundles, themes, and tooling.

Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-16 15:30:58 +08:00
parent cba5105908
commit d393302388
6248 changed files with 17322729 additions and 11036 deletions

View File

@@ -0,0 +1,136 @@
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 ViewControllerOrthographic 缩放与拖拽 */
@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;
}
}