同步主站 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

@@ -148,6 +148,9 @@ export class PlayerActionAnimator extends Component {
private frameTimer = 0;
private loadingGen = 0;
private useSequence = false;
/** 本轮序列是否已走到末帧并回绕(或播完非循环动作) */
private cycleDone = true;
private cycleWaiters: Array<() => void> = [];
/** 主题级统一缩放(按最高序列帧锁定,避免待机/走路切换时重新算 scale */
private lockedUniformScale: number | null = null;
/** 脚点对齐参考帧(与 lockedUniformScale 同源,取最高帧) */
@@ -210,6 +213,8 @@ export class PlayerActionAnimator extends Component {
this.action = action;
this.frameIdx = 0;
this.frameTimer = 0;
this.cycleDone = false;
if (actionChanged) this.flushCycleWaiters();
if (!this.useSequence) {
VisualAssets.applyPlayerSprite(
this.spriteNode, this.direction, { theme: this.theme }, this.scaleMul,
@@ -226,8 +231,63 @@ export class PlayerActionAnimator extends Component {
return this.action;
}
/** 当前动作一轮序列的未缩放时长;帧未就绪时按 4 帧估算 */
getCycleDuration(): number {
const interval = FRAME_INTERVAL[this.action];
if (interval <= 0) return 0;
const n = this.useSequence && this.frames.length > 0 ? this.frames.length : 4;
return n * interval;
}
/** 从当前帧播到本轮结束的未缩放剩余时间 */
getRemainingCycleDuration(): number {
if (!this.useSequence || this.frames.length <= 1) return 0;
if (this.cycleDone) return 0;
const interval = FRAME_INTERVAL[this.action];
if (interval <= 0) return 0;
const currentLeft = Math.max(0, interval - this.frameTimer);
const framesAfter = Math.max(0, this.frames.length - this.frameIdx - 1);
return currentLeft + framesAfter * interval;
}
hasCompletedCycle(): boolean {
if (!this.useSequence || this.frames.length <= 1) return true;
return this.cycleDone;
}
/** 新的一格开始:不重播第 0 帧,只重新计一轮,避免循环移动掐断 */
beginCycle() {
this.cycleDone = this.frames.length <= 1;
if (this.cycleDone) this.flushCycleWaiters();
}
waitUntilCycleComplete(): Promise<void> {
if (this.hasCompletedCycle()) return Promise.resolve();
return new Promise((resolve) => {
this.cycleWaiters.push(resolve);
});
}
flushCycleWaiters() {
if (this.cycleWaiters.length === 0) return;
const pending = this.cycleWaiters;
this.cycleWaiters = [];
for (const fn of pending) fn();
}
onDestroy() {
this.cycleDone = true;
this.flushCycleWaiters();
}
update(dt: number) {
if (!this.useSequence || this.frames.length <= 1) return;
if (!this.useSequence || this.frames.length <= 1) {
if (!this.cycleDone) {
this.cycleDone = true;
this.flushCycleWaiters();
}
return;
}
const interval = FRAME_INTERVAL[this.action];
if (interval <= 0) return;
@@ -242,8 +302,16 @@ export class PlayerActionAnimator extends Component {
|| this.action === PlayerAction.Idle;
if (loop) {
this.frameIdx = (this.frameIdx + 1) % this.frames.length;
if (this.frameIdx === 0) {
this.cycleDone = true;
this.flushCycleWaiters();
}
} else if (this.frameIdx < this.frames.length - 1) {
this.frameIdx++;
if (this.frameIdx >= this.frames.length - 1) {
this.cycleDone = true;
this.flushCycleWaiters();
}
}
this.showFrame(this.frames[this.frameIdx]!);
}
@@ -314,7 +382,9 @@ export class PlayerActionAnimator extends Component {
this.frames = frames;
this.frameIdx = 0;
this.frameTimer = 0;
this.cycleDone = frames.length <= 1;
this.showFrame(frames[0]!);
if (this.cycleDone) this.flushCycleWaiters();
if (sortOnLoad && (action === PlayerAction.Win || action === PlayerAction.Fail)) {
this.refreshResultDrawOrder();
}

View File

@@ -40,13 +40,11 @@ export function resolvePlayerAnimPaths(theme: string | undefined): PlayerAnimPat
idle: `${base}/skin/待机正面`,
move: `${base}/skin/走`,
jump: `${base}/skin/跳`,
fail: key === 'silu' ? `${base}/player/失败正` : undefined,
},
back: {
idle: `${base}/skin/待机背面`,
move: `${base}/skin/走背面`,
jump: `${base}/skin/跳背面`,
fail: key === 'silu' ? `${base}/player/失败反` : undefined,
},
};
default: