Pathfinding NPC gets confused on wedges

Hello there!

I’m currently creating a pathfinding script using SimplePath. It works for the most part, however though, it seems to be confused whenever I jump onto a wedge’s side as it jumps back and fourth as seen in the video below.

External Media

As you can see, the npc will keep jumping back and fourth until I go near him which he’ll continue as normally (Although will occasionally jump back for some reason).

--//Defiler
local NPC = script.Parent
local Humanoid = NPC:WaitForChild("Humanoid")
Humanoid.BreakJointsOnDeath = false
NPC.HumanoidRootPart:SetNetworkOwner(nil) --No hacking
--//Services
local Players = game:GetService("Players")
local PFS = game:GetService("PathfindingService")
local Debris = game:GetService("Debris")
--//Pathfinding Stuff
local ServerStorage = game:GetService("ServerStorage")
local SimplePath = require(ServerStorage.SimplePath)
--//AI
local function FindNearestTarget()
	local players = {}
	local nearest = math.huge
	local Target = nil

	for _, Player in pairs(Players:GetPlayers()) do
		local Character = Player.Character or Player.CharacterAdded:Wait()

		local Distance = (NPC.HumanoidRootPart.Position - Character.PrimaryPart.Position).Magnitude
		if Distance <= nearest then
			table.insert(players,{
				Magnitude = Distance,
				player = Player
			})
		end
	end

	for _, Entry in pairs(players) do
		local Mag = Entry.Magnitude
		local Plr = Entry.player
		if Mag <= nearest then
			nearest = Mag
			Target = Plr
		end
	end

	return Target
end

game:GetService("RunService").Heartbeat:Connect(function()
	local Player = FindNearestTarget()
	--//Character
	local Player_Char = Player.Character or Player.CharacterAdded:Wait()
	local Char_Root = Player_Char.PrimaryPart
	local Char_Hum = Player_Char:FindFirstChildWhichIsA("Humanoid")

	if Char_Hum.Health <= 1 then
		return
	end
	
	--//Pathfinding
	local Goal = Char_Root.Position
	local Path = SimplePath.new(NPC)

	Path.Blocked:Connect(function()
		Path:Run(Goal)
	end)
	Path.Reached:Connect(function()
		Path:Run(Goal)
	end)
	Path.Error:Connect(function(errorType)
		Path:Run(Goal)
	end)
	Path:Run(Goal)
end)
1 Like

Updated with complexity:

local PathfindingService = game:GetService("PathfindingService")
local CollectionService = game:GetService("CollectionService")
local MessagingService = game:GetService("MessagingService")
local RunService = game:GetService("RunService")

local AStar = require(game.ServerScriptService.AStar)
local EnvironmentAnalyzer = require(game.ServerScriptService.EnvironmentAnalyzer)
local PathLearning = require(game.ServerScriptService.PathLearning)

local NPC = {}
NPC.__index = NPC

function NPC.new(character)
    local self = setmetatable({}, NPC)
    self.character = character
    self.humanoid = character:FindFirstChildOfClass("Humanoid")
    self.currentPath = nil
    self.target = nil
    self.pathUpdateRate = 2
    self.obstacleDetectionRange = 50
    self.pathEfficiencyData = PathLearning.init()
    return self
end

function NPC:updatePath(targetPosition)
    local path = AStar.calculatePath(self.character.PrimaryPart.Position, targetPosition, self.obstacleDetectionRange)
    self.currentPath = path
    self:followPath()
end

function NPC:followPath()
    if not self.currentPath then return end
    for _, waypoint in ipairs(self.currentPath) do
        if EnvironmentAnalyzer.detectObstacles(waypoint, self.obstacleDetectionRange) then
            self:updatePath(self.target.Position)
            return
        end
        self.character.PrimaryPart.CFrame = CFrame.new(waypoint.Position)
        RunService.Heartbeat:Wait()
    end
end

function NPC:setTarget(target)
    self.target = target
    self:updatePath(target.Position)
end

