How to make NPC attack player?

How would i make an NPC try to attack the player when the player goes within around maybe seven studs?

I know it involves magnitude but i’m not sure how i would make the npc walk towards the player, to then attack it.

2 Likes

You can use Humanoid:MoveTo. Give the position of the HumanoidRootPart as the first and the HumanoidRootPart as the second argument. Use Humanoid.MoveToFinished to detect when the timeout is reached and repeat the MoveTo call.

To make sure that the NPC only follows when it’s close enough, check the magnitude every frame.

I haven’t tested this code, so I’m not sure if it works.

local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local FOLLOW_MAX_DISTANCE = 7
local npc = -- npc here

local plrChars = {}
local plrConns = {}

local function onCharAdded(char)
    plrChars[#plrChars+1] = char
end

local function onCharRemoving(char)
   table.remove(plrChars, table.find(plrChars, char)
end

local function onPlayerAdded(plr)
    local conns = {}
    conns[1] = plr.CharacterAdded:Connect(onCharacterAdded)
    conns[2] = plr.CharacterRemoving:Connect(onCharacterRemoving)
    plrConns[plr] = conns
end

local function onplrRemoving(plr)
    for i, v in ipairs(plrConns[plr]) do
        v:Disconnect()
    end
    plrConns[plr] = nil
end

local function isCloseEnough(npc, plrChar)
    local distance = (npc.HumanoidRootPart.Position-plrChar.HumanoidRootPart.Position).Magnitude
    if distance <= FOLLOW_MAX_DISTANCE
        return distance
    end
end

local function randDirNum()
    return math.random()*(-1)^math.random(1, 2)
end

local function getRandomDirection()
    local direction = Vector3.new(randDirNum(), 0, randDirNum())
    if direction == Vector3.new() then
        direction = direction = getRandomDirection()
    end
    direction = direction.Unit
    return direction
end

local function randomMovement(npc)
    local hum = npc.Humanoid
    local direction = getRandomDirection()
    hum:MoveTo(npc.HumanoidRootPart.Position+direction*hum.WalkSpeed*8)
end

local function moveToWardsPlr(npc, plrChar)
    local plrHrp = plrChar.HumanoidRootPart
    npc.Humanoid:MoveTo(plrHrp.Position, plrHrp)
end

local function findClosestChar(npc)
    local closestChar, closestDistance
    for i, char in ipairs(plrChars) do
        local distance = isCloseEnough(char)
        if distance and not closestChar or distance < closestDistance then
            closestChar = char
            closestDistance = distance
        end
    end
    return closestChar
end

local function handleMovement(npc)
    local hum = npc.Humanoid
    local moving = false
    local conn = 
    hum.MoveToFinished:Connect(function()
        moving = false
    end
    while npc.Parent and hum.Health > 0 do
        local closestChar = findClosestChar(npc)
        if not closestChar and (isFollowing or not moving) then
            randomMovement(npc)
            isFollowing = nil
            isMoving = true
        elseif closestChar and (closestChar ~= isFollowing or not moving) then
            moveTowardsPlr(npc, closestChar)
            isFollowing = closestChar
            isMoving = true
        end
        RunService.Heartbeat:Wait()
    end
    conn:Disconnect()
end

Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)

handleMovement(npc)
6 Likes