0
\$\begingroup\$

I am having problem with the most basic physic response when the player collide with static wall, floor or roof. I have a simple 3D maze, true means solid while false means air:

bool bMap[100][100][100];

The player is a sphere. I have keys for moving x++, x--, y++, y-- and diagonal at speed 0.1f (0.1 * ftime). The player can also jump. And there is gravity pulling the player down. Relative movement is saved in: relx, rely and relz.

One solid cube on the map is exactly 1.0f width, height and depth. The problem I have is to adjust the player position when colliding with solids, I don't want it to bounce or anything like that, just stop. But if moving diagonal left/up and hitting solid up, the player should continue moving left, sliding along the wall.

Before moving the player I save the old player position:

    oxpos = xpos;
    oypos = ypos;
    ozpos = zpos;

    vec3 direction;
    direction = vec3(relx, rely, relz);

    xpos += direction.x*ftime;
    ypos += direction.y*ftime;
    zpos += direction.z*ftime;

    gx = floor(xpos+0.25);
    gy = floor(ypos+0.25);
    gz = floor(zpos+0.25);
    if (bMap[gx][gy][gz] == true) {

        vec3 normal = vec3(0.0, 0.0, 1.0); // <- Problem.
        vec3 invNormal = vec3(-normal.x, -normal.y, -normal.z) * length(direction * normal);
        vec3 wallDir = direction - invNormal;
        xpos = oxpos + wallDir.x;
        ypos = oypos + wallDir.y;
        zpos = ozpos + wallDir.z;
    }

The problem with my version is that I do not know how to chose the correct normal for the cube side. I only have the bool array to look at, nothing else. One theory I have is to use old values of gx, gy and gz, but I do not know have to use them to calculate the correct cube side normal.

\$\endgroup\$
  • 3
    \$\begingroup\$ You might want to cut the noise out of this question and just ask your base question. I imagine you could get rid of most of the question and you'd be more likely to get a response. Also, you can calculate the normal you need by comparing the position you're colliding with to the player position before collision. \$\endgroup\$ – MichaelHouse Apr 13 '14 at 15:38
  • \$\begingroup\$ @Byte56 Thanks. I am not sure what you mean comparing positions, like: old_gx, old_gy and old_gz? That will not work since old_gz will almost always be different from gz because of gravity. When player moves in xy-plane every time moving across a cube to another I have old_gx diff from gx and old_gz diff from gz. If I calc normal from that the player will bounce diagonally backwards, not continuing moving forward in XY-plane. \$\endgroup\$ – GlamCasvaluir Apr 13 '14 at 16:01
2
\$\begingroup\$

You need to detect which face you have collided with, penetration depth and then decide which way to resolve out. Essentially you don't have enough information to do what you need.

To do this you represent the cube faces as planes. That is a normal and dot product. You then calculate distance from the sphere position to the planes and choose the face with the smallest depth to resolve out of.

So if you have a plane pointing directly up it's normal would be vec3(0.0,1.0,0.0). Depending on where the plane is its offset would be the planes height so for a cube on the floor, 1m high the offset would be 1. The cube face on the floor would be vec3(0.0,-1.0,0.0) and offset zero.

You then calculate penetration depth of your sphere. This is simply the dot product between the normal & sphere position. So if your sphere is at (3.0,6.9,1.4) then the dot product with the top plane is 6.9. Subtract the offset of 1 and you get a distance of 5.9. So if the sphere has a radius > 5.9 then you have an intersection. Penetration depth is radius - distance to resolve out. Collision normal is the normal of the face Vec3(0.0,1.0,0.0).

Now that you have the resolution depth & normal you can r solve the sphere out as well as adjust velocity to remove the velocity towards the cube face. This is something like NewVel = OldVel - facenormal* Dot(facenormal,OldVel)

You'll have to check the maths because I'm writing this on iPad.

That's how you, basically, resolve sphere and plane collisions. However this is a rabbit hole you are going down.

Far smarter is to use a Physics library to do this. You'll get better results and it'll save you a ton of time.

\$\endgroup\$
0
\$\begingroup\$

Forgive me if I didn't understand your question (just comment below and I can modify my answer) but it sounds like what you need to implement is something like a "Slide along wall" if you detect that the player is going to hit a wall.

Usually I would implement this as a swept-sphere against plane test, or a capsule for plane test. I'm sure you can find source code for this in Ericson's Real-Time Collision Detection book, where the source is free to download online.

The idea is to compute the closest point on a line-segment to each plane of a cube. This line segment is the center of one sphere to the center of the swept sphere. Then you compare the computed distance from segment to plane with the radius of the sphere itself.

If a collision is detected with a plane you can move your sphere to the time of impact, and then take the leftover translation and project it onto the collision plane. This would require some sort of "slide along wall" function. The slide along wall function can use projection or the outer product to perform a projection, whichever is your preference. Given a plane with the normal u, you can project any vector v onto the plane corresponding to u like so:

(I - (u * u))v

Where that * symbol is the outer product. The outer product produces a matrix. I believe the inner product form would look like:

v - u(u ∙ v)

Source: Stan Melax - Math for Game Programmers - GDC 2013

\$\endgroup\$
0
\$\begingroup\$

You dont need complex math for this simple thing. To get the slide collision response do this: move along x axis, if collision=true adjust x position (stop the x movement). Pick this new positon add y movement and test collision. If true adjust y position. Pick this new position and add the z movement adjust z movement in case of collision. The key to slide is move one axis at a time, adjusting positions.

Sorry my poor english...

\$\endgroup\$
  • \$\begingroup\$ that's right. but on a pure code maintenance point of view, one should apply the "ifless principle", or like the zen of python says "Special cases aren't special enough to break the rules.". Which means, if you can eliminate 6 ifs (cubic directions) and replace it with one math formula using a dot product to make a projection along the free direction, you have won a Zen award ! \$\endgroup\$ – v.oddou Sep 11 '14 at 6:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.