R6 IKPF (Inverse Kinematics Procedural Footplanting)

I would want this to only be the walking animation but when doing an attack, and playing my animation for the attack it doesnt work, do i have to temporarly dissable the ikpf script for it to play my animations?

1 Like

how did you make it like this?? i wanna replicate this for my game

3 Likes

Inside ProceduralAnimator Module replace the function

function ProceduralAnimatorClass:MoveLegs(stepCycle,dt)
	--if moving
	for _, Leg in pairs(self.Legs) do
		local strideCF2 = Leg.StrideCF or self.DefaultStrideCF
		local strideOffset2 = Leg.StrideOffset or self.DefaultStrideOffset
		local raycastParams2 = self.RaycastParams
		Leg.CurrentCycle = (Leg.CurrentCycle+stepCycle)%360
		local cycle2 = Leg.CurrentCycle
		local IKTolerance2 = Leg.IKTolerance or 0

		local hip2			=Leg.HipAttachment.WorldPosition
		--Position of where the lower leg should be, spread out
		local ground2		=Leg.FootAttachment.WorldPosition
		local desiredPos2	=(CF(ground2, ground2+self.MovementDirectionXZ)*ANGLES(-cycle2, 0, 0)*strideCF2).p
		local futurePos1	=(CF(ground2, ground2+self.MovementDirectionXZ)*ANGLES(-(cycle2 + 0.7), 0, 0)*strideCF2).p
		local offset2		=(desiredPos2-hip2)--vector from hip to the circle
		local foffset		=(futurePos1-hip2)--vector from hip to the circle
		local highlightedfuture = (hip2 + foffset.unit*(foffset.magnitude+strideOffset2))
		local raycastResult2 = workspace:Raycast(hip2,offset2.unit*(offset2.magnitude+strideOffset2),raycastParams2)
		local footPos2 = raycastResult2 and raycastResult2.Position or (hip2 + offset2.unit*(offset2.magnitude+strideOffset2))
		
		if self.rootVelocityMagnitude > 0.1 then
			--Do IK towards foot pos
			--Leg.CCDIKController:CCDIKIterateOnce(footPos,IKTolerance)
			--Iterating once won't fully track the footPos, needs to iterate until
			-- DEBUG
			--[[local HighLight = Instance.new("Part", workspace)
			HighLight.Name = "Highlight"
			HighLight.Position = footPos2
			HighLight.CanCollide = false
			HighLight.Size = Vector3.new(0.5, 0.5, 0.5)
			HighLight.Shape = Enum.PartType.Ball
			HighLight.CanTouch = false
			HighLight.CanQuery = false
			HighLight.Anchored = true
			local HighLighter = Instance.new("Highlight", HighLight)
			HighLighter.FillColor = Color3.new(1, 0, 0.0156863)
			HighLighter.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
			game.Debris:AddItem(HighLight,0.05)]]
			
			Leg.CCDIKController:CCDIKIterateUntil(footPos2,IKTolerance2)
			
			if not Leg.TouchGround and raycastResult2 then
				self.FootStep:Fire(raycastResult2)
			end
			--
			if raycastResult2 then -- hit ground so raycast result
				Leg.TouchGround = true
			else
				Leg.TouchGround = false
			end
			
		else --stand still
			
			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
			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))
			
			-- LAST LEG POSITION DEBUG
			--[[local HighLight2 = Instance.new("Part", workspace)
			HighLight2.Name = "Highlight"
			HighLight2.Position = footPos2
			HighLight2.CanCollide = false
			HighLight2.Size = Vector3.new(0.5, 0.5, 0.5)
			HighLight2.Shape = Enum.PartType.Ball
			HighLight2.CanTouch = false
			HighLight2.CanQuery = false
			HighLight2.Anchored = true
			local HighLighter = Instance.new("Highlight", HighLight2)
			HighLighter.FillColor = Color3.new(1, 0, 0.0156863)
			HighLighter.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
			game.Debris:AddItem(HighLight2,0.05)
			
			-- CURRENT LEG POSITION DEBUG
			local HighLight = Instance.new("Part", workspace)
			HighLight.Name = "Highlight"
			HighLight.Position = Vector3.new(footPos2.X, footPos.Y, footPos2.Z)
			HighLight.CanCollide = false
			HighLight.Size = Vector3.new(0.5, 0.5, 0.5)
			HighLight.Shape = Enum.PartType.Ball
			HighLight.CanTouch = false
			HighLight.CanQuery = false
			HighLight.Anchored = true
			local HighLighter = Instance.new("Highlight", HighLight)
			HighLighter.FillColor = Color3.new(0.733333, 1, 0)
			HighLighter.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
			game.Debris:AddItem(HighLight,0.05)]]
			
			--Leg.CCDIKController:CCDIKIterateOnce(Vector3.new(desiredPos2.X, desiredPos.Y + desiredPos2.Y,desiredPos2.Z),IKTolerance)
			Leg.CCDIKController:CCDIKIterateOnce(
				Vector3.new(footPos2.X, footPos.Y, footPos2.Z)
				,IKTolerance
			)
			
			if not Leg.TouchGround and raycastResult then
				self.FootStep:Fire(raycastResult) 
			end
			
			if raycastResult then -- hit ground so raycast result
				Leg.TouchGround = true
			else
				Leg.TouchGround = false
			end
			
		end
		
	end
	
