同步主站 Cocos 当前工程:关卡资源、运行脚本与打包工具。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-12 14:40:34 +08:00
parent ae75fce80b
commit fac515a669
5609 changed files with 27744634 additions and 5653 deletions

View File

@@ -3,7 +3,7 @@ import {
Direction, GameState, GridType, MoveState, MoverRole, addDirection,
} from '../core/Define';
import { GameManager } from '../manager/GameManager';
import { markIsoDrawOrderDirty, resolveLevelDrawRoot } from '../level/TileLayout';
import { markIsoDrawOrderDirty, resolveLevelDrawRoot, sortIsoTiles } from '../level/TileLayout';
import { scaledMoveSpeed, UNITY_VEHICLE_MOVE_SPEED } from '../core/GridConstants';
import { cellToWorldCenter } from '../core/GridCoords';
import {
@@ -57,6 +57,11 @@ export class Movement extends Component {
protected landingCell: Vec3 | null = null;
private moveStepFrom = new Vec3();
private queue: Promise<void> = Promise.resolve();
private moveWaitWakeups: Array<() => void> = [];
/** resetToSpawn / 重开关时作废进行中的 moveCoroutine避免走两步被拽回出生点再走 */
private resetEpoch = 0;
/** 本步实际位移速度(可按动画一轮时长拉长,避免下一格掐断) */
private stepMoveSpeed = 0;
static callEach = false;
protected getMoverLocalPosition(): Vec3 {
@@ -97,6 +102,7 @@ export class Movement extends Component {
public shareCommittedCell(cell: Vec3) {
if (!this.committedCell) this.committedCell = new Vec3();
this.committedCell.set(cell);
this.markDrawOrderDirty();
}
getCommittedCell(): Vec3 | null {
@@ -166,7 +172,10 @@ export class Movement extends Component {
start() {
this.setDirection(this.direction);
this.syncCommittedCellFromPosition();
if (!this.committedCell) {
this.syncCommittedCellFromPosition();
this.markDrawOrderDirty();
}
}
protected commitLandingCell() {
@@ -199,15 +208,41 @@ export class Movement extends Component {
/** 主题 entityDisplay 变更后重算站立 Y缩放刷新不会自动更新节点坐标 */
reapplyCellStandPosition() {
if (this.moveState === MoveState.Moving) return;
this.snapMoverToCellStand();
this.markDrawOrderDirty();
}
resetMoveRuntime() {
this.resetEpoch++;
this.moveState = MoveState.Idle;
this.moveWait = false;
this.step = 0;
this.stepMoveSpeed = 0;
this.queue = Promise.resolve();
this.wakeMoveWaiters();
}
resetToSpawn() {
const moved = !!(this.spawnCell && this.committedCell
&& (this.committedCell.x !== this.spawnCell.x || this.committedCell.y !== this.spawnCell.y));
const walking = this.moveState !== MoveState.Idle || this.step > 0;
if (moved || walking) {
console.warn(
'[tfrh-reset] 把角色拉回出生点',
this.node.name,
{ from: this.committedCell, spawn: this.spawnCell, walking, step: this.step },
new Error().stack,
);
}
this.resetMoveRuntime();
this.landingCell = null;
if (this.spawnCell) {
if (!this.committedCell) this.committedCell = new Vec3();
this.committedCell.set(this.spawnCell);
}
this.snapMoverToCellStand();
this.markDrawOrderDirty();
}
update(dt: number) {
@@ -215,24 +250,33 @@ export class Movement extends Component {
const pos = this.node.position;
const next = new Vec3();
const speedMul = GameManager.instance?.getGameSpeed() ?? Movement.speedMultiplier;
Vec3.moveTowards(next, pos, this.targetPosition, this.moveSpeed * dt * speedMul);
const speed = this.stepMoveSpeed > 0 ? this.stepMoveSpeed : this.moveSpeed;
Vec3.moveTowards(next, pos, this.targetPosition, speed * dt * speedMul);
this.node.setPosition(next);
this.onMoving();
this.syncRideAfterMoveStep();
this.markDrawOrderDirty();
if (Vec3.distance(next, this.targetPosition) < 0.005) {
this.node.setPosition(this.targetPosition);
this.moveState = MoveState.Idle;
this.moveWait = false;
this.onMoveToTarget();
this.markDrawOrderDirty();
this.applyDrawOrderAfterMove();
this.wakeMoveWaiters();
}
}
private markDrawOrderDirty() {
protected markDrawOrderDirty() {
const root = resolveLevelDrawRoot(this.node);
if (root) markIsoDrawOrderDirty(root);
}
/** 落地后按新格写 sibling */
protected applyDrawOrderAfterMove() {
const root = resolveLevelDrawRoot(this.node);
if (root) sortIsoTiles(root, true);
}
protected syncRideAfterMoveStep() {}
setDirection(dir: Direction) {
@@ -246,8 +290,28 @@ export class Movement extends Component {
/** 转向结束Unity RotateCoroutine 只改朝向,不重新 snap 落点) */
protected onRotateComplete() {}
protected onMoveNextSet(_isJump: boolean) {}
/** 本 CallMove 最后一格已起步landingCell 已确定),可提前 processData */
protected onLastMoveStepReady() {}
protected onMoveFail(_isJump: boolean) {}
protected playMoveAnim() {}
/** 本步位移至少持续该未缩放秒数(用于对齐走路/跳跃一轮) */
protected getMoveStepMinDuration(): number {
return 0;
}
/** 落地后若动画一轮未完,等播完再走下一格 */
protected waitMoveVisualReady(): Promise<void> {
return Promise.resolve();
}
private resolveStepMoveSpeed() {
const minDur = this.getMoveStepMinDuration();
const dist = Vec3.distance(this.moveStepFrom, this.targetPosition);
if (minDur <= 0 || dist < 1e-4) {
this.stepMoveSpeed = this.moveSpeed;
return;
}
this.stepMoveSpeed = Math.min(this.moveSpeed, dist / minDur);
}
/** 本步移动起点(子类可去掉骑乘视觉抬高等) */
protected resolveMoveStepOrigin(_targetCell: Vec3, _landingGrid: GridType): Vec3 {
@@ -303,22 +367,46 @@ export class Movement extends Component {
this.queue = this.queue.then(fn).catch((e) => console.error(e));
}
protected waitUntilIdle(): Promise<void> {
return this.waitUntil(() => this.moveState !== MoveState.Moving && !this.moveWait);
}
private waitUntil(cond: () => boolean): Promise<void> {
if (cond()) return Promise.resolve();
return new Promise((resolve) => {
let settled = false;
const finish = () => {
if (settled || !cond()) return;
settled = true;
resolve();
};
this.moveWaitWakeups.push(finish);
const tick = () => {
if (cond()) resolve();
if (settled) return;
if (cond()) finish();
else requestAnimationFrame(tick);
};
tick();
});
}
/** 落地当帧唤醒队列,避免再等一帧 rAF */
protected wakeMoveWaiters() {
if (this.moveWaitWakeups.length === 0) return;
const pending = this.moveWaitWakeups;
this.moveWaitWakeups = [];
for (const fn of pending) fn();
}
private async moveCoroutine(n: number, isJump: boolean) {
await this.waitUntil(() => !this.moveWait);
const epoch = this.resetEpoch;
await this.waitUntil(() => !this.moveWait || epoch !== this.resetEpoch);
if (epoch !== this.resetEpoch) return;
const toFront = n > 0;
this.step = Math.abs(n);
const gm = GameManager.instance!;
while (this.step > 0 && gm.gameState === GameState.Run) {
if (epoch !== this.resetEpoch) return;
this.step--;
const r = this.moveNextCheck(isJump, toFront);
if (r === -1) {
@@ -330,9 +418,12 @@ export class Movement extends Component {
this.lastPosition.set(this.getGridSamplePosition());
this.moveState = MoveState.Moving;
this.onMoveNextSet(isJump);
// 起步 dirty角色朝前会切落点载具仍按起点人车可能同帧都要重排
this.markDrawOrderDirty();
await this.waitUntil(() => !this.moveWait);
this.resolveStepMoveSpeed();
if (this.step === 0) this.onLastMoveStepReady();
await this.waitUntil(() => !this.moveWait || epoch !== this.resetEpoch);
if (epoch !== this.resetEpoch) return;
await this.waitMoveVisualReady();
if (epoch !== this.resetEpoch) return;
} else {
this.playMoveAnim();
this.moveState = MoveState.Moving;
@@ -340,13 +431,16 @@ export class Movement extends Component {
if (this.step === 0) {
this.moveState = MoveState.Idle;
this.onMoveToTarget();
this.applyDrawOrderAfterMove();
}
}
}
}
private async rotateCoroutine(n: number) {
await this.waitUntil(() => !this.moveWait);
const epoch = this.resetEpoch;
await this.waitUntil(() => !this.moveWait || epoch !== this.resetEpoch);
if (epoch !== this.resetEpoch) return;
this.moveWait = true;
this.setDirection(addDirection(this.direction, n));
this.moveWait = false;