R6 IKPF (Inverse Kinematics Procedural Footplanting)

Thank you! This works.
Here’s a better formatted post that makes it easier to copy and paste for anyone interested:

--Procedural Animator Class
--Dthecoolest
--November 20, 2020

local RunService = game:GetService("RunService")

--Module to handle the procedural animation the hip and legs
--remnants from iGottics Code
local ProceduralAnimatorClass = {}
ProceduralAnimatorClass.__index = ProceduralAnimatorClass

local CF =CFrame.new
local ANGLES =CFrame.Angles
local x_and_y = Vector3.new(1, 0, 1)
local TAU = 2*math.pi
local DOWN = 10*Vector3.new(0,-1,0)

--template for legs
	--local mechLegs = {
		--[“rightLeg”] = {
			--[“CurrentCycle”] = 0,
			--[“LimbChain”] = rightLegChain,
			--[“HipAttachment”]= rightHipAttachment,
			--[“FootAttachment”] = rightStepAttachment,
			--},

		--[“leftLeg”] = {
			--[“CurrentCycle”] = math.pi,
			--[“LimbChain”] =leftLegChain,
			--[“CCDIKController”] =leftLegChain,
			--[“HipAttachment”]= leftHipAttachment,
			--[“FootAttachment”] = leftStepAttachment,
			--}
		--}

	local Signal = require(script.Parent.Signal)

	function ProceduralAnimatorClass.new(RootPart,Legs,RootMotor,raycastParams)

		local self = setmetatable({}, ProceduralAnimatorClass)

		--Constants
		self.RootPart = RootPart
		self.RaycastParams = raycastParams --manual input it

		if RootMotor then
			self.RootMotor = RootMotor
			self.RootMotorC1Store = RootMotor.C1
			self.WaistCycle = 0 
		end

		self.Legs = Legs

		--Default settings for legs
		self.DefaultStride = 2 -- Changes how far the legs move
		self.CycleSpeed = 15 -- How fast the leg-movement cycle is. Change this to suit your needs!
		self.DefaultStrideOffset = 0
		-- Radius of the circle at CFrame front of the player
		self.DefaultStrideCF = CFrame.new(0, 0, -self.DefaultStride / 2) -- Turn that stride number into a CFrame we can use


		--Variables that will change
		self.MovementDirectionXZ = Vector3.new(1, 0, 1) -- This will be changed
		self.rootvelm = 0

		--Sound
		self.FootStep = Signal.new();
		self.MaxSpeed = 20
		self.EngineSound = nil;
		self.FootStepSound = nil;
		self.RandomNumGenerator = Random.new()
		--debug the signal, works
		--self.FootStep:Connect(function()
		--	print("Step")
		--end)

		self.WalkBounce = 0.4 -- factor by which it bounces
		self.SwayX = -1*5 -- factor in Z direction front or behind, currently set to tilt forward
		return self
	end

	function ProceduralAnimatorClass:MoveLegs(stepCycle,dt)
		--if moving
			if self.rootVelocityMagnitude > 0.1 then
				for _, Leg in pairs(self.Legs) do
					local strideCF = Leg.StrideCF or self.DefaultStrideCF
					local strideOffset = Leg.StrideOffset or self.DefaultStrideOffset
					local raycastParams = self.RaycastParams
					Leg.CurrentCycle = (Leg.CurrentCycle+stepCycle)%360
					local cycle = Leg.CurrentCycle
					local IKTolerance = Leg.IKTolerance or 0

					local hip			=Leg.HipAttachment.WorldPosition
					--Position of where the lower leg should be, spread out
					local ground		=Leg.FootAttachment.WorldPosition
					local desiredPos	=(CF(ground, ground+self.MovementDirectionXZ)*ANGLES(-cycle, 0, 0)*strideCF).p
					local offset		=(desiredPos-hip)--vector from hip to the circle
					local raycastResult = workspace:Raycast(hip,offset.unit*(offset.magnitude+strideOffset),raycastParams)
					local footPos = raycastResult and raycastResult.Position or (hip + offset.unit*(offset.magnitude+strideOffset))

					--debug foot pos position
					--local part = Instance.new("Part")
					--part.CanCollide = false
					--part.CanTouch = false
					--part.BrickColor = BrickColor.Red()
					--part.Anchored = true
					--part.CanQuery = false
					--part.Size = Vector3.new(0.1,0.1,0.1)
					--part.Position = footPos
					--part.Parent = workspace
					--game.Debris:AddItem(part,0.1)

					--Do IK towards foot pos
					--Leg.CCDIKController:CCDIKIterateOnce(footPos,IKTolerance)
					--Iterating once won't fully track the footPos, needs to iterate until
					Leg.CCDIKController:CCDIKIterateUntil(footPos,IKTolerance)

					if not Leg.TouchGround and raycastResult then
						--print("Stomp")
						self.FootStep:Fire(raycastResult)
					end
					--
					if raycastResult then -- hit ground so raycast result
						Leg.TouchGround = true
					else
						Leg.TouchGround = false
					end
				end
			else--stand still
				for _, Leg in pairs(self.Legs) do
					local strideCF = Leg.StrideCF or self.DefaultStrideCF
					local strideOffset = Leg.StrideOffset or self.DefaultStrideOffset
					local raycastParams = self.RaycastParams
					local IKTolerance = Leg.IKTolerance or 0

					local hip			=Leg.HipAttachment.WorldPosition
					--Position of where the lower leg should be, spread out
					local desiredPos		=Leg.FootAttachment.WorldPosition+DOWN
					local offset		=(desiredPos-hip)--vector from hip to the circle
					local raycastResult = workspace:Raycast(hip,offset.unit*(offset.magnitude+strideOffset),raycastParams)
					local footPos = raycastResult and raycastResult.Position or (hip + offset.unit*(offset.magnitude+strideOffset))

					--Do IK towards foot pos
					Leg.CCDIKController:CCDIKIterateOnce(footPos,IKTolerance)
					--Leg.LimbChain:IterateOnce(footPos,0.1)
					--Leg.LimbChain:UpdateMotors()
					if not Leg.TouchGround and raycastResult then
						--print("Stomp")
						self.FootStep:Fire(raycastResult)
					end

					if raycastResult then -- hit ground so raycast result
						Leg.TouchGround = true
					else
						Leg.TouchGround = false
					end

				end
			end
	end

	function ProceduralAnimatorClass:MoveTorso(stepCycle,dt10,rootVelocity)

		local lowercf = self.RootPart.CFrame
		local waistjoint = self.RootMotor
		local waist1 = self.RootMotorC1Store
		local rootvel = rootVelocity


		if self.rootVelocityMagnitude > 0.1 then

			self.WaistCycle = (self.WaistCycle+stepCycle)%360

			local relv0	= lowercf:vectorToObjectSpace(rootvel)
			local relv1	= relv0*0.2

			do -- Upper Torso
				local bounceCFrame = CFrame.new(0,self.WalkBounce*math.cos((self.WaistCycle+2+1)*0.02),0)

				local sway = math.rad(-relv1.X)+0.08*math.cos(self.WaistCycle+0.05)
				local swayY = 0.06*math.cos(self.WaistCycle)-0.1*math.rad(relv1.X)
				local swayX = math.rad(relv1.Z)*0.5*self.SwayX
				local goalCF = bounceCFrame*waist1*ANGLES(swayX,swayY,sway):inverse()
				-- goalCF *= CFrame.new(0,math.cos((self.WaistCycle+90+45)*2),0)-- Up and down
				--goalCF *= CFrame.new(0,self.WalkBounce*math.cos((self.WaistCycle+90+45)*2),0)-- Up and down
				--local rotationOnly = goalCF-goalCF.Position
				waistjoint.C1	=	waistjoint.C1:Lerp(goalCF,dt10)
			end

		else
			--when not moving go back to original position
			local goalCF = waistjoint.C1:Lerp(waist1, dt10)
			--local rotationOnly = goalCF-goalCF.Position
			waistjoint.C1	= goalCF
		end
	end

	function ProceduralAnimatorClass:Animate(dt)
		if game.Players.LocalPlayer.Character:WaitForChild("Humanoid").FloorMaterial ~= Enum.Material.Air then
			--Begin the step
			local dt10 = math.min(dt*10, 1)

				local rootpart = self.RootPart
				local rootvel0 = rootpart.Velocity -- Our movement velocity

				local rootVelocity = rootvel0 * x_and_y --XY plane velocity only
				local rootVelocityMagnitude = rootVelocity.Magnitude --root velocity magnitude
			self.rootVelocityMagnitude = rootVelocityMagnitude

			if self.EngineSound then
				self.EngineSound.PlaybackSpeed = (rootVelocityMagnitude / self.MaxSpeed) + 0.6
			end

			--if moving then lerp current direction
			if rootVelocityMagnitude > 0.1 then 
				--lerp current direction towards curren velocity
				self.MovementDirectionXZ = self.MovementDirectionXZ:Lerp(rootVelocity.unit, dt10) 
			end

			local relativizeToHumanoidSpeed = rootVelocityMagnitude/16 --default walk speed is 16
			local stepCycle = relativizeToHumanoidSpeed*dt*self.CycleSpeed

			self:MoveLegs(stepCycle,dt)
			if self.RootMotor then
				self:MoveTorso(stepCycle,dt10,rootVelocity)
			end	
	end