end
9 Likes

its the sway also you need to red the notes in the script its quite usefull

1 Like

Help my tiny little brain can’t figure out how to use the script I can get to the part to use iterate once setup foot those things but the values it wants me to put in their just confuse me. I tried going to the tutorial but the link doesn’t work am I just dumb is this easy to setup

3 Likes

Could this also be done using the new IK Controls?

2 Likes

Yep, it only takes one line to replace the IK portion of the script in the quote above :CCDIKIterateUntil.

Just be aware of the changes made to the R6 leg to make it 2 limbs instead of 1 for that animation effect.

3 Likes

im very late but after a little bit of tweaking i figured it out so what you need to do

inside the procedural animator module copy this code its the whole script

– Procedural Animator Class
– Dthecoolest
– November 20, 2020
local RunService = game:GetService(“RunService”)

local ProceduralAnimatorClass = {}
ProceduralAnimatorClass.__index = ProceduralAnimatorClass

–Module to handle the procedural animation the hip and legs
–remnants from iGottics Code
local CF =CFrame.new
local ANGLES =CFrame.Angles
local x_and_y = Vector3.new(1, 0, 1)
local TAU = 2math.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) – Normalize dt for our needs

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

So if i try to animate them what will happen?
Trying to make kicking animations.
If this will do nothing(Pretty sure it will do nothing)
then how would I do this?

2 Likes

I downloaded this and did the command game:SetUniverseId(1818) so my offline experience would have R6 enabled. Placed it in StarterPlayerScripts because it was a LocalScript with a few modules.

This picture is the server-sided picture. Now as described, it creates 4 motor6d and 2 parts to set up a fake joint and then disables the old motor6ds. I do not know why they decided to do this in the first place.
Some basic behavior of motor6ds is that only the .Transform property is replicated from client to server (for animation purposes). So basically you have an unreplicated client implementation here. Also Roblox’s animation player uses the .Transform property as well.

Additionally, a more practical approach would be to use the .Transform property of the existing joint, and to create a boolean value inside of Humanoid to disable the IK animation temporarily so normal animations can be played. I believe this could be done if you simply record the properties (as in C0, C1, Transform) of the 4 motor6ds you created as variables. That way there are no new joints or parts. To get the resulting .Transform for the existing joint, perform a CFrame calculation.

I believe this would be more practical because instead of performing 20 character calculations on the server or 20 character calculations on each client, each client would perform 1 character’s calculation and replicate normally, and allow for animations.

2 Likes

Screenshot 2023-03-25 101741
I tried multiplayer and when a player resets the other player’s legs go crazy anyone knows how to fix this?

3 Likes

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: