aboutsummaryrefslogtreecommitdiff
#include "game.h"

struct FRect
{
  float x, y, w, h;
};

static inline bool colliding2D(const struct FRect *a, const struct FRect *b)
{
  return ((a->x + a->w > b->x && a->x < b->x + b->w)
	  && (a->y + a->h > b->y && a->y < b->y + b->h));
}

bool frect_intersect(const struct FRect *a, const struct FRect *b, struct FRect *res)
{
  res->x = fmaxf(a->x, b->x);
  res->w = fminf(a->x + a->w, b->x + b->w) - fmaxf(a->x, b->x);
  res->y = fmaxf(a->y, b->y);
  res->h = fminf(a->y + a->h, b->y + b->h) - fmaxf(a->y, b->y);

  return colliding2D(a, b);
}

bool colliding_vertically(const struct Entity *a, const struct Entity *b, const struct FRect *res)
{
  //return a->y + a->h < b->y + b->h / 2.0f || b->y + b->h < a->y + a->h / 2.0f;
  return res->w > res->h;
}

void collide_with_fixed(struct Entity *e, struct Entity *fixed, const struct FRect *res)
{
  // Check if either of the boxes
  if( colliding_vertically(e, fixed, res) )
    {
      e->y += (e->y < fixed->y) ? -res->h : res->h;
      e->dy = 0.0f;
    }
  else
    {
      e->x += (e->x < fixed->x) ? -res->w : res->w;
      e->dx = 0.0f;
    }
}

void collide(struct Entity *a, struct Entity *b, const struct FRect *res)
{
  float a_disp, b_disp;

  float vx_sum, vy_sum;
  vx_sum = fabsf(a->dx) + fabsf(b->dx);
  vy_sum = fabsf(a->dy) + fabsf(b->dy);

  // Check if either of the boxes
  if( colliding_vertically(a, b, res) )
    {
      a_disp = vy_sum == 0.0f ? res->h / 2.0f : res->h * (fabsf(a->dy) / vy_sum);
      b_disp = vy_sum == 0.0f ? res->h / 2.0f : res->h * (fabsf(b->dy) / vy_sum);
      //a_disp = res->h / 2.0f;
      //b_disp = res->h / 2.0f;

      a->y += (a->y < b->y) ? -a_disp : a_disp;
      b->y -= (a->y < b->y) ? -b_disp : b_disp;

      a->dy = 0.0f;
      b->dy = 0.0f;
    }
  else
    {
      a_disp = vx_sum == 0.0f ? res->w / 2.0f : res->w * (fabsf(a->dx) / vx_sum);
      b_disp = vx_sum == 0.0f ? res->w / 2.0f : res->w * (fabsf(b->dx) / vx_sum);
      //a_disp = res->w / 2.0f;
      //b_disp = res->w / 2.0f;

      a->x += (a->x < b->x) ? -a_disp : a_disp;
      b->x -= (a->x < b->x) ? -b_disp : b_disp;

      a->dx = 0.0f;
      b->dx = 0.0f;
    }
}

void check_collisions(void)
{
  int i, j;
  struct Entity *a, *b;

  for(i = 0; i < game->num_entities; i ++)
    {
      a = game->entities[i];

      if(!a)
	continue;

      for(j = i + 1; j < game->num_entities; j ++)
	{
	  b = game->entities[j];

	  if(!b)
	    continue;

	  struct FRect res;
	  struct FRect r1 = {a->x, a->y, a->w, a->h};
	  struct FRect r2 = {b->x, b->y, b->w, b->h};

	  if( frect_intersect(&r1, &r2, &res) )
	    {
	      if(a->collidable && b->collidable)
		{
		  if(!a->fixed && !b->fixed)
		    {
		      collide(a, b, &res);
		    }
		  else if(a->fixed && !b->fixed)
		    {
		      collide_with_fixed(b, a, &res);
		    }
		  else if(!a->fixed && b->fixed)
		    {
		      collide_with_fixed(a, b, &res);
		    }
		}

	      if(a->on_collision)
		a->on_collision(a, b);
	      if(b->on_collision)
		b->on_collision(b, a);
	    }
	}
    }
}