end

function ProceduralAnimatorClass:ConnectFootStepSound(sound : Sound)
	self.FootStep:Connect(function(raycastResult)
		local soundPositionAttachment = Instance.new("Attachment")
		soundPositionAttachment.WorldPosition = raycastResult.Position
		soundPositionAttachment.Parent = workspace.Terrain

		local footStepSound = sound:Clone()
		local randomPlaybackSpeed = self.RandomNumGenerator:NextNumber(0.7,1)
		footStepSound.PlaybackSpeed = randomPlaybackSpeed

		local reverbEffect = Instance.new("ReverbSoundEffect")
		reverbEffect.Density = 0.8
		reverbEffect.DecayTime = 1
		reverbEffect.Parent = footStepSound
		footStepSound.PlayOnRemove = true

		footStepSound.Parent = soundPositionAttachment
		soundPositionAttachment:Destroy()
	end)
end

function ProceduralAnimatorClass:StartEngineSound(sound : Sound)
	local engineSound = sound:Clone()
	engineSound.Parent = self.RootPart
	engineSound.Looped = true
	engineSound:Play()
end

function ProceduralAnimatorClass:InitDragDebug()
	for _, Leg in pairs(self.Legs) do
		Leg.CCDIKController:InitDragDebug()
	end
end

function ProceduralAnimatorClass:Destroy()
	if self.FootStep then
		self.FootStep:Destroy()
	end
	self = nil
