Pretty nice R15 footplanting system I made for fun, feel free to put it into a local script if you want it to be a bit smoother, but I just chose to make it a server script to save myself the troubles of making replication.
Works with terrain as well. You can see the feet align with the slope of whatever surface they are resting on.
Script:
---///Variables\\\---
--Limbs
local Character = script.Parent
local Human = Character:WaitForChild("Humanoid")
local RFoot = Character:WaitForChild("RightFoot")
local LFoot = Character:WaitForChild("LeftFoot")
local Root = Character:WaitForChild("HumanoidRootPart")
--Caches
local TargetCache = Instance.new("Folder", Character)
TargetCache.Name = "Targets"
local IKCache = Instance.new("Folder", Character)
IKCache.Name = "IKControls"
--Target Creation Func
local function CreateTargetFor(Limb : BasePart)
local Target = Instance.new("Part", TargetCache)
Target.Anchored = true
Target.CanCollide = false
Target.CanQuery = false
Target.BrickColor = BrickColor.Red()
Target.Size = Limb.Size
Target.Transparency = 1
return Target
end
--Targets
local RTarget = CreateTargetFor(RFoot)
RTarget.Name = "RightTarget"
local LTarget = CreateTargetFor(LFoot)
LTarget.Name = "LeftTarget"
--Control Creation Func
local function CreateIK(Chain, End, Target)
local Control = Instance.new("IKControl", IKCache)
Control.ChainRoot = Chain
Control.EndEffector = End
Control.Target = Target
Control.Type = Enum.IKControlType.Transform
Control.Priority = 999
Control.Weight = 1
Control.Enabled = true
Control.SmoothTime = 0.1
return Control
end
--Controls
local RControl = CreateIK(Character:WaitForChild("RightUpperLeg"), RFoot, RTarget)
local LControl = CreateIK(Character:WaitForChild("LeftUpperLeg"), LFoot, LTarget)
--Function For Casting
local function getFootCFrame(position, rootLookVector)
local forward = Vector3.new(rootLookVector.X, 0, rootLookVector.Z).Unit
local up = Vector3.new(0, 1, 0)
local right = up:Cross(forward).Unit
local fixedForward = right:Cross(up).Unit
return CFrame.fromMatrix(position, right, up)
end
--Raycast Parameters
local RayParams = RaycastParams.new()
RayParams.FilterType = Enum.RaycastFilterType.Exclude
RayParams.FilterDescendantsInstances = {Character}
local Direction = Vector3.new(0, -3, 0)
--Script
local function PlantFeet()
local LOrigin = Root.Position - Root.CFrame.RightVector * 0.5 - Vector3.new(0, 1, 0)
local ROrigin = Root.Position + Root.CFrame.RightVector * 0.5 - Vector3.new(0, 1, 0)
local LRay = workspace:Raycast(LOrigin, Direction, RayParams)
local RRay = workspace:Raycast(ROrigin, Direction, RayParams)
if LRay then
local Position = LRay.Position + Vector3.new(0, LFoot.Size.Y / 2, 0)
local Normal = LRay.Normal
local Forward = Root.CFrame.LookVector
local Right = Normal:Cross(Forward).Unit
local Up = Normal
local AlignedForward = Right:Cross(Up).Unit
LTarget.CFrame = CFrame.fromMatrix(Position, AlignedForward, Up) * CFrame.fromEulerAngles(0, math.rad(-90), 0)
else
local position = LOrigin + Direction
local rootLook = Root.CFrame.LookVector
LTarget.CFrame = getFootCFrame(position, rootLook) * CFrame.Angles(math.rad(50), math.rad(180), 0)
end
if RRay then
local Position = RRay.Position + Vector3.new(0, RFoot.Size.Y / 2, 0)
local Normal = RRay.Normal
local Forward = Root.CFrame.LookVector
local Right = Normal:Cross(Forward).Unit
local Up = Normal
local AlignedForward = Right:Cross(Up).Unit
RTarget.CFrame = CFrame.fromMatrix(Position, AlignedForward, Up) * CFrame.fromEulerAngles(0, math.rad(-90), 0)
else
local position = ROrigin + Direction
local rootLook = Root.CFrame.LookVector
RTarget.CFrame = getFootCFrame(position, rootLook) * CFrame.Angles(math.rad(50), math.rad(180), 0)
end
end
--Smoothing
local TweenService = game:GetService("TweenService")
local Info = TweenInfo.new(0.15)
local R_On = TweenService:Create(RControl, Info, {Weight = 1})
local R_Off = TweenService:Create(RControl, Info, {Weight = 0.001})
local L_On = TweenService:Create(LControl, Info, {Weight = 1})
local L_Off = TweenService:Create(LControl, Info, {Weight = 0.001})
local function Toggle(val : boolean)
if val == true then
L_On:Play()
R_On:Play()
task.wait(Info.Time)
LControl.Enabled = true
RControl.Enabled = true
else
L_Off:Play()
R_Off:Play()
task.wait(Info.Time)
LControl.Enabled = false
RControl.Enabled = false
end
end
game:GetService("RunService").Heartbeat:Connect(function()
if Human.MoveDirection == Vector3.zero and Human:GetState() == Enum.HumanoidStateType.Running then
PlantFeet()
Toggle(true)
else
Toggle(false)
end
end)