void BasicAbstractGame::basic_step_object()

in procgen/src/basic-abstract-game.cpp [593:656]


void BasicAbstractGame::basic_step_object(const std::shared_ptr<Entity> &obj) {
    if (obj->will_erase)
        return;

    int num_sub_steps;

    if (grid_step) {
        num_sub_steps = 1;
    } else {
        num_sub_steps = int(4 * sqrt(obj->vx * obj->vx + obj->vy * obj->vy));
        if (num_sub_steps < 4)
            num_sub_steps = 4;
    }

    float pct = 1.0 / num_sub_steps;

    float cmp = fabs(obj->vx) - fabs(obj->vy);

    /*
     Resolve ties randomly -- important for randomized movement through tight corridors in orbeater.
     In order to ensure that enemies choose randomly between horizontal/vertical forks in a path,
     this collision detection shouldn't favor one direction over another.
    */
    bool step_x_first = cmp == 0 ? step_rand_int % 2 == 0 : (cmp > 0);

    // edge case -- needed for player movement through tight corridors (e.g. Pacman)
    if (obj->type == PLAYER) {
        if (action_vx != 0)
            step_x_first = true;
        if (action_vy != 0)
            step_x_first = false;
    }

    float vx_pct = 0;
    float vy_pct = 0;

    for (int s = 0; s < num_sub_steps; s++) {
        bool block_x = false;
        bool block_y = false;

        if (step_x_first) {
            block_x = sub_step(obj, obj->vx * pct, 0, 0);
            block_y = sub_step(obj, 0, obj->vy * pct, 0);
        } else {
            block_y = sub_step(obj, 0, obj->vy * pct, 0);
            block_x = sub_step(obj, obj->vx * pct, 0, 0);
        }

        if (!block_x)
            vx_pct += 1;
        if (!block_y)
            vy_pct += 1;

        if (block_x && block_y) {
            break;
        }
    }

    vx_pct = vx_pct / num_sub_steps;
    vy_pct = vy_pct / num_sub_steps;

    obj->vx *= vx_pct;
    obj->vy *= vy_pct;
}