okay so, this really cool pathfinding code
is responsible for… pathfinding!
the path gets created really perfectly, and all of that stuff (Which is seen in the video), but for whatever reason, the enemy goes backwards and then back to the player very quickly, this should also be visible in the video
i’m really not sure why this is happening?
the script that calls all the pathfinding things
local sScriptService = game:GetService("ServerScriptService")
local players = game:GetService("Players")
-- Path to module;
local enemyScriptsFolder = sScriptService:WaitForChild("Enemies")
-- Module;
local pathfindingModule = require(enemyScriptsFolder.PathfindingModule)
local enemyStats = require(enemyScriptsFolder.EnemyStats)
-- Folder of existing enemies (on the map);
local enemiesFolder = workspace:WaitForChild("Enemies")
-- Functions;
function GetEnemyBehaviorType(enemy: Model): number
return enemyStats[enemy.Name]["behavior"]
end
function GetEnemyCriticalHealthAmount(enemy: Model): number
return enemyStats[enemy.Name]["criticalHealth"]
end
function GetClosestPlayer(enemy: Model, limb: BasePart, closestPlayer: any): Player
local character: Model = limb.Parent
local humanoid: Humanoid = character:FindFirstChildOfClass("Humanoid")
if not character or not humanoid then return end
local targetPlayer = players:GetPlayerFromCharacter(character)
if not targetPlayer then return end
local enemyRootPart: BasePart = enemy:FindFirstChild("HumanoidRootPart")
local playerRootPart: BasePart = character:FindFirstChild("HumanoidRootPart")
-- long if statement
-- checks for closest player
if closestPlayer == nil or (enemyRootPart.Position - playerRootPart.Position).Magnitude < (enemyRootPart.Position - closestPlayer.Character.HumanoidRootPart.Position).Magnitude then
closestPlayer = targetPlayer
end
return closestPlayer
end
function HandlePathfindInitiating()
local enemies = enemiesFolder:GetChildren()
if #enemies == 0 then return end
for _, enemy in ipairs(enemies) do
local detectionPart: BasePart = enemy:FindFirstChild("DetectionPart")
local humanoid: Humanoid = enemy:FindFirstChildOfClass("Humanoid")
local rootPart: BasePart = enemy:FindFirstChild("HumanoidRootPart")
local closestPlayer = nil
local playersInBox = workspace:GetPartBoundsInBox(detectionPart.CFrame, detectionPart.Size)
for _, limb in playersInBox do
-- yes i know, doing it twcie but to prevent overlaod on the server
if not players:GetPlayerFromCharacter(limb.Parent) then continue end
closestPlayer = GetClosestPlayer(enemy, limb, closestPlayer)
end
if closestPlayer == nil then continue end
task.spawn(function()
-- if there's a closest player, pathfind to it
if closestPlayer then
local playerCharacter: Model = closestPlayer.Character
local playerTorso: BasePart = playerCharacter:FindFirstChild("Torso")
local playerPathfindPart: BasePart = playerTorso:FindFirstChild("PathfindPart")
if not playerCharacter or not playerTorso or not playerPathfindPart then return end
local targetPosition = playerPathfindPart.Position
local enemyBehaviorType = GetEnemyBehaviorType(enemy)
-- act based on enemy's behavior
-- first, passive aggressive (flee on low health)
if enemyBehaviorType == 0 then
local enemyCriticalHealth = GetEnemyCriticalHealthAmount(enemy)
if humanoid.Health <= enemyCriticalHealth then
pathfindingModule.Flee(enemy)
else
pathfindingModule.Chase(humanoid, targetPosition)
end
-- then, aggressive (attacks regardless of health)
elseif enemyBehaviorType == 1 then
pathfindingModule.Chase(humanoid, targetPosition)
-- then i need to add defensive here TODO
end
-- if there's no closest player, wander instead (if possible)
else
-- check if the enemy can wander
if enemy:GetAttribute("WanderCooldown") == false and enemy:GetAttribute("Wandering") == false and enemy:GetAttribute("Chasing") == false then
pathfindingModule.Wander(humanoid)
else
-- if the enemy cannot wander and is currently not wandering,
-- stop walking
if enemy:GetAttribute("Wandering") == false then
humanoid:MoveTo(rootPart.Position)
end
end
end
end)
end
end
-- Runtime;
while task.wait(0.05) do
HandlePathfindInitiating()
end
module script (relevant parts only)
function CreatePath(startPos: Vector3, targetPos: Vector3)
local path: Path = pfService:CreatePath(pathParameters)
local success, result = pcall(function()
path:ComputeAsync(startPos, targetPos)
end)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success and #waypoints > 0 then
return waypoints
end
end
function MoveTo(waypoints, humanoid: Humanoid)
for i = 1, #waypoints do
local waypoint: PathWaypoint = waypoints[i]
if waypoint.Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
VisualizePath(waypoint)
humanoid:MoveTo(waypoint.Position)
humanoid.MoveToFinished:Wait()
end
end
function pathfinding.Chase(Humanoid: Humanoid, targetPosition: Vector3) -- Chase the player;
-- Used in: [Aggressive, Passive-Aggressive]
if not Humanoid then return end
if not targetPosition then return end
local char: Model = Humanoid.Parent
char:SetAttribute("Chasing", true)
-- Getting the needed pathfinding data;
local path: Path = pfService:CreatePath(pathParameters)
local humanoidRootPart = char:FindFirstChild("HumanoidRootPart")
local startPosition = humanoidRootPart.Position
local waypoints = CreatePath(startPosition, targetPosition)
if not waypoints then
char:SetAttribute("Chasing", false)
return
end
Humanoid.WalkSpeed = enemyStats[char.Name]["chaseSpeed"]
MoveTo(waypoints, Humanoid)
char:SetAttribute("Chasing", false)
end