The code below is made by x_o, I just modified it
local module = {}
local jumpPower = 40
local stances = {
["None"] = {0.9, CFrame.new(0, -1, 0), 1},
["Sprint"] = {1.3, CFrame.new(0, -1.1, 0), 0.8},
["Crouch"] = {0.5, CFrame.new(0, -2, 0) * CFrame.Angles(-math.pi / 12, 0, 0), 0.5},
["Prone"] = {0.3, CFrame.new(0, -2.4, 0) * CFrame.Angles(-math.pi / 2.1, 0, 0), 0}
}
local RunService = game:GetService("RunService")
local atn2, acs, floor = math.atan2, math.acos, math.floor
local pi = math.pi
local function LerpNumber(a, b, t)
return a + (b - a) * t
end
local function IsNAN(x)
return x ~= x
end
function module.new(Character, stride, defaultSpeed, cycleSpeed)
local Connection
local direction = Vector3.new(0, 0, -1)
local left, right = 0, pi
local rhipcf, lhipcf
local Lefthit
local LeftfootPosition
local Righthit
local RightfootPosition
local BlacklistParams = RaycastParams.new()
BlacklistParams.FilterType = Enum.RaycastFilterType.Blacklist
BlacklistParams.IgnoreWater = true
local humanoid = Character:FindFirstChildWhichIsA("Humanoid") or Character:WaitForChild("Humanoid", 3) or nil
if humanoid.Health <= 0 or humanoid:GetState() == Enum.HumanoidStateType.Dead then return end
local torso = Character:FindFirstChild("Torso") or Character:WaitForChild("Torso", 3) or nil
local state = Character:FindFirstChild("State") or Character:WaitForChild("State", 3) or nil
local hrp = Character:FindFirstChild("HumanoidRootPart") or Character:WaitForChild("HumanoidRootPart", 3) or nil
if torso == nil or hrp == nil then return end
local lefthip = torso:FindFirstChild("Left Hip") or torso:WaitForChild("Left Hip", 3) or nil
local leftshoulder = torso:FindFirstChild("Left Shoulder") or torso:WaitForChild("Left Shoulder", 3) or nil
local rightshoulder = torso:FindFirstChild("Right Shoulder") or torso:WaitForChild("Right Shoulder", 3) or nil
local righthip = torso:FindFirstChild("Right Hip") or torso:WaitForChild("Right Hip", 3) or nil
local rootjoint = hrp:FindFirstChild("RootJoint") or hrp:FindFirstChild("Root Hip") or hrp:WaitForChild("RootJoint", 3) or hrp:WaitForChild("Root Hip", 3) or nil
local l, e = lefthip.C1.Y, righthip.C1.Y
lhipcf = CFrame.new(lefthip.C0.X, -l, lefthip.C0.Z)
rhipcf = CFrame.new(righthip.C0.X, -e, righthip.C0.Z)
Connection = RunService.Heartbeat:Connect(function(deltaTime)
if Character ~= nil and humanoid ~= nil and humanoid.Health > 0 and rootjoint ~= nil and torso ~= nil and lefthip ~= nil and righthip ~= nil and RunService:IsRunning() then
BlacklistParams.FilterDescendantsInstances = {Character, workspace.Projectiles, workspace.Humanoids, workspace.Humanoids.Boltons, workspace.Humanoids.Trojans, workspace.Camera}
local lerp10 = math.min(deltaTime * 10, 1)
local velocity = Vector3.new(torso.Velocity.X, 0, torso.Velocity.Z)
if velocity.magnitude > 0.1 then
direction = direction:Lerp(velocity.Unit, deltaTime * 10)
end
local climbing = humanoid:GetState() == Enum.HumanoidStateType.Climbing
if climbing then
velocity += Vector3.new(0, torso.Velocity.Y, 0)
direction = torso.CFrame.LookVector
end
right = (right + (velocity.magnitude / defaultSpeed) * deltaTime * cycleSpeed) % (pi * 2)
left = (left + (velocity.magnitude / defaultSpeed) * deltaTime * cycleSpeed) % (pi * 2)
-- LEANING
local localVelocity = hrp.CFrame:VectorToObjectSpace(velocity) * 0.2
rootjoint.C0 = rootjoint.C0:Lerp(stances[state.Value][2], lerp10)
rootjoint.C1 = CFrame.new(0, -1, 0) * CFrame.Angles(math.rad(localVelocity.Z), math.cos(right) * 0.1 - math.rad(localVelocity.X) * 2, math.rad(-localVelocity.X)):Inverse()
local up = (velocity.Magnitude / defaultSpeed)
-- RIGHT LEG
local hip = (torso.CFrame * rhipcf).Position
local ground = (torso.CFrame * CFrame.new(rhipcf.X, rhipcf.Y * 3, 0))
if state.Value == "Prone" or climbing then
ground = ground * CFrame.new(0, 0, -stride / 2)
end
ground = ground.Position
local desiredPosition = (CFrame.new(ground, ground + direction) * CFrame.Angles(-right, 0, 0) * CFrame.new(0, 0, -stride / 2)).Position
local distance = math.min((hip - desiredPosition).Magnitude, 3)
local ray = Ray.new(hip, CFrame.new(hip, desiredPosition).LookVector * LerpNumber(3, distance, up))
local hit1, footPosition1 = game.Workspace:FindPartOnRayWithIgnoreList(ray, BlacklistParams.FilterDescendantsInstances)
if hit1 then
if hit1.CanCollide == false then
table.insert(BlacklistParams.FilterDescendantsInstances, hit1)
end
end
distance = (hip - footPosition1).Magnitude
local offset1 = (torso.CFrame * rhipcf):PointToObjectSpace(footPosition1)
local x1, y1 = math.atan2(offset1.Z, offset1.Y), math.atan2(offset1.X, offset1.Y)
righthip.C0 = rhipcf * CFrame.Angles(x1, 0, 0) * CFrame.Angles(0, 0, y1) * CFrame.Angles(0, pi, 0)
if distance < 2 then
local angle = -math.acos(distance / 2)
local newCF1 = righthip.C0 * CFrame.Angles(-angle, 0, 0) * CFrame.new(0, -0.6, 0) * CFrame.Angles(angle * 1.6, 0, 0) * CFrame.new(0, 0.6, 0)
righthip.C0 = newCF1
end
-- LEFT LEG
local hip = (torso.CFrame * lhipcf).Position
local ground = (torso.CFrame * CFrame.new(lhipcf.X, lhipcf.Y * 3, 0))
if state.Value == "Prone" or climbing then
ground = ground * CFrame.new(0, 0, -stride / 2)
end
ground = ground.Position
local desiredPosition = (CFrame.new(ground, ground + direction) * CFrame.Angles(-left, 0, 0) * CFrame.new(0, 0, -stride / 2)).Position
local distance = math.min((hip - desiredPosition).Magnitude, 3)
local ray = Ray.new(hip, CFrame.new(hip, desiredPosition).LookVector * LerpNumber(3, distance, up))
local hit, footPosition = game.Workspace:FindPartOnRayWithIgnoreList(ray, BlacklistParams.FilterDescendantsInstances)
if hit then
if hit.CanCollide == false then
table.insert(BlacklistParams.FilterDescendantsInstances, hit)
end
end
distance = (hip - footPosition).Magnitude
local offset = (torso.CFrame * lhipcf):PointToObjectSpace(footPosition)
local x, y = math.atan2(offset.Z, offset.Y), math.atan2(offset.X, offset.Y)
lefthip.C0 = lhipcf * CFrame.Angles(x, 0, 0) * CFrame.Angles(0, 0, y) * CFrame.Angles(0, pi, 0)
if distance < 2 then
local angle = -math.acos(distance / 2)
local newCF = lefthip.C0 * CFrame.Angles(-angle, 0, 0) * CFrame.new(0, -0.6, 0) * CFrame.Angles(angle * 1.6, 0, 0) * CFrame.new(0, 0.6, 0)
lefthip.C0 = newCF
end
else
if Connection ~= nil then
Connection:Disconnect()
Connection = nil
end
end
end)
end
return module
The code above is the whole foot planting module, I’m not satisfied with how messy the code looks like, it uses FindPartOnRayWithIgnoreList
instead of WorldRoot:Raycast
, because FindPartOnRay
still returns positions even if the cast isn’t successful, while WorldRoot:Raycast
doesn’t return positions unless the cast is successful
The changes I have done is just variables & the parameter
(Character model is not made by me)
Any optimizations that can be used for this?