+
+void Physics::collide_circle_box(unsigned i, unsigned j)
+{
+ const LinAl::Vector<float, 2> &pos1 = entities[i].position;
+ const LinAl::Vector<float, 2> &pos2 = entities[j].position;
+ float radius = entities[i].entity->get_collider()->get_radius();
+ LinAl::Vector<float, 2> half_size = entities[j].entity->get_collider()->get_size()/2.0f;
+
+ LinAl::Vector<float, 2> delta = pos1-pos2;
+ float c = cos(entities[j].rotation);
+ float s = sin(entities[j].rotation);
+ LinAl::Vector<float, 2> local_delta(c*delta.x+s*delta.y, c*delta.y-s*delta.x);
+ LinAl::Vector<float, 2> local_closest(clamp(local_delta.x, -half_size.x, half_size.x), clamp(local_delta.y, -half_size.y, half_size.y));
+ LinAl::Vector<float, 2> local_cdelta = local_delta-local_closest;
+ float d_sq = inner_product(local_cdelta, local_cdelta);
+
+ if(d_sq<radius*radius)
+ {
+ Collision &collision = get_collision(i, j);
+ if(d_sq>1e-10)
+ {
+ collision.normal = normalize(LinAl::Vector<float, 2>(c*local_cdelta.x-s*local_cdelta.y, c*local_cdelta.y+s*local_cdelta.x));
+ collision.depth = radius-sqrt(d_sq);
+ }
+ else
+ {
+ LinAl::Vector<float, 2> inside_dist(half_size.x-abs(local_delta.x), half_size.y-abs(local_delta.y));
+ if(inside_dist.x<inside_dist.y)
+ {
+ collision.normal = LinAl::Vector<float, 2>(c, s) * (local_delta.x<0 ? -1.0f : 1.0f);
+ collision.depth = radius+inside_dist.x;
+ }
+ else
+ {
+ collision.normal = LinAl::Vector<float, 2>(-s, c) * (local_delta.y<0 ? -1.0f : 1.0f);
+ collision.depth = radius+inside_dist.y;
+ }
+ }
+ collision.point = pos1-collision.normal*(radius-collision.depth/2);
+ if(collision.body1!=i)
+ collision.normal = -collision.normal;
+ }
+}