修复跳一跳运行态方向与贴图刷新

恢复跳一跳运行态拖拽方向提交与后端方向落点计算

补齐平台六面贴图刷新签名和对应前端测试

更新跳一跳玩法链路文档与PRD方向契约说明
This commit is contained in:
kdletters
2026-06-09 17:42:24 +08:00
parent a0473771f1
commit 68dd48be42
5 changed files with 133 additions and 25 deletions

View File

@@ -13,6 +13,7 @@ import {
JUMP_HOP_THREE_CAMERA_UP_Y,
JumpHopRuntimeShell,
getJumpHopThreeProjectedY,
getJumpHopTileTextureSignature,
} from './JumpHopRuntimeShell';
vi.mock('../../hooks/useResolvedAssetReadUrl', () => ({
@@ -47,7 +48,7 @@ function dispatchPointerEvent(
target.dispatchEvent(event);
}
test('跳一跳运行态松手时提交长按蓄力值', async () => {
test('跳一跳运行态松手时提交长按蓄力值和后端方向向量', async () => {
vi.useFakeTimers();
const onJump = vi.fn().mockResolvedValue(undefined);
const run = buildRun();
@@ -90,14 +91,16 @@ test('跳一跳运行态松手时只提交长按蓄力值', async () => {
expect(onJump).toHaveBeenCalledTimes(1);
const jumpPayload = onJump.mock.calls[0]?.[0];
expect(jumpPayload?.dragVectorX).toBeUndefined();
expect(jumpPayload?.dragVectorY).toBeUndefined();
expect(typeof jumpPayload?.dragVectorX).toBe('number');
expect(typeof jumpPayload?.dragVectorY).toBe('number');
expect(Number.isFinite(jumpPayload?.dragVectorX)).toBe(true);
expect(Number.isFinite(jumpPayload?.dragVectorY)).toBe(true);
expect(jumpPayload?.dragDistance).toBeGreaterThanOrEqual(360);
expect(jumpPayload?.dragDistance).toBeLessThanOrEqual(380);
vi.useRealTimers();
});
test('跳一跳运行态手指移动不改变提交方向', async () => {
test('跳一跳运行态手指移动不改变蓄力时长但仍提交方向向量', async () => {
vi.useFakeTimers();
const onJump = vi.fn().mockResolvedValue(undefined);
const run = buildRun();
@@ -138,8 +141,10 @@ test('跳一跳运行态手指移动不改变提交方向', async () => {
});
const jumpPayload = onJump.mock.calls[0]?.[0];
expect(jumpPayload?.dragVectorX).toBeUndefined();
expect(jumpPayload?.dragVectorY).toBeUndefined();
expect(typeof jumpPayload?.dragVectorX).toBe('number');
expect(typeof jumpPayload?.dragVectorY).toBe('number');
expect(Number.isFinite(jumpPayload?.dragVectorX)).toBe(true);
expect(Number.isFinite(jumpPayload?.dragVectorY)).toBe(true);
expect(jumpPayload?.dragDistance).toBeGreaterThanOrEqual(240);
expect(jumpPayload?.dragDistance).toBeLessThanOrEqual(260);
vi.useRealTimers();
@@ -585,6 +590,29 @@ test('跳一跳新 UV 地板资源会解析六张面贴图而不是复用单张
).toBe(true);
});
test('跳一跳 Three.js 地板贴图签名包含六面贴图 URL', () => {
const asset = buildTileAssets({ withFaceAssets: true })[0];
const signature = getJumpHopTileTextureSignature(
{
'p1::top': 'top-url',
'p1::front': 'front-url',
'p1::right': 'right-url',
'p1::back': 'back-url',
'p1::left': 'left-url',
'p1::bottom': 'bottom-url',
},
'p1',
asset,
);
expect(signature).toContain('top-url');
expect(signature).toContain('front-url');
expect(signature).toContain('right-url');
expect(signature).toContain('back-url');
expect(signature).toContain('left-url');
expect(signature).toContain('bottom-url');
});
test('跳一跳运行态首块地块落在中下方并且后续两块向中央和上方展开', () => {
render(
<JumpHopRuntimeShell

View File

@@ -29,6 +29,7 @@ import {
formatJumpHopDurationLabel,
getJumpHopCharacterVisualPosition,
getJumpHopJumpFeedbackLabel,
getJumpHopBackendDragVector,
getJumpHopLandingAssistVisualPosition,
getJumpHopPlatformVisualSize,
getJumpHopRunDurationMs,
@@ -44,8 +45,8 @@ import { RuntimeResourcePendingMarker } from '../common/RuntimeResourcePendingMa
type JumpHopRuntimeJumpPayload = {
dragDistance: number;
dragVectorX?: number;
dragVectorY?: number;
dragVectorX: number;
dragVectorY: number;
};
type JumpHopVisualJump = {
@@ -289,6 +290,20 @@ function getJumpHopTileTextureUrl(
return textureUrls[getJumpHopTileTextureKey(renderKey, face)] ?? textureUrls[renderKey] ?? '';
}
export function getJumpHopTileTextureSignature(
textureUrls: Record<string, string>,
renderKey: string,
asset: JumpHopTileAsset | null | undefined,
) {
if (!asset?.faceAssets) {
return textureUrls[renderKey] ?? '';
}
return JUMP_HOP_TILE_FACE_KEYS.map((face) =>
getJumpHopTileTextureUrl(textureUrls, renderKey, face),
).join('|');
}
function hasJumpHopTileTexturesReady(
textureUrls: Record<string, string>,
renderKey: string,
@@ -953,7 +968,11 @@ function JumpHopThreeScene({
item.screenY.toFixed(3),
item.scale.toFixed(3),
cubeSide.toFixed(2),
textureUrls[item.renderKey] ?? '',
getJumpHopTileTextureSignature(
textureUrls,
item.renderKey,
item.asset,
),
item.advanceState,
].join(':');
})
@@ -2027,8 +2046,17 @@ export function JumpHopRuntimeShell({
x: targetDirection ? -targetDirection.unitScreenX : 0,
y: targetDirection ? -targetDirection.unitScreenY : 0,
});
const backendDragVector = getJumpHopBackendDragVector(
predictionRun ?? activeRun,
visiblePlatforms,
landingAssistStageSize,
targetDirection ? -targetDirection.unitScreenX : 0,
targetDirection ? -targetDirection.unitScreenY : 0,
);
await onJump({
dragDistance: nextDragDistance,
dragVectorX: backendDragVector.dragVectorX,
dragVectorY: backendDragVector.dragVectorY,
});
};