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.
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):
vel
attribute.vel
attribute accordingly.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.