improved handling of interpolate_move calls with a distance shorter than minimum delta

pull/10/head
Sara 2023-06-24 22:42:38 +02:00
parent b8c856bf56
commit a9ba15f93b
1 changed files with 40 additions and 54 deletions

View File

@ -179,91 +179,77 @@ float get_solve_force(const object_t* a, const object_t* b, float* out_px, float
} }
static inline static inline
void _solve_collision_slide(object_t* this, object_t* other, float old_x, float old_y, float new_x, float new_y) { void _solve_collision_slide(object_t* this, object_t* other) {
float dx, dy; float dx, dy;
const float d = get_solve_force(this, other, &dx, &dy); const float d = get_solve_force(this, other, &dx, &dy);
this->sprite.x += dx; this->sprite.x += dx;
this->sprite.y += dy; this->sprite.y += dy;
return;
this->sprite.x = old_x;
this->sprite.y = new_y;
if(!_collision_check(other, this)) {
return;
} }
this->sprite.x = new_x; static inline
this->sprite.y = old_y; void _solve_move(object_t* this) {
if(!_collision_check(other, this)) { // loop over all objects and check collision if applicable
return; for(int i = 0; i < WORLD_NUM_OBJECTS; ++i) {
// get pointer to other object
object_t* other = g_objects + i;
// check collision, return if found
if(can_collide(other) && this != other && _collision_check(other, this)) {
object_broadcast_collision(other, this);
object_broadcast_collision(this, other);
_solve_collision_slide(this, other);
} }
this->sprite.x = old_x;
this->sprite.y = old_y;
if(!_collision_check(other, this)) {
return;
} }
} }
void interpolate_move(object_t* object, const float target_x, const float target_y, const float max_step_size, const int slide) { void interpolate_move(object_t* this, const float target_x, const float target_y, const float max_step_size, const int slide) {
// calculate step delta // calculate step delta
float dx = target_x - object->sprite.x, dy = target_y - object->sprite.y; float dx = target_x - this->sprite.x, dy = target_y - this->sprite.y;
if(dx == 0 && dy == 0) if(dx == 0 && dy == 0)
return; return;
// calculate direction x,y // calculate direction x,y
float m = sqrtf(dx*dx + dy*dy); float m = sqrtf(dx*dx + dy*dy);
if(dx != 0)
dx /= m; dx /= m;
if(dy != 0)
dy /= m; dy /= m;
dx *= max_step_size; dy *= max_step_size; dx *= max_step_size; dy *= max_step_size;
int step_count = max_step_size / m; int step_count = max_step_size / m;
// ensure this object would ever collide // ensure this object would ever collide
// if it wouldn't collide anyway, just set position // if it wouldn't collide anyway, just set position
if(!can_collide(object)) { if(!can_collide(this)) {
object->sprite.x = target_x; this->sprite.x = target_x;
object->sprite.y = target_y; this->sprite.y = target_y;
return; return;
} }
if(step_count == 0) {
this->sprite.x = target_x;
this->sprite.y = target_y;
_solve_move(this);
}
/* /*
* 1. move towards target * 1. move towards target
* 2. check collision with every other object * 2. check collision with every other object
*/ */
for(int steps = 0; steps < step_count && (object->sprite.x != target_x || object->sprite.y != target_y); ++steps) { for(int steps = 0; steps <= step_count && (this->sprite.x != target_x || this->sprite.y != target_y); ++steps) {
// move towards target, snap to target if distance is too low // move towards target, snap to target if distance is too low
const float old_x = object->sprite.x, old_y = object->sprite.y; const float old_x = this->sprite.x, old_y = this->sprite.y;
float new_x, new_y; float new_x, new_y;
const float distx = fabsf(object->sprite.x - target_x), disty = fabsf(object->sprite.y - target_y); const float distx = fabsf(this->sprite.x - target_x), disty = fabsf(this->sprite.y - target_y);
const float sqdist = distx*distx + disty*disty; const float sqdist = distx*distx + disty*disty;
if(sqdist > max_step_size) { if(sqdist > max_step_size*max_step_size) {
object->sprite.x += dx; this->sprite.x += dx;
object->sprite.y += dy; this->sprite.y += dy;
new_x = object->sprite.x; new_x = this->sprite.x;
new_y = object->sprite.y; new_y = this->sprite.y;
} else { } else {
new_x = object->sprite.x = target_x; this->sprite.x = target_x;
new_y = object->sprite.y = target_y; this->sprite.y = target_y;
new_x = target_x;
new_y = target_y;
} }
// loop over all objects and check collision if applicable _solve_move(this);
for(int i = 0; i < WORLD_NUM_OBJECTS; ++i) {
// get pointer to other object
object_t* other = g_objects + i;
// check collision, return if found
if(can_collide(other) && object != other && _collision_check(other, object)) {
object_broadcast_collision(other, object);
object_broadcast_collision(object, other);
if(slide) {
_solve_collision_slide(object, other, old_x, old_y, new_x, new_y);
} else {
object->sprite.x = old_x;
object->sprite.y = old_y;
return;
}
}
}
} }
} }