updated the collision for jumps and terrain

This commit is contained in:
phenom committed 2026-08-16 18:07:34 -04:00
1 parent c00f3211ea
commit e39aebf3a1
5 files changed
+138 -18

No files matched your search

+51 -1
View File
@@ -3,7 +3,8 @@ export const PLAYER_JUMP_COYOTE_MS = 100;
export const PLAYER_JUMP_BUFFER_MS = 120;
export const PLAYER_JUMP_LANDING_UNLOCK_MS = 80;
export const PLAYER_LANDING_PRESENTATION_MS = 180;
export const PLAYER_GROUND_PROBE_DISTANCE = 0.14;
export const PLAYER_AIRBORNE_PRESENTATION_DELAY_MS = 100;
export const PLAYER_GROUND_PROBE_DISTANCE = 0.22;
export const PLAYER_GROUND_MIN_NORMAL_Y = 0.55;
export type CharacterVerticalMotion = "grounded" | "rising" | "falling" | "landing";
@@ -15,6 +16,12 @@ export interface PlayerJumpTiming {
lockedUntilLanding: boolean;
}
export interface CharacterVerticalPresentationTiming {
airborneStartedAtMs: number;
airbornePresented: boolean;
landingUntilMs: number;
}
export interface GroundProbeHit {
readonly timeOfImpact: number;
readonly normal: { readonly y: number };
@@ -29,6 +36,14 @@ export function createPlayerJumpTiming(nowMs = Number.NEGATIVE_INFINITY): Player
};
}
export function createCharacterVerticalPresentationTiming(): CharacterVerticalPresentationTiming {
return {
airborneStartedAtMs: Number.NEGATIVE_INFINITY,
airbornePresented: false,
landingUntilMs: Number.NEGATIVE_INFINITY,
};
}
export function bufferPlayerJump(timing: PlayerJumpTiming, requestedAtMs: number): void {
if (!Number.isFinite(requestedAtMs)) return;
timing.bufferedUntilMs = requestedAtMs + PLAYER_JUMP_BUFFER_MS;
@@ -92,3 +107,38 @@ export function characterVerticalMotion(
if (grounded) return nowMs < landingUntilMs ? "landing" : "grounded";
return verticalVelocity > 0.15 ? "rising" : "falling";
}
/**
* Keeps tiny terrain gaps from interrupting locomotion with a fall/land pair.
* An intentional jump is presented immediately; an incidental loss of ground
* must persist before it becomes visible, and only visible airtime may land.
*/
export function updateCharacterVerticalPresentation(
timing: CharacterVerticalPresentationTiming,
grounded: boolean,
verticalVelocity: number,
nowMs: number,
intentionalJump: boolean,
): CharacterVerticalMotion {
if (!Number.isFinite(nowMs)) {
return characterVerticalMotion(grounded, verticalVelocity, 0, Number.NEGATIVE_INFINITY);
}
if (!grounded) {
if (!Number.isFinite(timing.airborneStartedAtMs)) timing.airborneStartedAtMs = nowMs;
if (
intentionalJump
|| nowMs - timing.airborneStartedAtMs >= PLAYER_AIRBORNE_PRESENTATION_DELAY_MS
) timing.airbornePresented = true;
return timing.airbornePresented
? characterVerticalMotion(false, verticalVelocity, nowMs, timing.landingUntilMs)
: "grounded";
}
if (timing.airbornePresented) {
timing.landingUntilMs = nowMs + PLAYER_LANDING_PRESENTATION_MS;
}
timing.airborneStartedAtMs = Number.NEGATIVE_INFINITY;
timing.airbornePresented = false;
return characterVerticalMotion(true, verticalVelocity, nowMs, timing.landingUntilMs);
}