Am I on the floor please? (FPS Games)

Started by
11 comments, last by ricekrispyw 18 years, 7 months ago
Does anyone have any good solutions for detecting whether the player is on the floor in a first person shooter engine? It seems to be a fairly common problem amongst FPS engines and was wondering if there was some cut 'n dry solution. As an indie developer, we're surprisingly NOT using a terrain engine...so I'm sure standard issue solutions should work. Any suggestions? Will rate for suggestions. ^_^
Advertisement
Just cast a line straight down from the players positions and see where it hits the world... assuming you've got your collision detection code running, if not, well, it might be time to start working on that... :)
// Object-to-object bounding-box collision detector:
short int Sprite_Collide(sprite_ptr object1, sprite_ptr object2) {

int left1, left2;
int right1, right2;
int top1, top2;
int bottom1, bottom2;

left1 = object1->x;
left2 = object2->x;
right1 = object1->x + object1->width;
right2 = object2->x + object2->width;
top1 = object1->y;
top2 = object2->y;
bottom1 = object1->y + object1->height;
bottom2 = object2->y + object2->height;

if (bottom1 < top2) return(0);
if (top1 > bottom2) return(0);

if (right1 < left2) return(0);
if (left1 > right2) return(0);

return(1);

};
object->width = <ACTUAL BITMAP WIDTH>;
object->height = <ACTUAL BITMAP HEIGHT>;

object->col_width = object->width * 0.80;
object->col_height = object->height * 0.80;

object->col_x_offset = (object->width - object->col_width) / 2;
object->col_y_offset = (object->height - object->col_height) / 2;

// Object-to-object, reduced bounding-box collision detector:
short int Sprite_Collide(sprite_ptr object1, sprite_ptr object2) {

int left1, left2;
int right1, right2;
int top1, top2;
int bottom1, bottom2;

left1 = object1->x + object1->col_x_offset;
left2 = object2->x + object2->col_x_offset;
right1 = left1 + object1->col_width;
right2 = left2 + object2->col_width;
top1 = object1->y + object1->col_y_offset;
top2 = object2->y + object1->col_y_offset;
bottom1 = top1 + object1->col_height;
bottom2 = top2 + object2->col_height;

if (bottom1 < top2) return(0);
if (top1 > bottom2) return(0);

if (right1 < left2) return(0);
if (left1 > right2) return(0);

return(1);

};


// Object-to-Point, pixel-level collision detector:
short int Sprite_Collide(sprite_ptr object, int x, int y) {

int x_offset, y_offset;
int left, right, top, bottom;


left = object->x;
right = left + object->width;
top = object->y;
bottom = top + object->height;

if (x < left) return(0);
if (x > right) return(0);

if (y < top) return(0);
if (y > bottom) return(0);

x_offset = abs(x - object->x);
y_offset = abs((y - object->y) * object->width);

if (*(object->frames[object->curr_frame] +
y_offset + x_offset) == 0) return(0);

return(1);

};

// Object-to-Point, pixel-level collision detector:
short int Sprite_Collide(sprite_ptr object, int x, int y) {

int x_offset, y_offset;
int left, right, top, bottom;


left = object->x;
right = left + object->width;
top = object->y;
bottom = top + object->height;

if (x < left) return(0);
if (x > right) return(0);

if (y < top) return(0);
if (y > bottom) return(0);

x_offset = abs(x - object->x);
y_offset = abs((y - object->y) * object->width);

if (*(object->frames[object->curr_frame] +
y_offset + x_offset) == 0) return(0);

return(1);

};
// Object-to-Point, pixel-level collision detector:
short int Sprite_Collide(sprite_ptr object, int x, int y) {

int x_offset, y_offset;
int left, right, top, bottom;


left = object->x;
right = left + object->width;
top = object->y;
bottom = top + object->height;

if (x < left) return(0);
if (x > right) return(0);

if (y < top) return(0);
if (y > bottom) return(0);

x_offset = abs(x - object->x);
y_offset = abs((y - object->y) * object->width);

if (*(object->frames[object->curr_frame] +
y_offset + x_offset) == 0) return(0);

return(1);

};

