Skip to content

Commit

Permalink
Arbitrary angle collision resolution for walls fully working, but it …
Browse files Browse the repository at this point in the history
…looks a bit messy
  • Loading branch information
Ben Green committed Jul 16, 2009
1 parent b09a9dc commit 78c9306
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 19 deletions.
4 changes: 4 additions & 0 deletions character.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Character::Character() {
xVel = 0, yVel = 0;
speed = 5;
layer = 0;
before.x = 0;
before.y = 0;
}

Player::Player() {
Expand Down Expand Up @@ -38,6 +40,8 @@ void Player::handle_input() {
}

void Player::handle_move() {
before.x = position.x;
before.y = position.y;
position.x += speed * xVel;
position.y += speed * yVel;
}
Expand Down
6 changes: 5 additions & 1 deletion character.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ class Character: public Object {
public:
int speed;
float xVel, yVel;
struct coord before;

Character();

int hit_where(Object* other);

virtual void handle_move() {
return;
}

char* pos_str(char* buffer) {
sprintf(buffer, "%3d, %3d @ %2f, %2f\n", position.x, position.y, xVel, yVel);
sprintf(buffer, "%3f, %3f @ %2f, %2f\n", position.x, position.y, xVel, yVel);
return buffer;
}
};
Expand Down
3 changes: 2 additions & 1 deletion object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

void Object::handle_show(SDL_Surface* scene[]) {
SDL_Rect tmp;
tmp = position;
tmp.x = position.x;
tmp.y = position.y;
SDL_BlitSurface(sprite, NULL, scene[layer], &tmp);
}

Expand Down
8 changes: 7 additions & 1 deletion object.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#include <SDL/SDL.h>
#include <vector>


struct coord {
float x;
float y;
};

class Object {
public:
int layer;
SDL_Rect position;
struct coord position;
std::vector<SDL_Rect> hitboxes;

Object();
Expand Down
131 changes: 115 additions & 16 deletions static.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#include "static.h"
#include "character.h"
#include "math.h"

#define HIT_TOP (0b0001)
#define HIT_BOTTOM (0b0010)
#define HIT_LEFT (0b0100)
#define HIT_RIGHT (0b1000)

Wall::Wall(SDL_Rect dim) {
position.x = dim.x;
Expand All @@ -12,56 +18,149 @@ Wall::Wall(SDL_Rect dim) {
}

void Wall::collide(Object* other) {
// TODO: each movement vector is assigned the same values, fix that
// TODO: this should be more based on hitboxes than item dimensions
// TODO: this is all ugly as fuck
struct mv_vector {
float x1, y1;
float x2, y2;
// current position
float x, y;
// distance to get here
float dx, dy;
bool top, bottom, left, right;
} path[4];
// Make sure the object is a movable character (it really should be)
Character* o = dynamic_cast<Character*>(other);
if(o != NULL) {
// detect the simple and most common perpendicular collisions
// correct the simplest and most common perpendicular collisions
// vertical:
if(o->xVel == 0) {
// from the top:
if(o->yVel > 0) {
o->position.y -= (o->position.y + o->hitboxes.front().h) - position.y;
o->position.y = position.y - o->hitboxes.front().h;
// from the bottom:
} else {
o->position.y += (position.y + hitboxes.front().h) - other->position.y;
o->position.y = position.y + hitboxes.front().h;
}
return;
}
// horizontal:
if (o->yVel == 0) {
// from the left:
if(o->xVel > 0) {
o->position.x -= (o->position.x + o->hitboxes.front().w) - position.x;
o->position.x = position.x - o->hitboxes.front().w;
// from the right:
} else {
o->position.x += (position.x + hitboxes.front().w) - other->position.x;
o->position.x = position.x + hitboxes.front().w;
}
return;
}

// calculate the lines represented by the movement
// of each vertex of the hitbox
for(int i=0; i<3; i++) {
path[i].x2 = o->position.x;
path[i].y2 = o->position.y;
path[i].x1 = o->position.x - o->speed * o->xVel;
path[i].y1 = o->position.y - o->speed * o->yVel;
}
//path[0] = {o->position.x, o->position.y, o->speed * o->xVel, o->speed * o->yVel};
path[0].x = o->position.x;
path[0].y = o->position.y;
path[0].dx = o->speed * o->xVel;
path[0].dy = o->speed * o->yVel;
path[0].top = true;
path[0].left = true;
path[1] = path[0];
path[1].x += o->hitboxes.front().w;
path[1].left = false;
path[2] = path[1];
path[2].y += o->hitboxes.front().h;
path[2].top = false;
path[3] = path[2];
path[3].x -= o->hitboxes.front().w;
path[3].left = true;

// check which movement vectors intersect with the hitbox and where
for(int i=0; i<3; i++) {
mv_vector hit_vector;
float max_dist = 0;
int hit_where = NULL;
for(int i=0; i<4; i++) {
//printf("%d:\nx=%03f;y=%03f;dx=%03f;dy=%03f\n", i, path[i].x, path[i].y, path[i].dx, path[i].dy);
// we need to define the upper and lower bound for the
// intersection point, so we know whether it is on the
// mv_vector or not
float upper_bound, lower_bound;
if(path[i].dy > 0) {
upper_bound = path[i].y;
lower_bound = path[i].y - path[i].dy;
} else {
upper_bound = path[i].y - path[i].dy;
lower_bound = path[i].y;
}

// general case:
// derive b (y = mx + b) using a line and a point
float m = path[i].dy/path[i].dx;
float b = path[i].y - m * path[i].x;
//printf("m=%3f;b=%3f\n", m, b);
// determine where this line intersects
// on the left?
float x = position.x;
float y = m * x + b;
if((lower_bound <= y) && (y <= upper_bound) && !path[i].left) {
// hit on the left
//printf("hit left: x=%3.1f;y=%3.1f\n", x, y); fflush(stdout);
float dist = sqrt(pow(x - path[i].x, 2) + pow(y - path[i].y, 2));
if(dist > max_dist) {
max_dist = dist;
hit_vector = path[i];
hit_where = HIT_LEFT;
}
}
// on the right?
x = (position.x + hitboxes.front().w);
y = m * x + b;
if((lower_bound <= y) && (y <= upper_bound) && path[i].left) {
// hit on the right
//printf("hit right: x=%3.1f;y=%3.1f\n", x, y); fflush(stdout);
float dist = sqrt(pow(x - path[i].x, 2) + pow(y - path[i].y, 2));
if(dist > max_dist) {
max_dist = dist;
hit_vector = path[i];
hit_where = HIT_RIGHT;
}
}
// on the top?
y = position.y;
x = (y - b) / m;
if((lower_bound <= y) && (y <= upper_bound) && !path[i].top) {
// hit on the top
//printf("hit top: x=%3.1f;y=%3.1f\n", x, y); fflush(stdout);
float dist = sqrt(pow(x - path[i].x, 2) + pow(y - path[i].y, 2));
if(dist > max_dist) {
max_dist = dist;
hit_vector = path[i];
hit_where = HIT_TOP;
}
}
// on the bottom?
y = (position.y + hitboxes.front().h);
x = (y - b) / m;
if((lower_bound <= y) && (y <= upper_bound) && path[i].top) {
// hit on the bottom
//printf("hit bottom: x=%3.1f;y=%3.1f\n", x, y); fflush(stdout);
float dist = sqrt(pow(x - path[i].x, 2) + pow(y - path[i].y, 2));
if(dist > max_dist) {
max_dist = dist;
hit_vector = path[i];
hit_where = HIT_BOTTOM;
}
}
}
//printf("diag: 0x%X\n", hit_where); fflush(stdout);
float mag = max_dist / sqrt(pow(hit_vector.dx, 2) + pow(hit_vector.dy, 2));
if(hit_where == HIT_TOP || hit_where == HIT_BOTTOM) {
o->position.y -= mag * hit_vector.dy;
} else if(hit_where == HIT_LEFT || hit_where == HIT_RIGHT) {
o->position.x -= mag * hit_vector.dx;
}

} else {
fprintf(stderr, "Error: somehow two immovable objects collided");
}

fflush(stdout);
return;
}

0 comments on commit 78c9306

Please sign in to comment.