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;
}