How to make the player face the nearest NPC?

As the title says, im trying to make the player face the nearest enemy. Im working on a combat system and i want to be able to run up to an NPC and automatically face him.

What im trying to achieve is the ability to run up to an NPC and not have to worry about aiming your mouse while swinging your sword. Kind of like some auto lock feature i guess. Any help is greatly appreciated!

2 Likes

You could try setting the character’s HumanoidRootPart’s CFrame
Since the CFrame.new constructor can take a position and a “lookAt”, you can do something like this:

rootPart.CFrame = CFrame.new(rootPart.Position, enemyRoot.Position)
2 Likes

You can do the following

local function getNearestNPC(character, npcsFolder) -- Your character and the folder containing all the NPCs
    local rootPart = character:FindFirstChild("HumanoidRootPart")
    local rootPosition = rootPart.CFrame.Position
    
    local bestNPC
    local maxDistance = math.huge -- Change it to the maximum distance you want an NPC to be
    for _, model in next, npcsFolder:GetChildren() do
        if model:IsA("Model") and model:FindFirstChild("HumanoidRootPart") then
            local distance = (model.HumanoidRootPart.CFrame.Position - rootPosition).Magnitude
            if distance < maxDistance then
                maxDistance = distance
                bestNPC = model
            end
        end
    end
    
    return bestNPC, maxDistance
end

game:GetService("RunService").RenderStepped:Connect(function()
    local closestNPC, closestDistance = getNearestNPC(YOUR_CHARACTER, NPC_FOLDER)
    if closestNPC then
        local rootCFrame = YOUR_CHARACTER.HumanoidRootPart.CFrame
        local targetCFrame = closestNPC.HumanoidRootPart.CFrame
        YOUR_CHARACTER:PivotTo(CFrame.new(rootCFrame.Position, targetCFrame.Position))
    end
end)

Best regards,
Octonions

1 Like

Hello, Would you tell me where i should put this script? and What you meant by “Your Character”.

I just started scripting so i got confused here

Just use lookAt. It’s as simple as that.

YOUR_CHARACTER can be defined as your player’s model.

local PlayerService = game:GetService("Players")
local localPlayer = PlayerService.LocalPlayer
if not localPlayer.Character then
    localPlayer.CharacterAdded:Wait()
end
local YOUR_CHARACTER = localPlayer.Character

oh ok. And where should i put this script? Like in starterplayer or somewhere else.

You can put that in StarterGui. I guess it will work just fine.

1 Like

Here’s an example script in Lua for Roblox that should achieve the auto-lock feature you’re looking for:

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

local detectionRadius = 10
local target = nil

function findNearestEnemy()
    local enemies = game.Workspace:GetChildren()
    local minDistance = math.huge
    local nearestEnemy = nil
    
    for i, enemy in ipairs(enemies) do
        if enemy:IsA("Model") and enemy:FindFirstChild("Humanoid") and enemy.Humanoid.Health > 0 then
            local distance = (enemy.HumanoidRootPart.Position - player.Character.HumanoidRootPart.Position).magnitude
            if distance < minDistance and distance <= detectionRadius then
                minDistance = distance
                nearestEnemy = enemy
            end
        end
    end
    
    return nearestEnemy
end

function rotatePlayerToTarget()
    if target then
        local direction = target.HumanoidRootPart.Position - player.Character.HumanoidRootPart.Position
        local angle = math.atan2(direction.z, -direction.x)
        player.Character.HumanoidRootPart.CFrame = CFrame.new(player.Character.HumanoidRootPart.Position) * CFrame.Angles(0, angle, 0)
    end
end

function onMouseClick()
    target = findNearestEnemy()
    rotatePlayerToTarget()
end

mouse.Button1Down:Connect(onMouseClick)

This script first defines the detection radius and initializes the target variable to nil. The findNearestEnemy() function loops through all objects in the game’s Workspace and finds the nearest enemy within the detection radius. The rotatePlayerToTarget() function calculates the angle between the player’s forward vector and the direction to the target enemy, then rotates the player towards the target. Finally, the onMouseClick() function is called when the player clicks their left mouse button, and it sets the target variable to the nearest enemy and rotates the player towards the target.

Hello Holis, I tried using this and made it work for my game but it doesn’t seem to work… this is what i did. made a local script inside STarterGUI and pasted the script inside. did i do something wrong?

Is there a way to make it so that the camera turns with the player? (sorry for all these questions homie)

Yeah, however it will get very complicated to manipulate if you don’t have experience with how roblox works. You can try to read the documentation and watch tutorials on YT. I am pretty sure that it will be helpful for you :slight_smile:

try this, code recicled form Help with aim assist! - #7 by Gordo_pica

local RunService = game:GetService("RunService")

local tool = script.Parent
local camera = workspace.CurrentCamera

local studsRange = 100
local cameraRange = 0.994

local function printDicctionary(table) for i, v in pairs(table) do warn(i) warn("") warn(v) end end

local function getCharactersArray(plrPos)
	local characters = {}
	for _, v in workspace:GetDescendants() do
		if v:IsA("Humanoid") and v.Health > 0 and v.Parent:FindFirstChild("HumanoidRootPart") and (v.Parent.HumanoidRootPart.Position - plrPos).Magnitude <= studsRange and tool.Parent ~= v.Parent then
			table.insert(characters,v.Parent.HumanoidRootPart.Position)
		end
	end
	return characters
end

local function getDotProductOfPositions(positions, cameraLookVector, cameraPosition)
	local dotArray = {}
	
	for _, pos in pairs(positions) do
		local posToPlayer = (pos - cameraPosition).Unit
		local dot = posToPlayer:Dot(cameraLookVector)
		dotArray[dot] = pos
	end
	
	return dotArray
end

local function getBiggerFromTable(table)
	local greatestNumber = -2
	for number, _ in pairs(table) do
		if number > greatestNumber then
			greatestNumber = number
		end
	end
	return greatestNumber, table[greatestNumber]
end

tool.Equipped:Connect(function()
	local camera = workspace.CurrentCamera
	local function beforeCamera(delta)
		--warn(camera.CameraType)
		local characters = getCharactersArray(camera:GetRenderCFrame().Position)

		local dotArray = getDotProductOfPositions(characters,camera:GetRenderCFrame().LookVector,camera:GetRenderCFrame().Position)
		local biggestDot,pos = getBiggerFromTable(dotArray)


		--warn(biggestDot,pos)
		if biggestDot > cameraRange then
			camera.CFrame = CFrame.lookAt(camera:GetRenderCFrame().Position,pos)
		end
	end

	RunService:BindToRenderStep("aimbot", Enum.RenderPriority.Camera.Value - 1, beforeCamera)
end)

tool.Unequipped:Connect(function()
	RunService:UnbindFromRenderStep("aimbot")
end)