[LWJGL] Vector-based player collisions (against polygonal geometry)

I’ve been trying to come up w/ decent player collisions for my game, but I feel like I could be doing them in a much better way. I want to strike up a conversation with other people who have written decent player collisions with triangles.

Here’s what I’ve done for my engine (Keep in mind I wrote my own triangle raytracing library, so my methodology may seem a little unconventional):

Floor collision:

float distToGround = getDistanceToGround(z, (-vz * this.getDeltaMultiplier()) + 6);
if ((distToGround <= 1) && vz <= 0) {
	z = z-distToGround;
}

Wall collision:

float vx = velocity.getX();
float vy = velocity.getY();
float rad = width;
float dis = 0;
if (CollisionHelper.collision_check(map, 0, 0, 0, collisionMask, x + vx, y + vy, z + 6)) {
    for(float k=6; k<=16; k+=1) {
        for(int i=0; i<360; i+=30){
            if (CollisionHelper.collision_line_3d(x + vx, y + vy, z+k, (x + vx) + CollisionHelper.lengthdir_x(rad,i), (y + vy) + CollisionHelper.lengthdir_y(rad,i), z+k, map)>0) {
                for(float j=rad; j>=0; j-=.1){
                    if (CollisionHelper.collision_line_3d(x + vx, y + vy,z+k,(x + vx) + CollisionHelper.lengthdir_x(j,i), (y + vy) + CollisionHelper.lengthdir_y(j,i), z+k, map)==0) {
                        dis = j;
                        break;
                    }
                }
        
                x=x+CollisionHelper.lengthdir_x(rad-dis,i+180);
                y=y+CollisionHelper.lengthdir_y(rad-dis,i+180);
            }
        }
    }
}

There’s nothing wrong with my collisions, however I fear as though what I use to detect walls is not efficient at all. The way I do it, is I cast rays out every 30 degrees, and if a triangle is found, it casts smaller and smaller rays until it finds free space (moving the player to this free space). Sure this method works, but it is quite costly to the CPU. Also, with my method, it doesn’t “change” the players velocity, if just shifts their location; visually this is fine, but technically, if you are moving fast enough you will push through the wall.

Does anyone have any good collision methods they want to share?

I don’t know why polygon collision isn’t enough for you, but I don’t really know how to make collision in triangles either.

The only way I know of to stop the problem of too much speed skipping collision is to move objects several times at a small distance. So if you want to move 1 unit (1 pixel say this time) you would just check for collision, and if there is no collision you would move. If you want to move 5 units, you need to check for collision 5 times. Do for loop and and at each loop check for collision. If there is no collision, move 1 pixel. If there is collision, break the loop.

Polygon collision IS enough for me. I just can’t seem to create a good system for determining how the player will act upon colliding with polygons. Articles I find online just cover the mathematics behind determining whether or not a collision happened between 2 triangles. No one seems to talk about conventional ways of having it affect something like a player object.

I have already written this few times throughout few topics. If you have point p, box b, speed s, then something like this:

if(!b.intersects(p + speed)) {
			p += speed;
		}

It depends on how realistic you would like your physics to be. I suppose the simplest is as @trollwarrior1 said above. More complex would be to move the object, then work out the minimum penetration distance and “push” the object out. Algorithms like GJK or SAT work well into this approach. For really realistic stuff, then you need to know the normal reaction of the contact and resolve the collision for momentum. It gets fairly complex at this point.

I’m trying to come up with a new method which seems like it could work:

float[] lastTriangleData = CollisionHelper.getLastTriangleData();
Vector normal = new Vector(lastTriangleData[9], lastTriangleData[10], lastTriangleData[11]);
Vector offset = velocity.clone().setZ(0);
Vector result = normal.multiply(offset.dot(normal) / normal.dot(normal));
Vector vfinal = result.add(velocity).getNormal();

I think that sometimes a few comments to say what code is doing can be helpful. I know that everyone on JGO is a genius, but sometimes even a genius likes to be told the answer.

If I had to guess, you are going with my last suggestion above of using the contact normal (but ignoring momentum ie with static geometry) to work out the new direction of the player. If so, it looks good - exactly how I would do it - but I’m not sure what “offset” is (well it’s velocity with z component set to 0 obviously).

If you’re just posting to give us some feedback then glad I could help (if I did help). If you’re looking for a critique then you’ll have to explain what “offset” has to do with anything. In fact I wouldn’t mind knowing anyway - just out of curiosity, since I’m not a cat.

I’m trying to find the proper vector to set the players velocity so that it increases the smoothness of the camera when colliding against walls.

I’ve been able to find these vectors:

float[] lastTriangleData = GMP3DC.getLastTriangleData();
Vector normal = new Vector(lastTriangleData[9], lastTriangleData[10], lastTriangleData[11]).setZ(0);
Vector offset = velocity.clone().setZ(0);

//Calculate parallel vector (to normal vector)
Vector parallel = normal.clone().multiply(offset.dot(normal) * -1).add(offset);

//Calculate perpendicular vector (to normal vector)
Vector result = normal.clone().multiply(offset.dot(normal) / normal.dot(normal));

the parallel vector doesn’t have the correct magnitude, and the perpendicular vector is only useful for shifting the location (not changing the velocity).

I’ve almost perfected my collision code :slight_smile:

if (CollisionHelper.collision_check(map, 0, 0, 0, collisionMask, x + (velocity.getX() * this.getDeltaMultiplier()), y + (velocity.getY() * this.getDeltaMultiplier()), z + 6)) {
    //If there WILL be a collision next step
    for(float k=6; k<=16; k+=1) {
    for(int i=0; i<360; i+=45){
        //check perimeter and height of player for triangle collisions
        if (CollisionHelper.collision_line_3d(x + (velocity.getX() * this.getDeltaMultiplier()), y + (velocity.getY() * this.getDeltaMultiplier()), z+k, (x + (velocity.getX() * this.getDeltaMultiplier())) + CollisionHelper.lengthdir_x(rad,i), (y + (velocity.getY() * this.getDeltaMultiplier())) + CollisionHelper.lengthdir_y(rad,i), z+k, map)>0) {
			//Calculate triangle vectors
			float[] lastTriangleData = CollisionHelper.getLastTriangleData();
			Vector normal = new Vector(lastTriangleData[9], lastTriangleData[10], lastTriangleData[11]);
			Vector offset = velocity.clone().setZ(0);
			
			//Calculate perpendicular vector (to normal vector)
			Vector result = normal.clone().multiply(offset.dot(normal) / normal.dot(normal));
			x = x - (result.getX()) * 0.125f;
			y = y - (result.getY()) * 0.125f;
			
			//Calculate parallel vector (to normal vector)
			Vector parallel = normal.clone().multiply(offset.dot(normal) * -1).add(offset);

			//Create a new potential velocity
			Vector newVelocity = parallel.setZ(velocity.getZ());
			
			//Check if your new velocity is possible
			if (!CollisionHelper.collision_check(map, 0, 0, 0, collisionMask, x + (newVelocity.getX() * this.getDeltaMultiplier()), y + (newVelocity.getY() * this.getDeltaMultiplier()), z + 6 + (newVelocity.getZ() * this.getDeltaMultiplier()))) {
				velocity = newVelocity;
			}
        }
    }
    }
}

I do need some help with my perpendicular vector. Most of the time it is correct, but every once and awhile it becomes flipped, and I get sucked through the wall.

I have made it as smooth as I think I can, so if anyone is interested in seeing it, here’s my wall collision code:
http://pastebin.com/cXFYhpnm

Thanks, quew8 :slight_smile:

You did it all yourself.