增加物理结算

This commit is contained in:
tianmo committed 2026-09-22 15:59:22 +08:00
1 parent 650d9c0398
commit c29de7a26b
4 files changed
+96 -39

No files matched your search

+21 -14
View File
@@ -320,6 +320,7 @@
let duration = 0; // 当前动画时长
let isStaticAnimation = false;
const FPS = 30;
const MAX_FRAME_DELTA = 0.064;
const STATIC_EPSILON = 1e-6;
let statusHoldUntil = 0;
@@ -572,9 +573,13 @@
}
// ---------- 更新动画状态 ----------
function updateWorld(sk) {
function updateWorld(sk, delta = 0, resetPhysics = false) {
if (sk.updateWorldTransform) {
if (spine.Physics && spine.Physics.update !== undefined) sk.updateWorldTransform(spine.Physics.update);
if (spine.Physics && spine.Physics.update !== undefined) {
if (delta > 0 && typeof sk.update === 'function') sk.update(delta);
const mode = resetPhysics && spine.Physics.reset !== undefined ? spine.Physics.reset : spine.Physics.update;
sk.updateWorldTransform(mode);
}
else sk.updateWorldTransform();
}
}
@@ -880,7 +885,7 @@
});
}
function applyAnimationPose(targetSkeleton, targetState, animation, time) {
function applyAnimationPose(targetSkeleton, targetState, animation, time, previousTime) {
if (typeof targetState.clearTracks === 'function') targetState.clearTracks();
else if (typeof targetState.clearTrack === 'function') targetState.clearTrack(0);
if (typeof targetSkeleton.setToSetupPose === 'function') targetSkeleton.setToSetupPose();
@@ -888,7 +893,7 @@
if (entry) entry.loop = false;
targetState.update(Math.max(0, time));
targetState.apply(targetSkeleton);
updateWorld(targetSkeleton);
updateWorld(targetSkeleton, previousTime === undefined ? 0 : Math.max(0, time - previousTime), previousTime === undefined);
}
function mergeBounds(total, next) {
@@ -916,7 +921,7 @@
probeRenderer = clippingRenderer.createRenderer(spine, context, activeRuntimeDir);
probeRenderer.premultipliedAlpha = premultipliedAlpha;
for (let index = 0; index < poseCount; index++) {
applyPose(index);
applyPose(index, index - 1);
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, size, size);
context.save();
@@ -972,14 +977,14 @@
previewStateData.defaultMix = 0;
const previewState = new spine.AnimationState(previewStateData);
let bounds = null;
for (const time of sampleTimes) {
applyAnimationPose(previewSkeleton, previewState, animation, time);
for (let index = 0; index < sampleTimes.length; index++) {
applyAnimationPose(previewSkeleton, previewState, animation, sampleTimes[index], index ? sampleTimes[index - 1] : undefined);
bounds = mergeBounds(bounds, getBounds(previewSkeleton));
}
bounds = bounds || stableFitBounds;
if (!bounds || bounds.width <= 0 || bounds.height <= 0) throw new Error(t('viewer.emptySkeletonMsg'));
bounds = await measureVisibleBounds(previewSkeleton, bounds, sampleTimes.length, (index) => {
applyAnimationPose(previewSkeleton, previewState, animation, sampleTimes[index]);
bounds = await measureVisibleBounds(previewSkeleton, bounds, sampleTimes.length, (index, previousIndex) => {
applyAnimationPose(previewSkeleton, previewState, animation, sampleTimes[index], previousIndex >= 0 ? sampleTimes[previousIndex] : undefined);
}) || bounds;
const off = document.createElement('canvas');
@@ -994,7 +999,7 @@
offRenderer = clippingRenderer.createRenderer(spine, octx, activeRuntimeDir);
offRenderer.premultipliedAlpha = premultipliedAlpha;
for (let index = 0; index < sampleTimes.length; index++) {
applyAnimationPose(previewSkeleton, previewState, animation, sampleTimes[index]);
applyAnimationPose(previewSkeleton, previewState, animation, sampleTimes[index], index ? sampleTimes[index - 1] : undefined);
octx.setTransform(1, 0, 0, 1, 0, 0);
octx.clearRect(0, 0, size, size);
octx.fillStyle = '#1e1e1e';
@@ -1371,10 +1376,12 @@
if (skeleton && state) {
if (playing) {
// Spine 运行时自身处理循环;持续 update 即可。
state.update(dt * speed);
const frameDelta = Math.min(Math.max(dt, 0), MAX_FRAME_DELTA) * speed;
state.update(frameDelta);
state.apply(skeleton);
updateWorld(skeleton, frameDelta);
}
updateWorld(skeleton);
else updateWorld(skeleton);
draw();
const entry = currentTrack();
if (entry) {
@@ -1611,7 +1618,7 @@
if (typeof skeleton.setBonesToSetupPose === 'function') skeleton.setBonesToSetupPose();
if (typeof skeleton.setSlotsToSetupPose === 'function') skeleton.setSlotsToSetupPose();
}
updateWorld(skeleton);
updateWorld(skeleton, 0, true);
updateTimelineDuration(null, true);
setStatus(t('viewer.setupPose'));
draw();
@@ -1693,7 +1700,7 @@
}
state.update(Math.max(0, time));
state.apply(skeleton);
updateWorld(skeleton);
updateWorld(skeleton, 0, true);
draw();
updateTimeReadout(time);
} catch (e) { /* ignore */ }