同步主站 Cocos 当前工程:关卡资源、运行脚本与打包工具。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user