improve this float RLBotBot::calculateMinAirTime(const Vec& playerPos, const Vec& playerVel, bool hasFlip) {
    constexpr float GRAVITY = 650.0f; // Units per second squared (adjust based on game physics)

    // Initialize simulation parameters
    float t = 0.0f;
    Vec pos = playerPos;
    Vec vel = playerVel;
    float timeToGround = std::numeric_limits<float>::infinity();
    float timeToSideWall = std::numeric_limits<float>::infinity();
    float timeToBackWall = std::numeric_limits<float>::infinity();
    float timeToCeiling = std::numeric_limits<float>::infinity();

    // Simulate the player's trajectory over time
    while (t < MAX_PREDICTION_TIME) {
        // Update position and velocity
        // Only vertical velocity is affected by gravity
        pos.z += vel.z * TIME_STEP + 0.5f * (-GRAVITY) * TIME_STEP * TIME_STEP;
        vel.z += (-GRAVITY) * TIME_STEP;

        pos.x += vel.x * TIME_STEP;
        pos.y += vel.y * TIME_STEP;

        // Check for ground collision
        if (pos.z <= CommonValues::BALL_RADIUS) { // Assuming ground is at z = 0
            timeToGround = t;
            break; // Ground collision is the earliest possible
        }

        // Check for ceiling collision
        if (vel.z > 0.0f && pos.z + CommonValues::BALL_RADIUS >= CommonValues::CEILING_Z) {
            timeToCeiling = t;
            // Do not break; the player might hit the ceiling before the ground
            // But ground collision is prioritized
            break;
        }

        // Check for side wall collision
        if (vel.x != 0.0f) {
            float timeToCurrentSideWall = 0.0f;
            if (vel.x > 0.0f) {
                timeToCurrentSideWall = (CommonValues::SIDE_WALL_X - pos.x - CommonValues::BALL_RADIUS) / vel.x;
            }
            else {
                timeToCurrentSideWall = (-CommonValues::SIDE_WALL_X - pos.x + CommonValues::BALL_RADIUS) / vel.x;
            }
            if (timeToCurrentSideWall >= 0.0f && timeToCurrentSideWall <= TIME_STEP) {
                timeToSideWall = t;
                //RG_LOG(timeToSideWall);
                break;
            }
        }

        // Check for back wall collision
        if (vel.y != 0.0f) {
            float timeToCurrentBackWall = 0.0f;
            if (vel.y > 0.0f) {
                timeToCurrentBackWall = (CommonValues::BACK_WALL_Y - pos.y - CommonValues::BALL_RADIUS) / vel.y;
            }
            else {
                timeToCurrentBackWall = (-CommonValues::BACK_WALL_Y - pos.y + CommonValues::BALL_RADIUS) / vel.y;
            }
            if (timeToCurrentBackWall >= 0.0f && timeToCurrentBackWall <= TIME_STEP) {
                timeToBackWall = t;
                //RG_LOG(timeToBackWall);
                break;
            }
        }

        // Increment time
        t += TIME_STEP;
    }

    // Determine the minimum time among all collision possibilities
    float minAirTime = RS_MIN(timeToGround, timeToSideWall, timeToBackWall, timeToCeiling);
    // Ensure the minimum air time is not negative or NaN
    if (minAirTime < 0.0f || std::isnan(minAirTime)) {
        minAirTime = 0.0f;
    }
    
    return minAirTime;
}


float RLBotBot::calculateTimeToReach(const RLGSC::GameState& gs) {
    constexpr float STEP_INTERVAL = 1.0f / 60.0f;
    constexpr float DIST_REACH_THRESH = 80.0f;
    constexpr float FLIP_FORCE = 495.0f;
    constexpr float MAX_TOTAL_SPEED = 2300.0f;
    constexpr float MAX_DRIVE_SPEED = 1410.0f;
    constexpr float BREAK_ACCEL = 3500.0f;
    constexpr float BOOST_ACCEL = 991.667f;
    constexpr float DRIVE_ACCEL = 1600.0f;
    constexpr float GRAVITY = 650.0f;

    const auto& car = gs.players[this->index];
    const auto& ball = gs.ball;

    Vec carPos = car.phys.pos;
    Vec carVel = car.phys.vel;
    Vec targetPos = ball.pos;
    Vec dirToTarget = (targetPos - carPos).Normalized();

    float dist = (targetPos - carPos).Length();
    float vel = carVel.Dot(dirToTarget);
    float rotTime = calculateRotationTime(gs);

    // Calculate the minimum time to land on any surface
    float minAirTime = calculateMinAirTime(carPos, carVel, car.hasFlip);
    RG_LOG(minAirTime);

    float t = 0.0f;
    float curDist = dist;
    float curVel = vel;
    Vec pos = carPos;
    Vec curVelVec = carVel;

    // Simulate air time
    for (; t < minAirTime && curDist > DIST_REACH_THRESH; t += STEP_INTERVAL) {
        // Update position and velocity
        pos += curVelVec * STEP_INTERVAL;
        curVelVec.z += -GRAVITY * STEP_INTERVAL;

        if (t == 0.0f && curVel < MAX_TOTAL_SPEED) {
            // Apply flip force only at the beginning
            curVelVec += dirToTarget * (FLIP_FORCE * STEP_INTERVAL);
        }

        curVel = curVelVec.Dot(dirToTarget);
        curDist = (targetPos - pos).Length();
    }

    // After landing: apply acceleration logic
    for (; curDist > DIST_REACH_THRESH; t += STEP_INTERVAL) {
        bool hasRotated = t >= rotTime;

        if (curVel < 0.0f) {
            curVel += (BREAK_ACCEL + BOOST_ACCEL * hasRotated) * STEP_INTERVAL;
            curVel = RS_CLAMP(curVel, -MAX_TOTAL_SPEED, MAX_TOTAL_SPEED);
        }
        else if (curVel < MAX_DRIVE_SPEED) {
            curVel += (DRIVE_ACCEL + BOOST_ACCEL * hasRotated) * STEP_INTERVAL;
            curVel = RS_CLAMP(curVel, 0.0f, MAX_DRIVE_SPEED);
        }
        else if (curVel < MAX_TOTAL_SPEED) {
            curVel += BOOST_ACCEL * hasRotated * STEP_INTERVAL;
            curVel = RS_CLAMP(curVel, 0.0f, MAX_TOTAL_SPEED);
        }

        curDist -= curVel * STEP_INTERVAL;
    }

    return t;
} calculate minimum time to the nearest surface first
fredrik._. — 08/03/2024 9:50 PM
so if its on the wall i first calculate the time to ground then time too ball?
thats pretty smart
Zealan — 08/03/2024 9:52 PM
its hard though
because what if the optimal landing spot isnt the fastest landing spot
but a landing spot closer to the ball
fredrik._. — 08/03/2024 9:52 PM
damn
how did you solve that then?
Zealan — 08/03/2024 9:52 PM
minimum case assumptions minimum case just means we combine the minimum possible answer from multiple cases
to make a combined answer that might be too low, but cant be too highwell we have multiple cases
going in the air to the ball
landing from the air and driving to the ball
its not obvious where to land though
or if its worth it at all
however under minimum cases, we assume that they reach a surface in their minimum surface reach time, then we assume they accelerate on that surface until they reach the ball, even if the minumum reach point isnt at the ball yet