Not entirely sure what you’re asking, so here’s two answers.
The simplest way to go about the effect shown in the video is to use something like workspace:GetPartBoundsInRadius()(here), then use a Raycast from the enemy in the direction of the found character. If any parts are in the way that aren’t the humanoid, it won’t trigger.
Although, from your question itself, it sounds like you just want a safe area, which is different from wall detection. If that’s the case, you can run checks on the player’s character and add them a tag whenever they enter the safe zone, then take that tag whenever they exit. The tag would be checked for by the enemy before moving.
Then, either way you go about this, again, the simplest (but not the most effective way) is to use Humanoid:MoveTo(), but a much better way is via PathfindingService.
(Read the docs before asking further questions, unless there’s something else related that you have to ask.)
Raycasts are mostly math. Specifically, rather than having two different points to raycast between, you’ll instead have to calculate the offset from the NPC, to the found target.
That’s pretty simple, though—subtracting the Position of the enemy HumanoidRootPart from the found target’s HumanoidRootPart should give you an “object-space” Vector3; i.e., an offset that can be used as the 2nd parameter to Raycast.
Do you know why this is not working the npc is not moving
-- Services
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
-- Configuration
local SAFE_ZONE_TAG = "InSafeZone"
local ENEMY = workspace.Noob
local DETECTION_RADIUS = 50
-- Functions
local function isPlayerVisible(enemy, target)
local direction = (target.Position - enemy.HumanoidRootPart.Position).Unit
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {enemy}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local raycastResult = workspace:Raycast(enemy.HumanoidRootPart.Position, direction * DETECTION_RADIUS, raycastParams)
if raycastResult then
local hitPart = raycastResult.Instance
if hitPart and hitPart:IsDescendantOf(target.Parent) then
return true
end
end
return false
end
local function onEnterSafeZone(player)
if not player.Character then return end
player.Character:SetAttribute(SAFE_ZONE_TAG, true)
end
local function onExitSafeZone(player)
if not player.Character then return end
player.Character:SetAttribute(SAFE_ZONE_TAG, nil)
end
local function moveToTarget(enemy, target)
local path = PathfindingService:CreatePath({
AgentRadius = 2,
AgentHeight = 5,
AgentCanJump = true,
AgentJumpHeight = 7,
AgentMaxSlope = 45
})
path:ComputeAsync(enemy.HumanoidRootPart.Position, target.Position)
if path.Status == Enum.PathStatus.Success then
local waypoints = path:GetWaypoints()
for _, waypoint in ipairs(waypoints) do
enemy:MoveTo(waypoint.Position)
enemy.Humanoid.MoveToFinished:Wait()
end
end
end
local function detectAndChase(enemy)
while task.wait(1) do
local partsInRadius = workspace:GetPartBoundsInRadius(enemy.HumanoidRootPart.Position, DETECTION_RADIUS)
for _, part in ipairs(partsInRadius) do
local player = Players:GetPlayerFromCharacter(part.Parent)
if player and not player.Character:GetAttribute(SAFE_ZONE_TAG) then
if isPlayerVisible(enemy, part) then
moveToTarget(enemy, part)
end
end
end
end
end
local safeZone = workspace.Safezone
safeZone.Touched:Connect(function(hit)
local player = Players:GetPlayerFromCharacter(hit.Parent)
if player then
onEnterSafeZone(player)
end
end)
safeZone.TouchEnded:Connect(function(hit)
local player = Players:GetPlayerFromCharacter(hit.Parent)
if player then
onExitSafeZone(player)
end
end)
task.spawn(function()
detectAndChase(ENEMY)
end)