IKControl Character Kinematic Twitching

Howdy! I followed this YouTube video on how to create a character kinematic look effect and I came across a twitching issue and I was wondering if anyone knew how to fix it?

Shoutout to @5uphi for making amazing videos!

local RunService = game:GetService('RunService')

local ReplicatedStorage = game:GetService('ReplicatedStorage')
local Players = game:GetService('Players')

local parts = {}

function characterAdded(character)
	task.wait()
	
	local ik = Instance.new('IKControl')
	ik.Type = Enum.IKControlType.LookAt
	ik.ChainRoot = character.UpperTorso
	ik.EndEffector = character.Head
	ik.Target = parts[Players:GetPlayerFromCharacter(character)]
	ik.Weight = .999
	ik.Parent = character.Humanoid
end

function playerAdded(player)
	local part = Instance.new('Part')
	
	part.Anchored = true
	part.CanCollide = false
	part.CanQuery = false
	part.CanTouch = false
	part.Transparency = .5
	part.Parent = workspace
	
	parts[player] = part
	
	if player.Character then
		characterAdded(player.Character)
	end
	
	player.CharacterAdded:Connect(characterAdded)
end

for index,player in Players:GetPlayers() do
	playerAdded(player)
end

Players.PlayerAdded:Connect(playerAdded)

function playerRemoving(player)
	parts[player]:Destroy()
	parts[player] = nil
end

Players.PlayerRemoving:Connect(playerRemoving)


function renderStepped(dt)
	for player,part in parts do
		if not player.Character then continue end
		
		part.Position = player.Character.Head.Position + player:GetAttribute('LookVector') * 10
		--part.Position = player.Character.Head.Position + Vector3.new(0,2,0) + player:GetAttribute('LookVector') * 20
	end
end

RunService.RenderStepped:Connect(renderStepped)

using ik.Weight = .999 no longer has the same effect as before

what you would need to do is decrees the weight as the angle between the players rootpart and camera look vector gets greater

or another option is to mirror the parts angle when looking behind yourself

1 Like

I appreciate the comment and instruction from the man himself! Unfortunately my math is terrible and I don’t know how to do what you suggested…

If I go with the mirror option, is this what you mean?

function renderStepped(dt)
	for player,part in parts do
		if not player.Character then continue end
		
		
		--part.Position = player.Character.Neck.Position + player:GetAttribute('LookVector') * 20

		local angle = math.acos(
				math.clamp(workspace.CurrentCamera.CFrame.LookVector:Dot(player.Character.HumanoidRootPart.CFrame.LookVector),-1, 1))

		local backwards = false
		if angle > math.pi/2 then
			backwards = true
		end
		
		part.Position = player.Character.Neck.Position + Vector3.new(0,2,0) + player:GetAttribute('LookVector') * (backwards and -10 or 10)
	end
end

RunService.RenderStepped:Connect(renderStepped)

I’d prefer your first option. I’m not going to ask you to write it for me but maybe you could point me in the right direction?

so in the video we cover using dot inside the Look localscript that’s inside StarterPlayerScripts
so we do the same thing and by using dot we can work out the angle by doing
camera.CFrame.LookVector:Dot(humanoidRootPart.CFrame.LookVector)
this will give us a value between 1 and -1

1 meaning 0 degrees
0 meaning 90 degrees
-1 meaning 180 degrees

so if we set the ik.Weight = 1 + dot
this will set the Weight to

2 at 0 degrees
1 at 90 degrees
0 at 180 degrees

and because ik.Weight has a maximum value of 1 it will clamp the value down to 1 so the ik will end up having

1 at 0 degrees
1 at 90 degrees
0 at 180 degrees

here is the final code

local runService = game:GetService("RunService")
local parts = {}
local iks = {} -- add a table so we can access each characters IK easily

local function CharacterAdded(character)
	task.wait()
	
	local ik = Instance.new("IKControl")
	ik.Type = Enum.IKControlType.LookAt
	ik.ChainRoot = character.UpperTorso
	ik.EndEffector = character.Head
	ik.Target = parts[game.Players:GetPlayerFromCharacter(character)]
	ik.Parent = character.Humanoid
	iks[character] = ik -- when we create the IK add it to the table
	
	character.Humanoid.Died:Wait() ik:Destroy() -- TEMP FIX
end

local function CharacterRemoving(character)
	iks[character] = nil -- when the character is removed remove the IK from the table
end


local function PlayerAdded(player)
	local part = Instance.new("Part")
	part.Anchored = true
	part.CanCollide = false
	part.CanQuery = false
	part.CanTouch = false
	part.Transparency = 1
	part.Parent = workspace
	
	parts[player] = part
	
	if player.Character ~= nil then CharacterAdded(player.Character) end
	player.CharacterAdded:Connect(CharacterAdded)
	player.CharacterRemoving:Connect(CharacterRemoving) -- we must now keep track of when a character is removed
end

local function PlayerRemoving(player)
	parts[player]:Destroy()
	parts[player] = nil
end

for i, player in game.Players:GetPlayers() do PlayerAdded(player) end
game.Players.PlayerAdded:Connect(PlayerAdded)
game.Players.PlayerRemoving:Connect(PlayerRemoving)

runService.RenderStepped:Connect(function(deltaTime)
	for player, part in parts do
		if player.Character == nil then continue end
		local ik = iks[player.Character] -- get the characters IK from the table
		if ik ~= nil then ik.Weight = 1 + workspace.CurrentCamera.CFrame.LookVector:Dot(player.Character.HumanoidRootPart.CFrame.LookVector) end -- use dot to workout the angle from the Camera and HumanoidRootPart and use that to set the Weight
		part.Position = player.Character.Head.Position + player:GetAttribute("LookVector") * 10
	end
end)
2 Likes

Thank you! It works perfectly!

I greatly appreciate the time and hard work you pour into your videos! Keep it up! You’re amazing.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.