zenno/racelib: allow accel skills to be delayed
This commit is contained in:
@@ -25,7 +25,7 @@ export interface Travel {
|
||||
* @param start Motion at the beginning of the segment
|
||||
* @param targetSpeed Target speed to accelerate to
|
||||
* @param totalAccel Total (positive) acceleration including skill bonuses
|
||||
* @param maxDur Max duration of the acceleration, or infinite if not given
|
||||
* @param maxDur Max position of the acceleration, or infinite if not given
|
||||
* @param maxDist Max distance of the acceleration, or infinite if not given
|
||||
* @param decel Negative acceleration value for cases where target speed is below start speed
|
||||
* @returns Travel segment after reaching the first of the given limits
|
||||
@@ -40,13 +40,13 @@ export function travelSegment(
|
||||
): Travel {
|
||||
const a = start.v < targetSpeed ? totalAccel : (decel ?? -1);
|
||||
const dvt = (targetSpeed - start.v) / a;
|
||||
const dxt = maxDist != null ? (-start.v + Math.sqrt(start.v * start.v + 4 * a * maxDist)) / (2 * a) : dvt;
|
||||
const dxt = maxDist != null ? (-start.v + Math.sqrt(start.v * start.v + 4 * a * (maxDist - start.x))) / (2 * a) : dvt;
|
||||
const time = maxDur != null ? Math.min(dvt, dxt, maxDur) : Math.min(dvt, dxt);
|
||||
// To address numerical imprecision, if accel time comes from velocity or distance,
|
||||
// set the reached values directly.
|
||||
const v = time === dvt ? targetSpeed : start.v + time * a;
|
||||
const dist = maxDist != null && time === dxt ? maxDist : (start.v + 0.5 * a * time) * time;
|
||||
const end = { t: start.t + time, x: start.x + dist, v };
|
||||
const dist = maxDist != null && time === dxt ? maxDist : start.x + (start.v + 0.5 * a * time) * time;
|
||||
const end = { t: start.t + time, x: dist, v };
|
||||
return { start, end, a };
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ export function travelSegment(
|
||||
* Acceleration bonus from skills.
|
||||
*/
|
||||
export interface Skill {
|
||||
/**
|
||||
* Forward position along the course at which the skill activates.
|
||||
*/
|
||||
x?: number;
|
||||
/**
|
||||
* Acceleration modifier in m/s².
|
||||
*/
|
||||
@@ -74,16 +78,18 @@ export interface Skill {
|
||||
*/
|
||||
export function up(start: Instant, targetSpeed: number, baseAccel: number, skills: Skill[]) {
|
||||
const segments: Travel[] = [];
|
||||
const sk = skills.map((s) => ({ ...s })).filter((s) => s.dur > 0);
|
||||
const sk = skills.map((s) => ({ x: 0, ...s })).filter((s) => s.dur > 0);
|
||||
const xs = sk.map((s) => s.x).filter((x) => x > 0).sort((a, b) => a - b);
|
||||
while (start.v < targetSpeed) {
|
||||
const active = sk.filter((s) => s.dur > 0);
|
||||
if (active.length === 0) {
|
||||
const active = sk.filter((s) => s.dur > 0 && s.x <= start.x);
|
||||
const dx = xs.find((x) => x > start.x);
|
||||
if (active.length === 0 && dx == null) {
|
||||
segments.push(travelSegment(start, targetSpeed, baseAccel));
|
||||
break;
|
||||
}
|
||||
const boost = active.reduce((a, s) => a + s.accel, 0);
|
||||
const time = Math.min(...active.map((s) => s.dur));
|
||||
const seg = travelSegment(start, targetSpeed, baseAccel + boost, time);
|
||||
const seg = travelSegment(start, targetSpeed, baseAccel + boost, time, dx);
|
||||
segments.push(seg);
|
||||
start = seg.end;
|
||||
for (const s of active) {
|
||||
|
||||
Reference in New Issue
Block a user