local function tagDynamicObstacles()
    for _, object in ipairs(workspace:GetDescendants()) do
        if object:IsA("Part") and object.CanCollide then
            CollectionService:AddTag(object, "Obstacle")
        end
    end
end
tagDynamicObstacles()

MessagingService:SubscribeAsync("PathEfficiencyData", function(message)
    PathLearning.updateData(message.Data)
end)

local npc = NPC.new(game.Workspace.NPCModel)

npc:setTarget(game.Players.LocalPlayer.Character)
1 Like

Works fine for the most part, although it still seems to be a bit confused on wedges

1 Like

The script is updated check it out

Uh, what is AStar, EnvironmentAnalyzer, and PathLearning?

1 Like

AStar is used for finding the shortest or most efficient path between two points in a game or simulation. It helps characters or objects navigate through a game world.

EnvironmentAnalyzer provides tools for analyzing the game environment. It allows developers to gather information about objects, their properties, and positions in order to create interactive systems or debug their games.

PathLearning focuses on machine learning techniques for pathfinding. It allows developers to train AI agents to learn and navigate through a game environment on their own, making them more intelligent and adaptive.

1 Like

Well, aren’t those ModuleScripts?

1 Like

They can be local variables or AStar, EnvironmentAnalyzer, and PathLearning are not.

Regarding whether they are module scripts, it depends on the specific context or separate modules or scripts that provide specific functionality.

But they are in this code require or separate models in this case

1 Like

Okay then. I’m entirely new to those things, mind if you send a setup of those three?

1 Like

Sure thing

  1. Create a new script in the “ServerScriptService” folder of your game.

  2. Copy and paste the AStar, EnvironmentAnalyzer, and PathLearning code into the script.

  3. Use the require function to import the modules in your main script or module.

  4. Set up the NPC class and perform pathfinding using the imported modules.

By following these steps, you can set up the AStar, EnvironmentAnalyzer, and PathLearning modules in your game.

Code

local AStar = require(game.ServerScriptService.AStar)
local EnvironmentAnalyzer = require(game.ServerScriptService.EnvironmentAnalyzer)
local PathLearning = require(game.ServerScriptService.PathLearning)
1 Like

Here’s the code of those three?

1 Like

If you’re looking to implement these modules in the Roblox game then here’s how you can approach it

  1. AStar Module:
local AStar = {}

function AStar:new(graph)
    local astar = {}
    astar.graph = graph
    -- Implement other necessary variables and functions

    return astar
end

function AStar:calculateHeuristic(node, goal)
    -- Calculate the heuristic value between the current node and the goal
end

function AStar:findOptimalPath(start, goal)
    -- Implement the A* search algorithm to find the optimal path
end

function AStar:updateCost(node)
    -- Update the cost values of the nodes in the graph
end

function AStar:getNeighbors(node)
    -- Get the neighboring nodes of a given node
end

return AStar
  1. EnvironmentAnalyzer Module:
local EnvironmentAnalyzer = {}

function EnvironmentAnalyzer:new(gameWorld)
    local analyzer = {}
    analyzer.gameWorld = gameWorld
    -- Implement other necessary variables and functions

    return analyzer
end

function EnvironmentAnalyzer:detectObstacles()
    -- Detect and identify obstacles in the game world
end
    
function EnvironmentAnalyzer:identifyWalkableAreas()
    -- Identify the walkable areas in the game world
end

function EnvironmentAnalyzer:calculateDistance(point1, point2)
    -- Calculate the distance between two points in the game world
end

return EnvironmentAnalyzer
  1. PathLearning Module:
local PathLearning = {}

function PathLearning:new()
    local learning = {}
    learning.successfulPaths = {}
    learning.unsuccessfulPaths = {}
    -- Implement other necessary variables and functions

    return learning
end

function PathLearning:storeSuccessfulPath(path)
    -- Store information about a successful path taken by the NPC
end

function PathLearning:storeUnsuccessfulPath(path)
    -- Store information about an unsuccessful path taken by the NPC
