Lock on target doesn't work properly

So I’ve been trying to script a lock on target system (a character and a camera looking at the Target) and everything seems to work but there’s only one issue that I can’t solve. Basically whenever I go forward, It goes a bit to the left and the closer I am to the target, the faster I go to the left.

I also realised that if I put 0 at X-axis of CAMERA_OFFSET then it doesn’t happens but I don’t want to have X-axis at 0 but 12. Here’s the script:

local UIS = game:GetService('UserInputService')
local RS = game:GetService('RunService')

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local HMRP = Character:WaitForChild('HumanoidRootPart')
local HUM = Character:WaitForChild('Humanoid')
local Mouse = Player:GetMouse()

local Camera = workspace.CurrentCamera

local Target

local MOUSE_HITBOX = Vector3.new(3,3,3)
local CAMERA_OFFSET = Vector3.new(12,2,12)
local CAMERA_LERP = .25

function unLock()
	Target = nil
	HUM.AutoRotate = true
	Camera.CameraType = Enum.CameraType.Custom
	script.Target.Value = nil
end

function check(p)
	return p:FindFirstChild('HumanoidRootPart') and p:FindFirstChild('Humanoid') and p.Humanoid.Health > 0
end

UIS.InputBegan:Connect(function(k,e)
	if(e)then return end
	k = k.KeyCode ~= Enum.KeyCode.Unknown and k.KeyCode or k.UserInputType

	if(k == Enum.KeyCode.L or k == Enum.UserInputType.MouseButton3)then
		if(Target)then
			unLock()
			return
		end

		local Hit = workspace:GetPartBoundsInBox(CFrame.new(Mouse.Hit.Position), MOUSE_HITBOX)
		for i,v in pairs(Hit) do
			local p = v.Parent

			if(check(p))then
				Target = p
				script.Target.Value = p
				Camera.CameraType = Enum.CameraType.Scriptable
			end
		end
	end
end)

RS.RenderStepped:Connect(function()
	if(Target)then
		if not(check(Target)) then
			unLock()
			return
		end

		local HMRP2 = Target.HumanoidRootPart.CFrame
		local distance = Player:DistanceFromCharacter(Target.HumanoidRootPart.Position)
		print(distance)

		HUM.AutoRotate = false
		HMRP.CFrame = CFrame.lookAt(HMRP.Position, Vector3.new(HMRP2.Position.X, HMRP.Position.Y, HMRP2.Position.Z))
		Camera.CFrame = Camera.CFrame:Lerp(CFrame.lookAt((CFrame.lookAt(HMRP.Position, Target.HumanoidRootPart.Position) * CFrame.new(CAMERA_OFFSET)).Position, Target.HumanoidRootPart.Position), CAMERA_LERP)
	end
end)

That happens because of Roblox’s movement code, the only possbile way (the hard way) i can think of its to make own controller that moves character relative to his rotation

Might be hard for me to make the whole controller script. Are you sure there isn’t any other way?

You could try locking from a center point w/o locking their rotation out the get-go to allow for more free movement. If a mouse lock type thing is required, it will still work properly p sure… You can find some UE5 tutorials on this and just take the concept from them as well.

not a completely own, but at least when Locked On the target.
Could use humanoid:MoveTo(Direction)
you can get direction using character.HumanoidRootPart.CFrame.LookVector or character.HumanoidRootPart.CFrame.RightVector
and multiply it by speed you want

I’m not sure what did u meant tbh. Could u explain it better with “roblox scripting” way?

You’d basically treat the character’s head as the central point focused on by the camera and then get the unit vector towards the target RootPart’s position. You may be able to do Target:GetPivot() but I’m pretty sure roblox made it so the pivot points of characters are at the bottom. Some pseudo code:

local RunService = game:GetService("RunService")
local Camera = workspace.CurrentCamera
Camera.CameraType = Enum.CameraType.Scriptable

local characterHead = myCharacterHead
local targetRootPart = myTargetsRootPart
RunService.RenderStepped:Connect(function()
	local headPos = characterHead.Position
	local targetPos = targetRootPart.Position
	local camOffset = (Camera.CFrame.Position-headPos).Magnitude -- don't need this if u do a set offset...
	Camera.CFrame = CFrame.lookAt(headPos,targetPos)*CFrame.new(0,0,camOffset) 
end)

pretty sure this will work, didn’t test this just an fyi

So it sorta worked but now when i change x axis of camera offset, the camera isnt really looking at the target anymore but a bit on the right as my x axis goes. Is there any way to make the camera also looking at the target after the offset is changed?

If you still want an offset on the x-axis you could probably do something like this:

local RunService = game:GetService("RunService")
local Camera = workspace.CurrentCamera
Camera.CameraType = Enum.CameraType.Scriptable

local characterHead = myCharacterHead
local targetRootPart = myTargetsRootPart
RunService.RenderStepped:Connect(function()
	local headPos = characterHead.Position
	local targetPos = targetRootPart.Position
	local offsetX = Camera.CFrame.RightVector*2 -- account for the offset prior to the lookat...
	Camera.CFrame = CFrame.lookAt(headPos+offsetX,targetPos)*CFrame.new(0,0,30) 
end)

The problem is, I’m pretty sure you’ll run into the same issue you’ve had… but you never know unless you try tbh.

This may help as well:

What happens

Roblox control scripts makes the character go to where the camera is looking, when you point your camera backwards your character will turn and walk toward that direction, your lock on changes the camera CFrame and the control script keeps making it go towards where the camera is looking due to some offsets or some stuff.

How to fix

First we need to fork the control script, press play on studio and clone the PlayerModule inside the PlayerScripts:
image

Stop testing, and place it at StarterPlayerScripts:
image

Open ControlModule under PlayerModule, thats the module we have to edit in order to fix the issue.

Firstly, we need to tell the module when we are locked on to someone, and what the root part is:
image

Here i add some simple variables and functions for the variables we will use, then the function we have to edit is calculateRawMoveVector:

This function, uses this line to calculate the direction of movement using the camera CFrame:

We then can simply add an if statement to change the variable it uses to the one we want, that being the root part:
image

In short, what is needed to do is fork the script, change the function that calculates move direction, and make it calculate by your Root Part CFrame instead, since in your Lock on script you move the root part to look directly to the opponent, we can use it and it will always move directly to it when you move forward, “fixing” the bug.

Hope this helps!

1 Like

Thank you so much for the help.

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