Question

I have a problem with collision detection I've been creating for a 3D thing I'm doing.

The way I made the collision detection is, first I store the old xyz coordinates in to variables, then call the moving function, and then the collision function. If there was a collision after the movement, the camera - as in the player (for now) - will be set back to the old x y z coordinates.

I want the character to be able to "slide" along the side of the cube - so that if you collide on x axis, you can still kind of slightly slide along the z axis. However, at the corner, the character completely stops - because there is both x and z collision. I decided to make separate variables for z and x collision to stop this from happening, but now I can get inside the cube when I'm at the corner - but only on X axis. I have no idea how to go about fixing this, I've tried various things (like the latest variable in the code) and I just can't quite figure it out. Help would be appreciated. Here is the relevant part of the code:

def otherCollision(self,x,y,z):
       print(float(Camera.x))
       xcol = 0
       zcol = 0
       latest = 0
       if (-Camera.x >= cubez[0][0] - 1) and \
          (-Camera.x <= cubez[0][0] + cubez[0][3] + 1) and \
          (-Camera.z >= cubez[0][2] - 1) and \
          (-Camera.z <= cubez[0][2] + cubez[0][5] + 1):

            if (-Camera.x >= cubez[0][0] - 1) and \
               (-Camera.x <= cubez[0][0]) or \
               (-Camera.x <= cubez[0][0] - 1 + cubez[0][3] + 2) and \
               (-Camera.x >= cubez[0][0] - 1 + cubez[0][3] + 1): #>
                #Camera.x = x
                xcol = 1
                latest = 1

            if (-Camera.z >= cubez[0][2] - 1) and \
               (-Camera.z <= cubez[0][2]) or \
               (-Camera.z <= cubez[0][2] - 1 + cubez[0][5] + 2) and \
               (-Camera.z >= cubez[0][2] - 1 + cubez[0][5] + 1):    #>=
                #Camera.z = z
                zcol = 1
                latest = 2

       if xcol == 1 and zcol == 0:
           Camera.x = x
       if zcol == 1 and xcol == 0:
           Camera.z = z
       if xcol == 1 and zcol == 1 and latest == 2:
           Camera.x = x
       if xcol == 1 and zcol == 1 and latest == 1:
           Camera.z = z

It should be mentioned that the cubez has a list inside of a list - the first index is the number of the object, and the next index is the value we're looking for. They're, in order, x,y,z,width,height,depth.

I am using pyglet 1.2alpha, but I don't think this is very relevant to the post, as clearly the problem is in my logic.

Was it helpful?

Solution

I think the best solution is to add a velocity attribute to your actor ("character", or "Camera" in your example?). Then depending on the collision, zero out a velocity attribute.

Given a simple vector class like this one:

class Vector(object):
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.x = x
        self.y = y
        self.z = z

... your actor then looks like this:

class Actor(object):
    def __init__(self):
        self.pos = Vector()
        self.vel = Vector()

Now when you update your scene, perform the following steps (abstracted to your example):

  1. Calculate the forces exerted on your actor, and update the vel attribute.
  2. Determine collisions, and update the vel attribute accordingly.
  3. Update the actor's pos with the data from vel.

The below example uses a 2D world for simplicity (z is always 0), and a constant timestep of updating (dt is considered 1 second).

class Actor(object):
    #(...)
    def update(self, dt=1):
        # Step 1 - assumes a constant movement to the top right
        self.vel.x = 1
        self.vel.y = 1

        # Step 2 - cube is your collision tested object
        cube = Cube()
        new_pos = self.pos + (self.vel * dt)
        if new_pos.x > cube.left and new_pos.x < cube.right:
            self.vel.x = 0
        if new_pos.y > cube.bottom and new_pos.y < cube.top:
            self.vel.y = 0

        # Step 3
        self.pos += self.vel * dt

First you should get something like this working. When functioning as it should, add a bounding box to your actor so that the collision is performed on the sides instead of on the center.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top