Matt : mattb0001@hotmail.comClick me please
// Full object-to-object pixel-level collision detector:
short int Sprite_Collide(sprite_ptr object1, sprite_ptr object2) {

int left1, left2, over_left;
int right1, right2, over_right;
int top1, top2, over_top;
int bottom1, bottom2, over_bottom;
int over_width, over_height;
int i, j;
unsigned char *pixel1, *pixel2;

left1 = object1->x;
left2 = object2->x;
right1 = object1->x + object1->width;
right2 = object2->x + object2->width;
top1 = object1->y;
top2 = object2->y;
bottom1 = object1->y + object1->height;
bottom2 = object2->y + object2->height;


// Trivial rejections:
if (bottom1 < top2) return(0);
if (top1 > bottom2) return(0);

if (right1 < left2) return(0);
if (left1 > right2) return(0);


// Ok, compute the rectangle of overlap:
if (bottom1 > bottom2) over_bottom = bottom2;
else over_bottom = bottom1;

if (top1 < top2) over_top = top2;
else over_top = top1;

if (right1 > right2) over_right = right2;
else over_right = right1;

if (left1 < left2) over_left = left2;
else over_left = left1;


// Now compute starting offsets into both objects' bitmaps:
i = ((over_top - object1\1->y) * object1->width) + over_left;
pixel1 = object1->frames[object1->curr_frame] + i;

j = ((over_top - object2->y) * object2->width) + over_left;
pixel2 = object2->frames[object2->curr_frame] + j;


// Now start scanning the whole rectangle of overlap,
// checking the corresponding pixel of each object's
// bitmap to see if they're both non-zero:

for (i=0; i < over_height; I++) {
for (j=0; j < over_width; j++) {
if (*pixel1 > 0) && (*pixel2 > 0) return(1);
pixel1++;
pixel2++;
}
pixel1 += (object1->width - over_width);
pixel2 += (object2->width - over_width);
}


// Worst case! We scanned through the whole darn rectangle of overlap
// and couldn't find a single colliding pixel!

return(0);

};

Matt : mattb0001@hotmail.comClick me please
I am using the same system as AP(with AABB instead of line though), works like a charm :)
Isn't that kind of a hacky solution for this? We're using newton for physics so collision code is all fine and dandy. Its just hard to keep the player on the floor and also hard to detect whether he can jump or not.
Didn't Quake have a flag "FL_ONGROUND" that was set when an objects bounding box collided with the ground, and un-set when it stopped colliding?

http://wiki.quakesrc.org/index.php/FL_ONGROUND
If you want to do it as proper physics (sort of) then each foot hitting the ground could exert an upwards force, so you progress in a series of small hops. It would rock if you could get it working, but I imagine it's a horrific thing to implement!
But why not assume player is on the ground unless the ground height drops suddenly below them as they move, then let them drop until their collision box re-connects with the ground?
usually, it's just a matter of finding out if you are colliding zith a polygon with a roughly vertical normal (say, normal.y > 0.8f).

Else, all sorts of algos can be used.

Everything is better with Metal.

I'm using the TrueAxis physics engine in my project, but I bet the same ideas apply. For my FPS player, I loop through all of the dynamic object's collisions from the last frame, discarding any that I don't need using "continue;". For each collision, then, I check if the normal's angle is within 0.6f (radians I think), of vertical. Then I check to make sure that the collision point, is near to where the feet should be. I used an arbitrary value for this that I trialed and errored to find out, with a little epsilon of 1/32. I have a boolean variable I keep track of in all "auto" classes (short for autonomous) called "grounded". If any of the collisions meets both criteria, then the "auto" object is grounded, and is allowed to exert force to walk and to jump. Otherwise if no collision was found that meets the criteria, grounded is false, and the player can only exert 1/10 of the force for moving laterally (no jumping), because who likes an FPS where you can't bunny hop, or change direction mid-air?

This topic is closed to new replies.

Advertisement