AABB Swept/Continuous Collision Detection

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
1 Like