I recently started working on a custom character controller completely from scratch. No roblox physics and custom collision detection. But there comes the issue, my first implementations for collision detection was raycasting out in all directions using first blockcasts then spherecasts. This worked until the move speed was too great and the character would phase through objects during frames, and hence no collision would be detected. After doing some research I stumbled across this video: https://www.youtube.com/watch?v=YR6Q7dUz2uk. After implementing it I couldn’t get wall collisions to work properly. If you went slow against a wall you would phase through and I couldn’t get proper collision response/sliding against walls. I then came across swept AABB collisions, I only found papers in 2d and code I couldn’t understand. My current method is a mix of collide and slide and swept collision detection. I get where the player will be using their velocity and every frame raycast from their current position to where they will be next frame. I use recursion and repeat this step a few times so I can properly detect corners. However this method doesn’t allow for moving up slopes and if moving around alot you can still sometimes clip through walls. If anyone has more insight on collide and slide or swept collisions detection any help would be appreciated. I know chickynoid uses a method of swept collisions but it’s hard to understand and would be harder to fork the system over to my character controller.
My current collision code:
local maxBounces = 5
local skinWidth = .015
function Movement:CollideAndSlide(vel: Vector3, pos: Vector3, depth: number)
if depth >= maxBounces then
return Vector3.zero
end
local predictedPos = pos + Vector3.new(vel.X, 0, vel.Z)
local distance = (pos - predictedPos).Magnitude
local direction = (predictedPos - pos).Unit
if distance < .5 then
distance = .5
end
distance += skinWidth
if not (direction ~= direction) then
local collisionCheck = workspace:Blockcast(CFrame.new(pos), Vector3.new(rootPart.Size.X - skinWidth, rootPart.Size.Y, rootPart.Size.Z - skinWidth), direction * distance, params)
if collisionCheck then
vel -= Vector3.new(collisionCheck.Normal.X, 0, collisionCheck.Normal.Z) * Vector3.new(collisionCheck.Normal.X, 0, collisionCheck.Normal.Z):Dot(Movement.velocity)
print("collision")
return Movement:CollideAndSlide(vel, pos, depth + 1)
end
end
return vel
end