How to make custom collision system?

So I have tried to make a custom collision system by checking if the part is inside a part and then setting the velocity to reflect off of it. My system isn’t very accurate so I need a better one.

Game File:
Collision Test.rbxl (54.2 KB)

Movement Script:

local RunService = game:GetService("RunService")

local part = script.Parent
part:SetAttribute("CurrentPosition", part.Position)

local movingCoroutine = nil

local function StopMoving()
	if movingCoroutine and coroutine.status(movingCoroutine) ~= "running" then
		coroutine.close(movingCoroutine)
		movingCoroutine = nil
	end
end

local function MoveToTarget(delta)
	local origin = part:GetAttribute("CurrentPosition")
	local WalkSpeed = part:GetAttribute("WalkSpeed")
	local Velocity = part:GetAttribute("Velocity")
	
	local cframe = part.CFrame
	local lookVector = cframe.LookVector

	local newPosition = origin + (lookVector * WalkSpeed) + Velocity

	local distance = math.abs((newPosition - origin).Magnitude)
	local timeToReachTarget = distance / WalkSpeed

	local alpha = math.clamp(delta / timeToReachTarget, 0, 1)
	local lerp = origin:Lerp(newPosition, alpha)

	part.Position = lerp
	part:SetAttribute("CurrentPosition", lerp)
end

RunService.Heartbeat:Connect(function(delta)
	MoveToTarget(delta)
end)

Collision Script:

local RunService = game:GetService("RunService")

local part = script.Parent

local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = {part}
overlapParams.FilterType = Enum.RaycastFilterType.Exclude

local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {part}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude

local function DetectCollision()
	local origin = part:GetAttribute("CurrentPosition")
	local WalkSpeed = part:GetAttribute("WalkSpeed")
	local LookVector = part.CFrame.LookVector

	local parts = workspace:GetPartsInPart(part, overlapParams)
	local collided = #parts > 0

	if not collided then
		part:SetAttribute("Velocity", Vector3.new())
	else
		for i,v in ipairs(parts) do
			local position = (v.Position - origin)
			local direction = position.Unit * position.Magnitude
			local raycast = workspace:Raycast(origin, direction, raycastParams)

			if raycast then
				local normal = raycast.Normal
				local dot = LookVector:Dot(normal)
				dot = if (math.abs(dot) == 0) then 1 else dot

				local reflection = LookVector - 2 * dot * normal
				local velocity = reflection.Unit * WalkSpeed
				local position = origin + velocity

				part:SetAttribute("Velocity", velocity)
			end
		end
	end
end

RunService.Heartbeat:Connect(function()
	DetectCollision()
end)

Video:

It would sometimes go through parts.

2 Likes

I must say, this is incredibly impressive. I believe Chickynoid have it’s own collision system and it’s open-sourced too. Might consider checking it out.

1 Like

It’s probably because when it hits two walls, they force each other into each other. Consider taking all the movements, and either averaging them out, or adding them together.

2 Likes

I made it work much better but it would still go through some parts:

as Den_vers said averaging. I know on the game beamNG their physics engine runs thousands of times per second, where as yours runs roughly 60 times per second. Since they run much faster they are able to average their results many times. so can you though but it will cause a delay, unfortunately in Roblox I am not aware of anyway to updating something faster than 60/s, so I don’t see a solution to fixing this delay.

Either way this is pretty cool

1 Like

I just made a script that lets you update faster than 60/s, so you can now average your physics or just have them update faster Updating faster than RenderStepped or task.wait()

1 Like