Hello I am making a NPC. This NPC runs on the client side. The NPC only stop it sees you and you move/run away from it. Below is the script and the game linked below.
-- Services
local Players = game:GetService("Players")
local PathfindingService = game:GetService("PathfindingService")
-- Constants
local ATTACK_DISTANCE = 5.5
local WAIT_TIME_BEFORE_PATROL = 7
local WAYPOINT_CHECK_INTERVAL = 0.1
-- Variables
local player = Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local enemy = nil
local waypointsFolder = game.Workspace:FindFirstChild("Waypoints")
repeat
task.wait(0.1)
until game.Workspace:FindFirstChild("Enemy")
enemy = game.Workspace:FindFirstChild("Enemy")
-- Animations and Sounds
local walkAnim = enemy:WaitForChild("Humanoid"):LoadAnimation(script.WalkAnim)
local attackAnim = enemy.Humanoid:LoadAnimation(script.AttackAnim)
local walkSound = script.WalkSound
local attackSound = script.AttackSound
-- Pathfinding parameters
local pathParams = {
AgentHeight = 5,
AgentRadius = 3,
AgentCanJump = false
}
-- Wait until enemy and waypoints are loaded
repeat
task.wait(WAYPOINT_CHECK_INTERVAL)
enemy = game.Workspace:FindFirstChild("Enemy")
until enemy and waypointsFolder and #waypointsFolder:GetChildren() > 0
-- Functions
local function CheckForCharacter(char)
local rayOrigin = enemy:FindFirstChild("HumanoidRootPart").Position
local rayDirection = (char.HumanoidRootPart.Position - rayOrigin).Unit * 40
local raycastResult = workspace:Raycast(rayOrigin, rayDirection, RaycastParams.new())
if raycastResult then
local raycastInstance = raycastResult.Instance
if raycastInstance:IsDescendantOf(char) then
return true
end
else
return false
end
end
local function FindNearestPlayers()
local players = Players:GetPlayers()
local nearestPlayer = nil
local maxDistance = 40
for _, player in pairs(players) do
if player.Character ~= nil then
local targetCharacter = player.Character
local distance = (enemy.HumanoidRootPart.Position - targetCharacter.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and CheckForCharacter(targetCharacter) then
nearestPlayer = targetCharacter
maxDistance = distance
end
end
end
return nearestPlayer
end
local function Attack(char)
local distance = (enemy.HumanoidRootPart.Position - char.HumanoidRootPart.Position).Magnitude
if distance > ATTACK_DISTANCE then
enemy.Humanoid:MoveTo(char.HumanoidRootPart.Position)
enemy.Humanoid.MoveToFinished:Wait()
else
attackAnim:Play()
attackSound:Play()
char.Humanoid.Health = 0
end
end
local function CalculatePath(destination)
local path = PathfindingService:CreatePath(pathParams)
path:ComputeAsync(enemy:WaitForChild("HumanoidRootPart").Position, destination)
return path
end
local function WalkToDesination(destination)
local path = CalculatePath(destination)
if path.Status == Enum.PathStatus.Success then
for _, waypoint in pairs(path:GetWaypoints()) do
local nearestPlayer = FindNearestPlayers()
if nearestPlayer then
Attack(nearestPlayer)
break
else
enemy.Humanoid:MoveTo(waypoint.Position)
enemy.Humanoid.MoveToFinished:Wait()
end
end
else
enemy.Humanoid:MoveTo(destination - (enemy.HumanoidRootPart.CFrame.LookVector * 10))
end
end
local function Patrol()
local waypoints = workspace.Waypoints:GetChildren()
if #waypoints > 0 then
if walkSound.Playing == false then walkAnim:Play() walkSound:Play() end
WalkToDesination(waypoints[math.random(1, #waypoints)].Position)
end
end
-- Start patrol after initial wait
task.wait(WAIT_TIME_BEFORE_PATROL)
Patrol()
-- Check for enemy and waypoints continuously
while true do
repeat
task.wait(WAYPOINT_CHECK_INTERVAL)
enemy = game.Workspace:FindFirstChild("Enemy")
until enemy
repeat
task.wait(WAYPOINT_CHECK_INTERVAL)
until #waypointsFolder:GetChildren() > 0
task.wait(WAIT_TIME_BEFORE_PATROL) -- Wait before starting patrol again
while true do
Patrol()
task.wait(0.01)
end
end
All help is appreciated!
Maze Generation [v. 1.0.0]