I’ve been making a mantling system very recently and it’s been going quite well
It works by emitting a forward raycast from the character and then emitting a downward raycast to find a ledge, if there is a ledge then the character is lerped into that target position
To not struggle with roblox collisions, i got the idea to split the lerping into 2 parts;
- Lerp player upwards until they’re at the same height as the target position
- Lerp player forward until they’re at target position
All of that works very well, except for one thing;
Post-mantle, the character does a really weird sudden flickback, which triggers the anti-cheat (anti-teleport) and I have no idea as to why it happens
I tried increasing the height of the target position slightly to account for slight offsets, but that didn’t change anything
I am now making the character’s legs non-collidable, but that doesn’t work either
I am out of ideas, and I need help
-- Helper functions;
local function SetLegsCollidability(character: Model, state: boolean)
for _, limb: BasePart in character:GetChildren() do
if limb.Name == 'Right Leg' or limb.Name == 'Left Leg' then
limb.CanCollide = state
end
end
end
-- Main functions;
local function GetMantleTarget(origin: Vector3, direction: Vector3): Vector3
local forwardResult = workspace:Raycast(origin, direction * mantleLength, mantleParams)
local forwardPos = if forwardResult then forwardResult.Position else origin + Vector3.new(0, 2, 0) + direction * mantleLength
local downOrigin = forwardPos + Vector3.new(0, ledgeHeightCheck, 0)
local downResult = workspace:Raycast(downOrigin, Vector3.new(0, -10, 0), mantleParams)
if not downResult then return nil end
return downResult.Position
end
local function MantlePlayer(player: Player, target: Vector3)
local character = player.Character
local root = character.PrimaryPart
local startPosition = root.Position
local targetPosition = target + Vector3.new(0, 10, 0)
local midPosition = Vector3.new(startPosition.X, targetPosition.Y, startPosition.Z)
local elapsed = 0
local heartbeat: RBXScriptConnection = nil
SetLegsCollidability(character, false)
heartbeat = rService.Heartbeat:Connect(function(dt)
elapsed += dt
local alpha = math.clamp(elapsed / mantleTime, 0, 1)
local upAlpha = alpha / 0.5
local forwardAlpha = (alpha - 0.5) / 0.5
local current = if alpha < 0.5 then startPosition:Lerp(midPosition, upAlpha) else midPosition:Lerp(targetPosition, forwardAlpha)
local lookAt = root.CFrame.LookVector + root.Position
root.CFrame = CFrame.lookAt(current, lookAt)
if alpha < 1 then return end
heartbeat:Disconnect()
SetLegsCollidability(character, true)
end)
end