1
1
Fork 0
Browse Source

Collision detection works between polys, added force and collision box debug indicators

thread-physics
user 5 years ago
parent
commit
019bc8b133
  1. 2
      debuginfo.h
  2. 105
      draw.c
  3. 5
      draw.h
  4. 223
      game.c
  5. 12
      game.h
  6. 9
      vect.c
  7. 3
      vect.h

2
debuginfo.h

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
#define SHOWCOLLISIONBOX 1

105
draw.c

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
#include "draw.h"
#include "vect.h"
/* generic rendering functions */
int MAX_ONSCREEN_OBJECTS = 99;
@ -32,8 +33,7 @@ SDL_Texture * load_image(SDL_Renderer * ren, char fname[]) { @@ -32,8 +33,7 @@ SDL_Texture * load_image(SDL_Renderer * ren, char fname[]) {
}
/* Game Specific rendering functions */
void draw_player(SDL_Renderer * ren, int x, int y) {
void draw_player(SDL_Renderer * ren, int x, int y, bool red) {
logwrite(DEBUG, "Drawing player\n");
/* draw the player as a coloured rect */
@ -45,28 +45,103 @@ void draw_player(SDL_Renderer * ren, int x, int y) { @@ -45,28 +45,103 @@ void draw_player(SDL_Renderer * ren, int x, int y) {
player_rect.w = 10;
player_rect.h = 10;
SDL_SetRenderDrawColor(ren, 0,0,0, 255);
if (red) {
SDL_SetRenderDrawColor(ren, 255, 0, 0, 255);
} else {
SDL_SetRenderDrawColor(ren, 120, 85, 188, 255);
}
SDL_RenderDrawRect(ren, &player_rect);
SDL_SetRenderDrawColor(ren, 120, 85, 188, 255);
SDL_RenderFillRect(ren, &player_rect);
SDL_SetRenderDrawColor(ren, 0,0,0, 255);
}
// draw collision poly
void draw_collision_poly(SDL_Renderer* ren, Body *body) {
if (!SHOWCOLLISION) {
return;
}
SDL_SetRenderDrawColor(ren, 0, 255, 0, 255);
if (body->collision_poly_size == 1) {
SDL_Rect dot;
dot.x = body->collision_poly[0].x;
dot.y = body->collision_poly[0].y;
dot.w = 4;
dot.h = 4;
SDL_RenderDrawRect(ren, &dot);
SDL_RenderFillRect(ren, &dot);
} else if (body->collision_poly_size == 2) {
int x_st = body->collision_poly[0].x;
int y_st = body->collision_poly[0].y;
int x_en = body->collision_poly[1].x;
int y_en = body->collision_poly[1].y;
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en);
} else if (body->collision_poly_size > 2) {
int x_st = body->collision_poly[0].x;
int y_st = body->collision_poly[0].y;
int x_en, y_en;
for (int i = 1; i < body->collision_poly_size; i++) {
x_en = body->collision_poly[i].x;
y_en = body->collision_poly[i].y;
printf("colpoly: %d %d %d %d\n", x_st, y_st, x_en, y_en);
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en);
x_st = x_en;
y_st = y_en;
}
x_en = body->collision_poly[0].x;
y_en = body->collision_poly[0].y;
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en);
}
SDL_SetRenderDrawColor(ren, 0,0,0, 255);
}
// draw indicator of forces acting on an object
void draw_forces(SDL_Renderer *ren, Body *body) {
if (!SHOWFORCES) {
return;
}
Vect start;
start.x = (int)body->x_pos;
start.y = (int)body->y_pos;
Vect F;
for (int i = 0; i < body->num_motors; i++) {
if (body->motors[i].TTL <= 0) {
continue;
}
F.x += body->motors[i].x;
F.y += body->motors[i].y;
Vect end = vect_add(start, F);
SDL_SetRenderDrawColor(ren, 255,0,0, 255);
SDL_RenderDrawLine(ren, start.x, start.y, start.x, end.y);
SDL_SetRenderDrawColor(ren, 0,0,255, 255);
SDL_RenderDrawLine(ren, start.x, start.y, end.x, start.y);
}
SDL_SetRenderDrawColor(ren, 0,0,0, 255);
}
void draw_wall(SDL_Renderer *ren, Wall *wall) {
float x_st, x_en, y_st, y_en;
x_st = wall->nodes[0].x;
y_st = wall->nodes[0].y;
SDL_SetRenderDrawColor(ren, 120, 85, 188, 255);
int x_st, x_en, y_st, y_en;
x_st = wall->nodes[0].x + wall->physics->x_pos;
y_st = wall->nodes[0].y + wall->physics->y_pos;
for (int i = 1; i < wall->numNodes; i++) {
x_en = wall->nodes[i].x;
y_en = wall->nodes[i].y;
printf("wall: %f %f %f %f\n", x_st, y_st, x_en, y_en);
SDL_SetRenderDrawColor(ren, 120, 85, 188, 255);
x_en = wall->nodes[i].x + wall->physics->x_pos;
y_en = wall->nodes[i].y + wall->physics->y_pos;
printf("wall: %d %d %d %d\n", x_st, y_st, x_en, y_en);
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en);
SDL_SetRenderDrawColor(ren, 0,0,0, 255);
x_st = x_en;
y_st = y_en;
}
x_en = wall->nodes[0].x + wall->physics->x_pos;
y_en = wall->nodes[0].y + wall->physics->y_pos;
SDL_RenderDrawLine(ren, x_st, y_st, x_en, y_en);
SDL_SetRenderDrawColor(ren, 0,0,0, 255);
}
int distance_colour(int x, int y, int x2, int y2, int blackpoint) {
@ -93,7 +168,6 @@ int distance_colour(int x, int y, int x2, int y2, int blackpoint) { @@ -93,7 +168,6 @@ int distance_colour(int x, int y, int x2, int y2, int blackpoint) {
void redraw_buffer(SDL_Renderer * ren) {
static int mousex = 0;
static int mousey = 0;
static int newmousex = 0;
@ -122,10 +196,13 @@ void redraw_buffer(SDL_Renderer * ren) { @@ -122,10 +196,13 @@ void redraw_buffer(SDL_Renderer * ren) {
case PLAYER:
newmousex = (*thing.player).physics->x_pos;
newmousey = (*thing.player).physics->y_pos;
draw_player(ren, (*thing.player).physics->x_pos, (*thing.player).physics->y_pos);
draw_player(ren, (*thing.player).physics->x_pos, (*thing.player).physics->y_pos, thing.player->colliding);
draw_collision_poly(ren, thing.player->physics);
draw_forces(ren, thing.player->physics);
break;
case STATIC_WALL_W:
draw_wall(ren, thing.wall);
draw_collision_poly(ren, thing.wall->physics);
break;
}
}

5
draw.h

@ -5,6 +5,9 @@ @@ -5,6 +5,9 @@
#ifndef _DEFDRAW
#define _DEFDRAW
#define SHOWCOLLISION 1
#define SHOWFORCES 1
#include "garbo.h"
#include "game.h"
@ -18,7 +21,7 @@ void render_texture_at(struct SDL_Renderer * ren, struct SDL_Texture * texture,i @@ -18,7 +21,7 @@ void render_texture_at(struct SDL_Renderer * ren, struct SDL_Texture * texture,i
SDL_Texture * load_image(SDL_Renderer * ren, char fname[]);
/* Load an image into a texture */
void draw_player(SDL_Renderer * ren, int x, int y);
void draw_player(SDL_Renderer * ren, int x, int y, bool red);
/* draw the player as a coloured rect */
//void queue_draw_item(void * object, draw_type kind);

223
game.c

@ -1,14 +1,24 @@ @@ -1,14 +1,24 @@
#include "game.h"
#include "vect.h"
#define GRAVITY_ACCEL 2
player_st *glob_player;
void set_motor_newtons(Body *thing, int motorID, double x, double y);
void set_motor_max_velocity(Body *thing, int motorID, double max);
// move the collision poly to the position of the player
void default_update_collision_poly(Body *body) {
return;
printf("Collision polygon: ");
for (int i=0; i < body->collision_poly_size; i++) {
int x = body->collision_shape[i].x + body->x_pos;
int y = body->collision_shape[i].y + body->y_pos;
printf("%d %d,", x, y);
body->collision_poly[i].x = x;
body->collision_poly[i].y = y;
}
printf("\n");
fflush(stdout);
}
// would probably be useful xd
@ -43,14 +53,13 @@ void get_new_physics(Body **phys) { @@ -43,14 +53,13 @@ void get_new_physics(Body **phys) {
add_motor(physics, 0.0, 0.0);
physics->updateCollisionPoly = default_update_collision_poly;
*phys = physics; return;
}
void updatePlayerCollision(Body *physics) {
physics->collision_poly[0].x = physics->x_pos;
physics->collision_poly[0].y = physics->y_pos;
}
/*void updatePlayerCollision(Body *physics) {*/
/*physics->collision_poly[0].x = physics->x_pos;*/
/*physics->collision_poly[0].y = physics->y_pos;*/
/*}*/
player_st get_player(int x, int y) {
/* creates player at given postion and zeroes physics */
@ -65,44 +74,28 @@ player_st get_player(int x, int y) { @@ -65,44 +74,28 @@ player_st get_player(int x, int y) {
player.physics->y_pos = y;
player.physics->glob_friction = 40; // drag coef * area
player.physics->updateCollisionPoly = updatePlayerCollision;
player.physics->updateCollisionPoly = default_update_collision_poly;
player.physics->collision_poly = calloc(1, sizeof(SDL_Point));
player.physics->collision_poly = calloc(4, sizeof(SDL_Point));
player.physics->collision_shape = calloc(4, sizeof(SDL_Point));
set_motor_newtons(player.physics, M_GRAVITY, 0.0, player.physics->obj_mass * 7);
player.physics->collision_poly_size = 4;
SDL_Point *rect = player.physics->collision_shape;
rect[0].x = -5; rect[0].y = -5;
rect[1].x = 5; rect[1].y = -5;
rect[2].x = 5; rect[2].y = 5;
rect[3].x = -5; rect[3].y = 5;
set_motor_newtons(player.physics, M_GRAVITY, 0.0, player.physics->obj_mass * 5);
// walking motor
add_motor(player.physics, 0.0, player.physics->obj_mass * 9.81);
set_motor_max_velocity(player.physics, M_PLAYER_WALK, 6); // has to be > grav
set_motor_max_velocity(player.physics, M_PLAYER_WALK, 5); // has to be > grav
set_motor_max_velocity(player.physics, M_GRAVITY, 5);
return (player);
}
wall_node get_wall_node(int x, int y) {
wall_node wn;
memset(&wn, 0, sizeof(wn));
wn.x = x;
wn.y = y;
return wn;
}
Wall *get_stat_wall(int st_x, int st_y, int en_x, int en_y) {
Wall wall;
memset(&wall, 0, sizeof(wall));
wall.numNodes = 2;
wall.nodes = malloc(sizeof(wall_node) * wall.numNodes);
wall.nodes[0] = get_wall_node(st_x, st_y);
wall.nodes[1] = get_wall_node(en_x, en_y);
Wall *wallwall = malloc(sizeof(wall));
*wallwall = wall;
return wallwall;
}
bool point_point_colcheck(SDL_Point one, SDL_Point two) {
if (one.x == two.x && one.y == two.y) {
return true;
@ -115,6 +108,7 @@ typedef struct { @@ -115,6 +108,7 @@ typedef struct {
Vect two;
} Collision;
bool point_line_colcheck(SDL_Point line[2], SDL_Point point) {
// point is outside the rectangle made by the line
@ -139,18 +133,125 @@ bool point_line_colcheck(SDL_Point line[2], SDL_Point point) { @@ -139,18 +133,125 @@ bool point_line_colcheck(SDL_Point line[2], SDL_Point point) {
return false;
}
double *project_col_poly(Body *shape, Vect V) {
printf("PROJECTION : \n");
double *proj = calloc(shape->collision_poly_size, sizeof(double));
for (int i = 0; i < shape->collision_poly_size; i++) {
Vect point;
point.x = shape->collision_poly[i].x;
point.y = shape->collision_poly[i].y;
printf("point: %f %f mag: %f\n", point.x, point.y, vect_mag(point));
printf("Vectp: %f %f mag: %f\n", V.x, V.y, vect_mag(V));
proj[i] = vect_scalar_projection(point, V);
}
double min, max;
max = -99999999;
min = 99999999;
for (int i = 0; i < shape->collision_poly_size; i++) {
if (proj[i] > max) {
max = proj[i];
}
if (proj[i] < min) {
min = proj[i];
}
}
double *res = calloc(2, sizeof(double));
res[0] = min;
res[1] = max;
return res;
}
Vect get_normal(SDL_Point start, SDL_Point end) {
Vect norm;
double x = (end.x - start.x);
double y = (end.y - start.y);
norm.x = -y;
norm.y = x;
return norm;
}
bool sat_collision_check(Body *one, Body *two) {
int num_axes = one->collision_poly_size + two->collision_poly_size;
Vect *axes = calloc(num_axes, sizeof(Vect));
SDL_Point end;
SDL_Point start = one->collision_poly[0];
for (int i = 1; i < one->collision_poly_size; i++) {
end = one->collision_poly[i];
axes[i-1] = get_normal(start, end);
printf(".%d\n", i-1);
start = end;
}
end = one->collision_poly[0];
axes[one->collision_poly_size - 1] = get_normal(start, end);
printf(".%d\n", one->collision_poly_size - 1);
start = two->collision_poly[0];
for (int i = 1; i < two->collision_poly_size; i++) {
end = two->collision_poly[i];
axes[i - 1 + one->collision_poly_size] = get_normal(start, end);
printf(".%d\n", i-1 + one->collision_poly_size);
start = end;
}
end = two->collision_poly[0];
axes[two->collision_poly_size + one->collision_poly_size - 1] = get_normal(start, end);
printf(".%d\n",two->collision_poly_size + one->collision_poly_size - 1);
// normalise
for (int i = 0; i < num_axes; i++) {
printf("AXIS TO CHECK :(num %d) %f %f\n", i, axes[i].x, axes[i].y);
double len = vect_mag(axes[i]);
axes[i].x = axes[i].x / len;
axes[i].y = axes[i].y / len;
printf("AXIS TO CHECK normed: %f %f\n", axes[i].x, axes[i].y);
}
double *proj_one, *proj_two;
proj_one = proj_two = 0;
for (int i = 0; i < num_axes; i++) {
// project
if (proj_one) {
free(proj_one);
}
if (proj_two) {
free(proj_two);
}
proj_one = project_col_poly(one, axes[i]);
proj_two = project_col_poly(two, axes[i]);
printf("Testing on : %f %f\n", axes[i].x, axes[i].y);
if (!(proj_one[1] > proj_two[1] && proj_one[0] < proj_two[0])
&& !(proj_one[1] < proj_two[1] && proj_one[0] > proj_two[0])) {
printf("not overlapping\n");
free(axes);
return false;
} else {
printf("overlapping\n");
}
}
free(axes);
free(proj_one);
free(proj_two);
return true;
}
bool route_collision(Body *one, Body *two) {
int onesize = one->collison_poly_size;
int twosize = two->collison_poly_size;
int onesize = one->collision_poly_size;
int twosize = two->collision_poly_size;
// point-point
if (one->collison_poly_size == 1 && two->collison_poly_size == 1) {
if (one->collision_poly_size == 1 && two->collision_poly_size == 1) {
if (point_point_colcheck(one->collision_poly[0], two->collision_poly[0])) {
return true;
}
}
// point-line
if ((onesize == 1 || twosize == 1) && (onesize == 2 || twosize == 2)) {
SDL_Point line[2];
@ -166,7 +267,6 @@ bool route_collision(Body *one, Body *two) { @@ -166,7 +267,6 @@ bool route_collision(Body *one, Body *two) {
}
return point_line_colcheck(line, point);
}
// line-line
@ -186,7 +286,8 @@ bool route_collision(Body *one, Body *two) { @@ -186,7 +286,8 @@ bool route_collision(Body *one, Body *two) {
// poly-poly
if ((onesize > 2 && twosize > 2)) {
return false;
return sat_collision_check(one, two);
}
}
@ -200,16 +301,21 @@ Wall *get_long_wall(int numNodes, int *nodes) { @@ -200,16 +301,21 @@ Wall *get_long_wall(int numNodes, int *nodes) {
memset(&wall, 0, sizeof(wall));
wall.numNodes = numNodes;
wall.nodes = malloc(sizeof(wall_node) * numNodes);
wall.physics = calloc(1, sizeof(Body));
wall.nodes = malloc(sizeof(SDL_Point) * numNodes);
get_new_physics(&wall.physics);
wall.physics->collision_poly = calloc(numNodes, sizeof(SDL_Point));
wall.physics->collision_shape = calloc(numNodes, sizeof(SDL_Point));
wall.physics->collision_poly_size = numNodes;
// collisions
//SDL_Point *collision_poly;
for (int i = 0; i < numNodes; i++) {
wall.nodes[i] = get_wall_node(nodes[2*i], nodes[2*i+1]);
wall.nodes[i].x = nodes[2*i];
wall.nodes[i].y = nodes[2*i+1];
wall.physics->collision_poly[i].x = nodes[2*i];
wall.physics->collision_poly[i].y = nodes[2*i+1];
wall.physics->collision_shape[i].x = nodes[2*i];
wall.physics->collision_shape[i].y = nodes[2*i+1];
}
Wall *wallwall = malloc(sizeof(wall));
@ -289,6 +395,9 @@ void advance_thing(Body * thing) { @@ -289,6 +395,9 @@ void advance_thing(Body * thing) {
// motors
for (int i = 0; i < thing->num_motors; i++) {
if (thing->motors[i].TTL <= 0) {
continue;
}
Vect F;
Vect V;
@ -298,20 +407,23 @@ void advance_thing(Body * thing) { @@ -298,20 +407,23 @@ void advance_thing(Body * thing) {
V.y = thing->y_vel;
Vect vel_in_dir = project_vect(V, F);
if (thing->motors[i].TTL <= 0) {
continue;
}
double dirF = atan2(F.y, F.x);
double dirV = atan2(V.y, V.x);
if (thing->motors[i].TTL != INFINITY) {
thing->motors[i].TTL--;
}
if (thing->motors[i].max_velocity > vect_mag(vel_in_dir)) {
double diff = dirV > dirF ? dirV - dirF: dirF - dirV;
if (thing->motors[i].max_velocity > vect_mag(vel_in_dir)
|| diff >= M_PI) {
double acc_x = thing->motors[i].x / thing->obj_mass;
double acc_y = thing->motors[i].y / thing->obj_mass;
accel_thing(thing, acc_x, acc_y);
}
// printf("\n diff angle: %f pi: %f \n", dirV - dirF, M_PI);
// printf("Vel: %f, Force: %f\n\n", dirV, dirF);
}
// accelerate based on accel
@ -364,6 +476,8 @@ void advance_thing(Body * thing) { @@ -364,6 +476,8 @@ void advance_thing(Body * thing) {
if (thing->x_pos < 0) {
thing->x_pos = width;
}
thing->updateCollisionPoly(thing);
}
// basic collision handler
@ -372,7 +486,6 @@ void handle_collisions(void) { @@ -372,7 +486,6 @@ void handle_collisions(void) {
if (world[k].kind == STATIC_WALL_W) {
if (check_collision(world[k].wall->physics,
player.physics)) {
player.physics->x_vel = 0;
player.physics->y_vel = 0;
}
@ -391,7 +504,7 @@ void advance_things(void) { @@ -391,7 +504,7 @@ void advance_things(void) {
break;
case STATIC_WALL_W:
logwrite(INFO, "ADVANCE WALL\n");
// advance_thing(world[i].wall->physics);
advance_thing(world[i].wall->physics);
break;
}
}

12
game.h

@ -50,7 +50,8 @@ typedef struct BodyStruct{ @@ -50,7 +50,8 @@ typedef struct BodyStruct{
// collisions
SDL_Point *collision_poly;
int collison_poly_size;
SDL_Point *collision_shape;
int collision_poly_size;
void (*updateCollisionPoly)(struct BodyStruct *);
// properties
@ -71,17 +72,12 @@ typedef struct { @@ -71,17 +72,12 @@ typedef struct {
bool has_physics;
Body *physics;
int max_walking_speed;
int colliding;
} player_st;
typedef struct {
int x;
int y;
//void setup(struct stat_wall_st *self);
} wall_node;
typedef struct {
int numNodes;
wall_node *nodes;
SDL_Point *nodes;
Body *physics;
} Wall;

9
vect.c

@ -16,6 +16,7 @@ Vect vect_scalar(Vect V, double s) { @@ -16,6 +16,7 @@ Vect vect_scalar(Vect V, double s) {
return ret;
}
Vect vect_add(Vect v1, Vect v2) {
Vect res;
res.x = v1.x + v2.x;
@ -23,6 +24,7 @@ Vect vect_add(Vect v1, Vect v2) { @@ -23,6 +24,7 @@ Vect vect_add(Vect v1, Vect v2) {
return res;
}
// project one onto two
Vect project_vect(Vect one, Vect two) {
// $$ a \cdot \frac {|b|} {b} $$
Vect unittwo;
@ -36,6 +38,13 @@ Vect project_vect(Vect one, Vect two) { @@ -36,6 +38,13 @@ Vect project_vect(Vect one, Vect two) {
return proj;
}
// project V onto P
double vect_scalar_projection(Vect V, Vect P) {
double angle = vect_dir(V) - vect_dir(P);
return cos(angle) * vect_mag(V);
}
double vect_dir(Vect V) {
return atan2(V.y, V.x);
}

3
vect.h

@ -27,4 +27,7 @@ Vect vect_add(Vect v1, Vect v2); @@ -27,4 +27,7 @@ Vect vect_add(Vect v1, Vect v2);
/* Return the projection of vector one onto vector two */
Vect project_vect(Vect one, Vect two);
/* Return the scalar projection of V onto P */
double vect_scalar_projection(Vect V, Vect P);
#endif

Loading…
Cancel
Save