Search code examples
luascriptinggame-developmentroblox

PathFinding closest Player


Why Isn't Pathfinding working I'm new to scripting and This just doesn't make sense to me I Understan my other code, and I've read the documentation but when it comes to integrating the pathfinding so he will only find/create a path when he had located the nearest player and follow that path has me stumped. To be honest after reading the documentation I would have figured I could just declare the path inside the if statement gauging if the player is close enough and he would follow the path but I looked up a tutorial and he used the GetWayPoints() but I figured that was to be to no avail so far this is my latest attempt

local runService = game:GetService("RunService") -- Run Service sort of like unitys Update frame by frame, SEE DOCUMENTATION SAVED FOLDER
local players = game:GetService("Players") -- Players will help "get" the players in the game

local humanoid = script.Parent -- grabs the parent of the script which is humanoid
local root = humanoid.Parent.PrimaryPart --root is the humanoids parent i.e models primary part which is typically the humanoid root part

local PathfindingService = game:GetService("PathfindingService"); -- A path finding service



local wantedDistance = 30 --  How far he can search or should be trying to search, The value now is small testing needed
local stopDistance = 5 -- In caase we want to use this to make him stop (like if he had a kill radius instead of touching)

local damage = 50
local attackDistance = 8
local attackWait = 1
local lastAttack = tick()
function findNearestPlaya()
    local playerList = players:GetPlayers()
    
    local playerNearest = nil
    local dist = nil
    local direction = nil
    
    for _, player in pairs(playerList) do -- basically a for each loop that says for each player in the list of players
        local character = player.Character 
        if character  then -- will only eggsacute if a player/character exists
            local distanceV = player.Character.HumanoidRootPart.Position - root.Position -- Distance  ''Vector'' equals the distance from the player torso/Root position minus the distance of the models primary part which we have as root
            
        
        
            
            
            if not playerNearest then
                playerNearest = player

                dist = distanceV.Magnitude -- distance vector magnitude gives us the actual distance
                direction = distanceV.Unit -- direction of the nearest player, SEE DOCUMENTATIOIN FOR UNIT AND MAGNITUDE

            elseif distanceV.Magnitude < dist then -- If the player is closer than the set nearest player then ''replace'' the player

                playerNearest = player -- resets to new player
                dist = distanceV.Magnitude
                direction = distanceV.Unit

            end
        end
    
    end
    
    return playerNearest, dist, direction -- function so return which playa and his distance and direction
end

-- Another call from the runService class that runs every "physics frame", Which I think is like the updateBefore in unity
runService.Heartbeat:Connect(function() -- lua thing essentially this odd function call thing is just an anonymous function meaning it will execute every heartbeat
local path = PathfindingService:CreatePath()
local playerNearest, distance, direction = findNearestPlaya()

if the distance is within range of the wanted distance
if playerNearest  then
if distance <=wantedDistance and distance >= stopDistance then
path:ComputeAsync(humanoid.PrimaryPart.Position, playerNearest.PrimaryPart.Position)
local waypoints = path:GetWaypoints()
for _, waypoint in pairs(waypoints)  do
humanoid.MoveTo(waypoint.Position)
end

else 
humanoid:Move(Vector3.new()) -- 


end

if distance <= attackDistance and tick() - lastAttack >= attackWait then
lastAttack = tick();
playerNearest.Character.Humanoid.Health -= damage
end
end


end)
    

I was expecting him to calculate the path to the nearest player hints my code player nearest. I really dont understand why that or just telling him to move to path after calculating it wouldnt work


Solution

  • Here is the solved version comments should do a good job of explaining but essentially I was just being dumb I was harping to much on the direction as long as you ommit that you can essentially guide the NPC as long as he is in range instead of updating every player playerNearest path, the heartbeat function is already handling that all that's required is to create a new path for each player that is nearest then guide him along that path. The script isn't perfect but this will find the nearest player and create a path for the NPC to follow each time for a different nearest player (I'm bad at explanations and I've dragged this on for too long just read the comments)

    local runService = game:GetService("RunService") -- Run Service sort of like unitys Update frame by frame, SEE DOCUMENTATION SAVED FOLDER
    local players = game:GetService("Players") -- Players will help "get" the players in the game
    
    local humanoid = script.Parent -- grabs the parent of the script which is humanoid
    local root = humanoid.Parent.PrimaryPart --root is the humanoids parent i.e models primary part which is typically the humanoid root part
    
    local PathfindingService = game:GetService("PathfindingService"); -- A path finding service
    
    
    
    local wantedDistance = 30 --  How far he can search or should be trying to search, The value now is small testing needed
    local stopDistance = 5 -- In caase we want to use this to make him stop (like if he had a kill radius instead of touching)
    
    local damage = 50
    local attackDistance = 8
    local attackWait = 1
    local lastAttack = tick()
    
    
    
    
    
    
    function findNearestPlaya()
        local playerList = players:GetPlayers()
    
        local playerNearest = nil
        local dist = nil
        local direction = nil   
        for _, player in pairs(playerList) do -- basically a for each loop that says for each player in the list of players
            local character = player.Character 
            if character  then -- will only eggsacute if a player/character exists
                local distanceV = player.Character.HumanoidRootPart.Position - root.Position -- Distance  ''Vector'' equals the distance from the player torso/Root position minus the distance of the models primary part which we have as root
    
    
    
    
    
                if not playerNearest then
                    playerNearest = player
    
                    dist = distanceV.Magnitude -- distance vector magnitude gives us the actual distance
                    direction = distanceV.Unit -- direction of the nearest player, SEE DOCUMENTATIOIN FOR UNIT AND MAGNITUDE
    
                elseif distanceV.Magnitude < dist then -- If the player is closer than the set nearest player then ''replace'' the player
    
                    playerNearest = player -- resets to new player
                    dist = distanceV.Magnitude
                    direction = distanceV.Unit
    
                end
            end
    
        end
    
        return playerNearest, dist, direction -- function so return which playa and his distance and direction
    end
    
    -- Another call from the runService class that runs every "physics frame", Which I think is like the updateBefore in unity
    runService.Heartbeat:Connect(function() -- lua thing essentially this odd function call thing is just an anonymous function meaning it will execute every heartbeat
    
    
        local playerNearest, distance, direction = findNearestPlaya()   
        -- if the distance is within range of the wanted distance
        if playerNearest and distance <= wantedDistance  then
            local path = PathfindingService:CreatePath(); -- Now if hes in range of the player create a new path
            path:ComputeAsync(root.Position, playerNearest.Character.HumanoidRootPart.Position) -- compute the path with the positions of the player and Dr. Sturgeon
            local waypoints = path:GetWaypoints()  -- Assign a new waypoint and and gathers the paths 
            -- standard for each loop for the nodes SEE DOCUMENTATION/TUTORIALS TO UNDERSTAND ''NODES''
            for _, waypoint in pairs(waypoints)  do 
                humanoid:MoveTo(waypoint.Position) -- For each waypoint/node move Dr. sturgeon to it until it reaches the computed path i.e the distance from the player to the robot vice a versa
                humanoid.MoveToFinished:Wait()
            end
        end
    
    
        if distance <= attackDistance and tick() - lastAttack >= attackWait then
            lastAttack = tick();
            playerNearest.Character.Humanoid.Health -= damage
        end
    
    end)