I have developed a crude wall collision system. It works partially, but as you can see below, it does not wrap around the player with a huge margin of space, and when I run at a shallow angle towards it, I seemingly ‘merge’ with the wall.
The red dot is a representation of the player’s velocity with a radius of 2.
My existing collision detection is heavily based on nicopatty’s solution, but he uses velocity derived just from the HumanoidRootPart itself, and I have a feeling that his solution will not work with mine, as I use an external force.
My linear velocity is set on an axis to a plane parallel to the ground, so my LinearVelocity is represented as a Vector2.
Here is the code below for the collision detection:
local function WallCheck()
local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = {Character}
overlapParams.FilterType = Enum.RaycastFilterType.Exclude
local getParts = workspace:GetPartBoundsInRadius(HumanoidRootPart.Position, 2, overlapParams)
if #getParts > 0 then
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {Character, p}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local origin = HumanoidRootPart.Position
local baseDirection
if InputDirection.magnitude > 0 then
baseDirection = InputDirection.Unit
else
baseDirection = PlayerVelocity.Unit
end
local angleRange = math.rad(2) -- total wedge = 2 degrees
local rayCount = 5
local half = math.floor(rayCount / 2)
local closestResult = nil
local closestDistance = math.huge
for i = -half, half do
local angle = i * (angleRange / rayCount)
-- rotate the baseDirection around the Y-axis
local rotatedDirection = CFrame.Angles(0, angle, 0):VectorToWorldSpace(baseDirection)
local result = workspace:Raycast(origin, rotatedDirection * 3, raycastParams)
if result and result.Distance < closestDistance then
closestResult = result
closestDistance = result.Distance
end
end
return closestResult
end
return nil
end
This function is called before I execute my movement functions:
local function Move()
local result = WallCheck()
if result and result.Instance and result.Normal then
bodyvelo.ForceLimitsEnabled = false
PlayerVelocity -= result.Normal * PlayerVelocity:Dot(result.Normal)
end
-- accelerate PlayerVelocity from target velocity
if InputDirection.magnitude ~= 0 then
if result and result.Instance and result.Normal then
targetVelocity -= result.Normal * targetVelocity:Dot(result.Normal)
end
end
end
I also made a separate one to handle collisions in the air because I want the character to bounce off the walls:
local function AirMove()
local result = WallCheck()
if result and result.Instance and result.Normal and PlayerVelocity.Magnitude > 0 then
bodyvelo.ForceLimitsEnabled = false
local normal = result.Normal
local impact = PlayerVelocity:Dot(normal)
PlayerVelocity -= (1 + "damping value here") * impact * normal
end
-- player velocity accelerated by target velocity
if InputDirection.Magnitude ~= 0 then
if result and result.Instance and result.Normal then
targetVelocity -= result.Normal * targetVelocity:Dot(result.Normal)
end
end
end
I don’t know if this requires a few tweaks or an entire redesign of my collision physics, but any help would be appreciated.