* refactor swing animation to controller * idle animator!!!! * implelment state switch transition * a huge fix for UI server edit! * adjust ui scaling so main menu elements clip less * view bobbing, new config name, ws: * EXTREMELY important fixes to entities rendering * a lot of fixes, add dns resolve fallback * improve f3 E, fix modal not found edge case * set correctly target for old browsers, should fix ios 14 crash * unecessary big refactor, to fix ts err * fix isWysiwyg check * fix entities rendering count
94 lines
3.1 KiB
TypeScript
94 lines
3.1 KiB
TypeScript
export class CameraBobbing {
|
|
private walkDistance = 0
|
|
private prevWalkDistance = 0
|
|
private bobAmount = 0
|
|
private prevBobAmount = 0
|
|
private readonly gameTimer = new GameTimer()
|
|
|
|
// eslint-disable-next-line max-params
|
|
constructor (
|
|
private readonly BOB_FREQUENCY: number = Math.PI, // How fast the bob cycles
|
|
private readonly BOB_BASE_AMPLITUDE: number = 0.5, // Base amplitude of the bob
|
|
private readonly VERTICAL_MULTIPLIER: number = 1, // Vertical movement multiplier
|
|
private readonly ROTATION_MULTIPLIER_Z: number = 3, // Roll rotation multiplier
|
|
private readonly ROTATION_MULTIPLIER_X: number = 5 // Pitch rotation multiplier
|
|
) {}
|
|
|
|
// Call this when player is moving
|
|
public updateWalkDistance (distance: number): void {
|
|
this.prevWalkDistance = this.walkDistance
|
|
this.walkDistance = distance
|
|
}
|
|
|
|
// Call this when player is moving to update bob amount
|
|
public updateBobAmount (isMoving: boolean): void {
|
|
const targetBob = isMoving ? 1 : 0
|
|
this.prevBobAmount = this.bobAmount
|
|
|
|
// Update timing
|
|
const ticks = this.gameTimer.update()
|
|
const deltaTime = ticks / 20 // Convert ticks to seconds assuming 20 TPS
|
|
|
|
// Smooth transition for bob amount
|
|
const bobDelta = (targetBob - this.bobAmount) * Math.min(1, deltaTime * 10)
|
|
this.bobAmount += bobDelta
|
|
}
|
|
|
|
// Call this in your render/animation loop
|
|
public getBobbing (): { position: { x: number, y: number }, rotation: { x: number, z: number } } {
|
|
// Interpolate walk distance
|
|
const walkDist = this.prevWalkDistance +
|
|
(this.walkDistance - this.prevWalkDistance) * this.gameTimer.partialTick
|
|
|
|
// Interpolate bob amount
|
|
const bob = this.prevBobAmount +
|
|
(this.bobAmount - this.prevBobAmount) * this.gameTimer.partialTick
|
|
|
|
// Calculate total distance for bob cycle
|
|
const totalDist = -(walkDist * this.BOB_FREQUENCY)
|
|
|
|
// Calculate offsets
|
|
const xOffset = Math.sin(totalDist) * bob * this.BOB_BASE_AMPLITUDE
|
|
const yOffset = -Math.abs(Math.cos(totalDist) * bob) * this.VERTICAL_MULTIPLIER
|
|
|
|
// Calculate rotations (in radians)
|
|
const zRot = (Math.sin(totalDist) * bob * this.ROTATION_MULTIPLIER_Z) * (Math.PI / 180)
|
|
const xRot = (Math.abs(Math.cos(totalDist - 0.2) * bob) * this.ROTATION_MULTIPLIER_X) * (Math.PI / 180)
|
|
|
|
return {
|
|
position: { x: xOffset, y: yOffset },
|
|
rotation: { x: xRot, z: zRot }
|
|
}
|
|
}
|
|
}
|
|
|
|
class GameTimer {
|
|
private readonly msPerTick: number
|
|
private lastMs: number
|
|
public partialTick = 0
|
|
|
|
constructor (tickRate = 20) {
|
|
this.msPerTick = 1000 / tickRate
|
|
this.lastMs = performance.now()
|
|
}
|
|
|
|
update (): number {
|
|
const currentMs = performance.now()
|
|
const deltaSinceLastTick = currentMs - this.lastMs
|
|
|
|
// Calculate how much of a tick has passed
|
|
const tickDelta = deltaSinceLastTick / this.msPerTick
|
|
this.lastMs = currentMs
|
|
|
|
// Add to accumulated partial ticks
|
|
this.partialTick += tickDelta
|
|
|
|
// Get whole number of ticks that should occur
|
|
const wholeTicks = Math.floor(this.partialTick)
|
|
|
|
// Keep the remainder as the new partial tick
|
|
this.partialTick -= wholeTicks
|
|
|
|
return wholeTicks
|
|
}
|
|
}
|