I have rewritten the collision module to use block casting; after lots of tweaking, I’ve gotten it to a state where I can no longer clip into objects, and there are no mispredicts! It is pretty simple, but it took me forever to think of it. Now, we can use variable-sized hitboxes!
This would probably get better results with capsule colliders, but its been working fine for me with the block ones.
It is a drop in replacement, the only bit of code that needs changing is the ProjectVelocity function in the Simulation module.
if planes[result.normal] == nil then
planes[result.normal] = true
--Deflect the velocity and keep going
moveVel = MathUtils:ClipVelocity(moveVel, result.normal, 1.0)
else
--We hit the same plane twice, push off it a bit
movePos += result.normal * 0.01
moveVel += result.normal
break
end
I changed it to use the results normal instead of its plane number.
local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")
local Debris = game:GetService("Debris")
local PhysicsService = game:GetService("PhysicsService")
if RunService:IsServer() then -- probably just create these in studio beforehand or the server module instead of here
PhysicsService:RegisterCollisionGroup("GameArea")
PhysicsService:CollisionGroupSetCollidable("GameArea","GameArea",true)
PhysicsService:CollisionGroupSetCollidable("GameArea","Default",false)
end
local module = {}
-- Constants
local DEFAULT_SIZE = Vector3.new(3, 5, 3)
local SHIFTBACK = 1 -- shift start position of the cast back by a constant offset, in opposite direction of movement. this will avoid the cast ever starting too close to a wall and us phasing through. There are some quirks when going over small terrain or features.
-- under 1 there are some rare cases when at extreme angles that you can get close enough to a wall to phase through it
function module:Sweep(startPos, endPos) -- not sure how to properly impelement all solid and start solid, possibly do a getpartBoundsInBox check at the starting position, but that will pick up meshparts incorrectly
local data = {
startPos = startPos,
endPos = endPos,
fraction = 1,
startSolid = false,
allSolid = false,
normal = Vector3.new(0, 1, 0),
}
local offset = endPos-startPos
local distance = offset.Magnitude
if distance <= 0 or distance >= 1024 then
return data
end
local direction = offset.Unit
local params = RaycastParams.new()
params.CollisionGroup = "GameArea"
--params.FilterType = Enum.RaycastFilterType.Exclude
--params.FilterDescendantsInstances = {}
local castOrigin = startPos-(direction*SHIFTBACK)
local result = workspace:Blockcast(
CFrame.new(castOrigin),
DEFAULT_SIZE,
direction*(distance+SHIFTBACK),
params
)
if result then
data.fraction = (result.Distance-SHIFTBACK) / direction.Magnitude
data.normal = result.Normal
data.endPos = castOrigin + direction.Unit * result.Distance
--data.allSolid = data.startSolid and data.fraction < 0.001
else
data.endPos = endPos
end
return data
end
function module:MakeWorld(folder)
debug.setmemorycategory("Collision")
-- Process existing parts
for _, instance in ipairs(folder:GetDescendants()) do
if instance:IsA("BasePart") and instance.CanCollide then
instance.CollisionGroup = "GameArea"
end
end
-- Handle new parts
folder.DescendantAdded:Connect(function(instance)
if instance:IsA("BasePart") and instance.CanCollide then
instance.CollisionGroup = "GameArea"
end
end)
end
return module