aboutsummaryrefslogtreecommitdiff
path: root/collisions.c
blob: e9f0c13ab505bca355be258ce1812878c5cc3b0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#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);
	    }
	}
    }
}