LWJGL - Collision problem.

Hello, I got a bit of a problem here.
I made simple code for collision detection.

When I start the game, I fly to a block and I get stuck in the block, No errors, I just can’t move in any direction.

The colliion detection happens In the block, I can’t seem to fix it. (Im new to AABB)

Code:


    if((keyUp) && (keyRight) && (!keyLeft) && (!keyDown)){
    	if(Game.world.getBlock((byte)this.x - 1, (byte)this.y + 1, (byte)this.z) == 0){
    		moveLookDir(speed * delta * 0.003F + 2, 0.0F - 2, -speed * delta * 0.003F - 2);
    	}
    }
    
    if((keyUp) && (keyLeft) && (!keyRight) && (!keyDown)){
    	if(Game.world.getBlock((byte)this.x - 1, (byte)this.y - 1, (byte)this.z) == 0){
    		moveLookDir(-speed * delta * 0.003F + 2, 0.0F + 2, -speed * delta * 0.003F - 2);
    	}
    }
    
    if ((keyUp) && (!keyLeft) && (!keyRight) && (!keyDown)) {
    	if(Game.world.getBlock((byte)this.x - 1, (byte)this.y, (byte)this.z) == 0){
    		moveLookDir(0.0F + 2, 0.0F, -speed * delta * 0.003F - 2);
    	}
    }
    
    if ((keyDown) && (keyLeft) && (!keyRight) && (!keyUp)) {
    	if(Game.world.getBlock((byte)this.x + 1, (byte)this.y - 1, (byte)this.z) == 0){
    		moveLookDir(-speed * delta * 0.003F - 2, 0.0F + 2, speed * delta * 0.003F - 2);
    	}
    }
    
    if ((keyDown) && (keyRight) && (!keyLeft) && (!keyUp)) {
    	if(Game.world.getBlock((byte)this.x + 1, (byte)this.y + 1, (byte)this.z) == 0){
    		moveLookDir(speed * delta * 0.003F - 2, 0.0F - 2, speed * delta * 0.003F - 2);
    	}
    }  
    
    if ((keyDown) && (!keyUp) && (!keyLeft) && (!keyRight)) {
    	if(Game.world.getBlock((byte)this.x + 1, (byte)this.y, (byte)this.z) == 0){
    		moveLookDir(0.0F - 2, 0.0F, speed * delta * 0.003F - 2);
    	}
    }
    
    if ((keyLeft) && (!keyRight) && (!keyUp) && (!keyDown)) {
    	if(Game.world.getBlock((byte)this.x, (byte)this.y - 1, (byte)this.z) == 0){
    		moveLookDir(-speed * delta * 0.003F, 0.0F + 2, 0.0F - 2);
    	}
    }
      
    if ((keyRight) && (!keyLeft) && (!keyUp) && (!keyDown)) {
    	if(Game.world.getBlock((byte)this.x, (byte)this.y + 1, (byte)this.z) == 0){
    		moveLookDir(speed * delta * 0.003F, 0.0F - 2, 0.0F - 2);
    	}
    }
    
    if ((space) && (!shift)) {
    	if(Game.world.getBlock((byte)this.x, (byte)this.y, (byte)this.z + 1) == 0){
    		this.y += 1 * delta * 0.003F;
    	}
    }
    
    if (!(space) && (!shift)) {
    	if(Game.world.getBlock((byte)this.x, (byte)this.y, (byte)this.z - 1) == 0){
    		this.y -= 1 * delta * 0.003F;
    	}
    }

    /**
    * this.x, this.y, this.z is the camera position.
    */

Thanks for reading.

Ok first off, why are you casting everything to a byte?

Second, collision detection and response are two different things. Quite obviously your detection works. Now you need to figure out how to respond to the collision. Basic response is easy, don’t do anything (besides not letting the player move in the direction of the block of course!). I have found a couple of issues with your code, I believe.

First, the casting thing. Are you seriously telling me the player positions are limited to the range of a byte?

Second, you shouldn’t be checking for each key combination. What you need to do is every frame you need to find where the player will be next. That means you will need some variables:

Movespeed - obvious what it is
Position - Player position
Next direction - basically on what axis will the player be moving next?

Then, use the following formula to calculate the next position of the player:


position.x + nextPos.x * moveSpeed (optionally also multiply by the delta if you calculate it, which you should)

When you have the next position, use your getBlock method to determine which block the player will be in next frame. If its empty, let the plate move. If not, well don’t.

This is how basic collision detection works, its not AABB.

Well, I removed the byte casting (Didn’t change anything) and how should I calculate the next position?

And. I still got the problem that its detecting the collision inside the block. For some reason…
How can I fix that?

And isn’t Collision Detection AABB?

No. AABBs are just a form of collision detection. It stands for Axis Aligned Bounding Box because the boxes never rotate. More specifically the model axis always line up with the world axis. If they did rotate you would have to use something like SAT.

You aren’t using AABBs right now, you’re just checking to see if you are going to be inside a block space. Its completely different.

I just gave you the “formula” to calculate the next position.

I meant.

position.x + nextPos.x * moveSpeed

How can I calculate

 nextPos.x 

?

Ah yes. Well, think about it. Your blocks are in an array, and arrays have indices. 1, 2, 3… Etc… So, it you want to get the next position of your player relative to your block array, you need to access the next block in which you are going to move. So, logically nextPos would only hold a value of 1 or 0 for its components.

What that’s means is that when you hit ‘W’ for example, you want to move forward on the Z axis. So, you set nextPos.z to be 1. Then you move the player. After you have moved the player, do two collision detection checks. Like this:


if(Game.world.getBlock(pos.x + nextPos.x * moveSpeed, pos.x, pos.z) != null) {
//do collision response for x axis. In this case, you can simply not move the player. Repeat this if statement for the y and z axis accordingly. You must check each axis separately though.
}

Pretty simple really, and you don’t need all those if statements that you already have. Just three simple if statements.

Oh thx, Ill try it out after I finished the Block placement and removement :slight_smile:

You have to calculate the velocity of your players bounding-box into the given Voxels bounding-box you are checking for collision, reducing the velocity on each axis for every voxel-collision so you don’t go trough any block.

Super-Pseudocode:


LIST<Voxels> nearbyVoxels = world.getNearbyVoxels(PLAYER_COLLISION_RANGE);
BOX playerBounds = ???;
VEC3 playerVelocity = ???;

for_each SPATIAL_AXIS [+-X,+-Y,+-Z]
{
  for_each VOXEL in nearbyVoxels
  {
    BOX voxelBounds = ??get boundingbox from given voxel??;
    
    (( the per-Axis difference method is applied here, using the velocity on the given spatial axis, the player-boundingbox, and the voxels boundingbox ))
    
  }
}


Actual Code:


vec3 playerPos = ...;
vec3 playerVelocity = ...;


// Check for all collisions on the Y-Axis.
for_each VOXEL in PLAYER_SURROUNDINGS
{
  playerVelocity.y = VOXEL.?.boundingBox.getYOffset(playerVelocity.Y);
}


// Check for all collisions on the X-Axis.
for_each VOXEL in PLAYER_SURROUNDINGS
{
  playerVelocity.x = VOXEL.?.boundingBox.getXOffset(playerVelocity.x);
}

// Check for all collisions on the Z-Axis.
for_each VOXEL in PLAYER_SURROUNDINGS
{
  playerVelocity.z = VOXEL.?.boundingBox.getZOffset(playerVelocity.z);
}

playerPosition += playerVelocity * moveSpeed;

Difference Method:


    public double getXOffset(AABB3D playerBoundings, double movementOnX)
    {
        if ((aabb.b.y <= this.a.y) || (aabb.a.y >= this.b.y))
			return movementOnX;

        if ((aabb.b.z <= this.a.z) || (aabb.a.z >= this.b.z))
			return movementOnX;

        if ((movementOnX > 0D) && (aabb.b.x <= this.a.x))
        {
            double d = this.a.x - aabb.b.x;

            if (d < movementOnX)
				movementOnX = d;
        }

        if ((movementOnX < 0D) && (aabb.a.x >= this.b.x))
        {
            double d1 = this.b.x - aabb.a.x;

            if (d1 > movementOnX)
				movementOnX = d1;
        }
        
        return movementOnX;
    }

The difference method takes some time to understand,so don’t worry if you don’t understand it!
Nobody understands it in the beginning.

I understand it, but I have serious trouble explaining it, so this is probably the worst explanation for this method, everi[/i].

Have a nice day!

  • Longor1996

PS: This is the method that is used in Minecraft.

WEll, Thanks you all for your replies.

It got fixed for like 90%.
I used all of your code and put it together.

I now can’t pass through blocks. But its clipping like crazy.


    if((keyUp)){
    	if(Game.world.getBlockB(this.x + 1, this.y, this.z) == 0) {
    		//do collision response for x axis. In this case, you can simply not move the player. Repeat this if statement for the y and z axis accordingly. You must check each axis separately though.
    		moveLookDir(0.0F, 0.0F, -speed * delta * 0.003F - 1);
    	}else{
    		moveLookDir(0.0F, 0.0F, 4.0F);
    	}
    }
    
    if((keyDown)){
    	if(Game.world.getBlockB(this.x - 1, this.y, this.z) == 0) {
    		//do collision response for x axis. In this case, you can simply not move the player. Repeat this if statement for the y and z axis accordingly. You must check each axis separately though.
    		moveLookDir(0.0F, 0.0F, speed * delta * 0.003F + 1);
    	}else{
    		moveLookDir(0.0F, 0.0F, -4.0F);
    	}
    }
    
    if((keyRight)){
    	if(Game.world.getBlockB(this.x, this.y, this.z + 1) == 0) {
    		//do collision response for x axis. In this case, you can simply not move the player. Repeat this if statement for the y and z axis accordingly. You must check each axis separately though.
    		moveLookDir(speed * delta * 0.003F + 1, 0.0F, 0.0F);
    	}else{
    		moveLookDir(4.0F, 0.0F, 0.0F);
    	}
    }
    
    if((keyLeft)){
    	if(Game.world.getBlockB(this.x, this.y, this.z - 1) == 0) {
    		//do collision response for x axis. In this case, you can simply not move the player. Repeat this if statement for the y and z axis accordingly. You must check each axis separately though.
    		moveLookDir(-speed * delta * 0.003F - 1, 0.0F, 0.0F);
    	}else{
    		moveLookDir(-4.0F, 0.0F, 0.0F);
    	}
    }
    
    if ((space) && (!shift)) {
    	if(Game.world.getBlockB(this.x, this.y, this.z + 1) == 0){
    		this.y += speed * delta * 0.003F;
    	}else{
    		this.y -= 2.0F;
    	}
    }
    
    if ((!space) && (!shift)) {
    	if(Game.world.getBlockB(this.x, this.y, this.z - 1) == 0){
    		this.y -= speed * delta * 0.003F;
    	}else{
    		this.y += 2.0F;
    	}
    }