end

function PathLearning:updatePathPreferences()
    -- Update the preferences for selecting paths based on past experiences
end

return PathLearning

Now you can use the require function to run these modules !

local AStar = require(game.ServerScriptService.AStar)
local EnvironmentAnalyzer = require(game.ServerScriptService.EnvironmentAnalyzer)
local PathLearning = require(game.ServerScriptService.PathLearning)

Hmm, what am I suppose to type inside of the module functions?

1 Like

For example, if you have the AStar module, you might use its functions like this:

local AStar = require(game.ServerScriptService.AStar)

-- Call a function from the AStar module
local path = AStar.FindPath(startPosition, endPosition)

Similarly, if you have the EnvironmentAnalyzer module, you might use it like this:

local EnvironmentAnalyzer = require(game.ServerScriptService.EnvironmentAnalyzer)

-- Access a variable from the EnvironmentAnalyzer module
local environmentType = EnvironmentAnalyzer.GetEnvironmentType(player)

And if you have the PathLearning module, you might use it like this:

local PathLearning = require(game.ServerScriptService.PathLearning)

-- Call a function from the PathLearning module
PathLearning.LearnPath(player, path)

Remember to replace startPosition, endPosition, and player with the appropriate values or variables in your game. Additionally, ensure that the module scripts are located in the correct folder and that you have the necessary permissions to access them which is in ServerScriptService

Alrighty then!

Sorry if you feel like your getting freeloaded, but mind if you write a simple script within the functions of the modules?

1 Like
  1. For the PathLearning module:
function PathLearning:printSuccessfulPaths()
    for i, path in ipairs(self.successfulPaths) do
        print("Successful Path " .. i .. ": " .. path)
    end
end

function PathLearning:printUnsuccessfulPaths()
    for i, path in ipairs(self.unsuccessfulPaths) do
        print("Unsuccessful Path " .. i .. ": " .. path)
    end
end
  1. For the EnvironmentAnalyzer module:
function EnvironmentAnalyzer:analyzeEnvironment()
    self:detectObstacles()
    self:identifyWalkableAreas()
    -- Implement other necessary analysis functions
end

function EnvironmentAnalyzer:printObstacles()
    for i, obstacle in ipairs(self.obstacles) do
        print("Obstacle " .. i .. ": " .. obstacle)
    end
end

function EnvironmentAnalyzer:printWalkableAreas()
    for i, area in ipairs(self.walkableAreas) do
        print("Walkable Area " .. i .. ": " .. area)
    end
end
  1. For the AStar module:
function AStar:printOptimalPath(path)
    for i, node in ipairs(path) do
        print("Node " .. i .. ": " .. node)
    end
end

These functions add some basic functionality to each module that allows you to print or analyze the stored data. You can expand these functions as well

Let me know if you need any further assistance!

Thanks! Anyway, is there a document on about the three?

1 Like

Yes, there is documentation available for A* pathfinding, environmental analysis, and path learning in Roblox.

  1. A* Pathfinding: The Roblox Developer Hub provides documentation on implementing A* pathfinding in Roblox games using the PathfindingService module. )

  2. Environmental Analyzer: The environmental analyzer in Roblox allows you to analyze the surroundings of a character or object in a game. You can use this feature to detect nearby objects, obstacles, or other environmental elements.

  3. Path Learning: Path learning involves teaching characters or objects in a game to navigate through a specific path or learn from their environment. While there isn’t a specific module or documentation dedicated to path learning in Roblox, you can use a combination of scripting, AI, and data storage techniques to implement path learning in your game.

Visit Roblox developer hub too

Okay then, mind if I have the links to the documents?

Relevant documentation:

  1. A* Pathfinding: Implementing A* Pathfinding

  2. Environmental Analyzer: Analyzing the Environment

Please note that the links provided will direct you to the specific sections of the Roblox Developer Hub where you can find detailed information and examples on implementing A* pathfinding and using the environmental analyzer in your Roblox games.

Visit Roblox hub too again