likeRunner/src/main/kotlin/core/RunnerPhysics.kt
pythagodzilla 07cb1304d2 init
2026-03-19 17:57:03 +08:00

89 lines
2.7 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package core
import model.PhysicsState
/**
* 物理引擎 - 模拟真实的运动物理过程
*
* 职责:根据时间计算运动状态(距离、速度、加速度)
*
* 数据流:
* 时间 t
* ↓
* [PhysicsEngine.calculate(t)]
* ↓
* PhysicsState(distance, velocity, acceleration)
*
* 预留扩展:
* - 支持不同的运动模式(跑步/散步)
* - 支持加速度衰减曲线
* - 支持不同的速度曲线
*/
class RunnerPhysics(
private val totalDistance: Double = 0.0, // 总路线距离(米)
private val duration: Double = 1000.0, // 总运动时间(秒)
private val maxVelocity: Double = 4.0 // 最大速度m/s
) {
private val derivativeStepSeconds = 1.0
// 接入人类风格距离引擎(仅用于 time -> distance
private val distanceEngine: HumanLikeDistanceEngine? =
if (totalDistance > 0.0 && duration > 0.0 && maxVelocity > 0.0) {
HumanLikeDistanceEngine(
HumanLikeDistanceConfig(
totalDistanceMeters = totalDistance,
totalDurationSeconds = duration,
minSpeedMps = (maxVelocity * 0.45).coerceAtLeast(0.5),
maxSpeedMps = maxVelocity
)
)
} else {
null
}
/**
* 计算指定时间的物理状态
*
* @param time 当前时间(秒)
* @return 包含距离、速度、加速度的物理状态
*/
fun calculate(time: Double): PhysicsState {
// 1) 距离:由 distanceEngine 生成
// 2) 速度:对距离做一阶差分
// 3) 加速度:对速度做二阶差分
val t = time.coerceAtLeast(0.0)
val dt = derivativeStepSeconds
val distance = getDistance(t)
val t1 = (t - dt).coerceAtLeast(0.0)
val t2 = (t - 2 * dt).coerceAtLeast(0.0)
val d1 = getDistance(t1)
val d2 = getDistance(t2)
val vNow = if (t > t1) (distance - d1) / (t - t1) else 0.0
val vPrev = if (t1 > t2) (d1 - d2) / (t1 - t2) else vNow
val velocity = vNow.coerceAtLeast(0.0)
val acceleration = if (t > t1) ((vNow - vPrev) / (t - t1)) else 0.0
return PhysicsState(
time = t,
distance = distance,
velocity = velocity,
acceleration = acceleration
)
}
/**
* 获取指定时间的行进距离
*
* @param time 时间(秒)
* @return 行进距离(米)
*/
fun getDistance(time: Double): Double {
// 优先使用新引擎;参数无效时回退为简单线性进度
return distanceEngine?.getDistance(time) ?: time.coerceAtLeast(0.0)
}
}