end

return ProceduralAnimatorClass
5 Likes

I just realized I forgot to format it lol :joy:

4 Likes

if i were wanting to have the legs move when jumping, what would i need to change/remove

2 Likes

How can I make it so my animations (Walk/Run) move in a procedure manner.

2 Likes

I’m not fully sure what you’re trying to ask here, the original code makes it so the player moves their feet when in the air. If you’re asking what part of the code to alter to make it so they don’t move their feet I’m honestly, unsure. I just used the provided code by Soulx_xFlame and adjusted it to my liking, try asking him. :slight_smile:

2 Likes

If you don’t mind me asking how exactly did you manage to make the legs move so smoothly? I’ve tried to replicate the same effect and have looked through the code of the CCDIKController but got no results like that.

3 Likes

I didn’t really changed much, except its a custom made character :person_shrugging: and added highlighted sphere part

2 Likes

Don’t know why you would want them to move but if you look at this line

function ProceduralAnimatorClass:Animate(dt)
		if game.Players.LocalPlayer.Character:WaitForChild("Humanoid").FloorMaterial ~= Enum.Material.Air then -- this is the line that stops the movement when in the air all It does is stop the leg movement when the player is touching the air material/ not touching the ground
			--Begin the step
			local dt10 = math.min(dt*10, 1)

				local rootpart = self.RootPart
				local rootvel0 = rootpart.Velocity -- Our movement velocity

				local rootVelocity = rootvel0 * x_and_y --XY plane velocity only
				local rootVelocityMagnitude = rootVelocity.Magnitude --root velocity magnitude
			self.rootVelocityMagnitude = rootVelocityMagnitude

			if self.EngineSound then
				self.EngineSound.PlaybackSpeed = (rootVelocityMagnitude / self.MaxSpeed) + 0.6
			end

			--if moving then lerp current direction
			if rootVelocityMagnitude > 0.1 then 
				--lerp current direction towards curren velocity
				self.MovementDirectionXZ = self.MovementDirectionXZ:Lerp(rootVelocity.unit, dt10) 
			end

			local relativizeToHumanoidSpeed = rootVelocityMagnitude/16 --default walk speed is 16
			local stepCycle = relativizeToHumanoidSpeed*dt*self.CycleSpeed

			self:MoveLegs(stepCycle,dt)
			if self.RootMotor then
				self:MoveTorso(stepCycle,dt10,rootVelocity)
			end	
	end
end

i hope that Helps :slightly_smiling_face:

2 Likes

Hi! If I use your module, can I credit you in the credits scene rather then the description, please? I’m going to make a dedicated GUI of credits! :slight_smile:

since this isn’t animation compatible, how would i make it animation compatible; im making a movement system with the procedural movement and it messes with the sprint & slide animations

Just found this out; you can just Enable and/Or Disable Left Hip and Right Hip inside Torso whenever you want it animation compatible.

1 Like

I found the easiest way to fix the jumping

fixed jumping r6ikpf.rbxl (69.3 KB)

I also really like how it works when you apply a actual movement script with it

Movement + Fixed jumping with r6 ikpf

Very nice and the procedural animations seem very customizable

6 Likes

How do i make the legs bend outward?

Great work ! Just wanted to ask how can I animate arms with inverse kinematics, the arms are way too cartoony and moves to fast. As of for now I’am using animation for arms but it oftens glitches. Any solutions ?

Guys how can I make the arms sync the legs? (its a bit urgent, thanks)

how would i go about disabling or enabling left/right hip?

doing it anywhere in a local script will work. You can find it by doing something “like this” : [if its in R6]

	local Character = plr.Character
	local HumRP = Character.HumanoidRootPart
	local Hum = Character.Humanoid
	local Torso = Character.Torso
	local RightHip = Torso:WaitForChild("Right Hip")
	local LeftHip = Torso:WaitForChild("Left Hip")

    LeftHip.Enabled = true 
    RightHip.Enabled = true
1 Like

Apologies for the bump, but can you make this work with @Maximum_ADHD’s Realism?

You can check the video to see whats going on

robloxapp-20230924-1356150.wmv (825.7 KB)

this is in the explorer (if it doesn’t have like (authorname resourcename) then it’s my script

image

image

1 Like

what did you disable? im struggling with this specifically lol

you ever find this out? if you did please let me know.