I am creating a monster in Roblox that is supposed to chase the player and make a sound (a scream) when it detects the player. However, there is a bug: when the player leaves the detection radius and then re-enters it, the monster starts screaming again, and this can be repeated infinitely by “going in and out” of the detection radius.
What happens:
- When the player enters the detection radius of the monster, it starts chasing the player and the monster makes a scream.
- If the player leaves the detection radius, the chase stops, and the scream stops.
- However, when the player re-enters the detection radius, the monster screams again and starts chasing.
- If this is done multiple times, the monster can be “bugged,” making it scream every time the player enters the detection radius.
Here is a video:
Here are scripts:
Main
local ws = game:GetService("Workspace")
local rs = game:GetService("RunService")
local pfs = game:GetService("PathfindingService")
local SoundService = game:GetService("SoundService")
local npc = script.Parent
local hum = npc:WaitForChild("Monster")
local root = npc.HumanoidRootPart
local chasing = npc:WaitForChild("Chasing")
local targetVal = npc:WaitForChild("Target")
local attack = false
local canAttack = npc.Configuration.CanAttack
local canFollowNPCs = false
local anims = {
aLeft = hum:LoadAnimation(script.AttackLeft),
aRight = hum:LoadAnimation(script.AttackRight),
aHeavy = hum:LoadAnimation(script.AttackHeavy)
}
local damage = npc.Configuration.Damage
local attackDelay = npc.Configuration.AttackDelay
local rSpeed = npc.Configuration.RunSpeed
local wSpeed = npc.Configuration.WalkSpeed
local hitSounds = {
SoundService:WaitForChild("Hit1"),
SoundService:WaitForChild("Hit2"),
SoundService:WaitForChild("Hit3")
}
local swingSound = SoundService:WaitForChild("Swing")
local currentTarget = nil
local lastChasingState = false
local lostTargetTime = 0
local MAX_TARGET_LOST_TIME = 2
function getNearestTarget()
local dist = 44.5
local char
if canFollowNPCs then
for _, v in pairs(ws:GetChildren()) do
if v:FindFirstChild("Humanoid") and v:FindFirstChild("HumanoidRootPart") and v ~= npc then
local vHum = v:WaitForChild("Humanoid")
local vRoot = v:WaitForChild("HumanoidRootPart")
if vHum.Health > 0 then
local distance = (vRoot.Position - root.Position).Magnitude
if distance <= dist then
dist = distance
char = v
end
end
end
end
else
for _, v in pairs(game.Players:GetPlayers()) do
if v.Character then
local vChar = v.Character
if vChar:FindFirstChild("Humanoid") and vChar:FindFirstChild("HumanoidRootPart") and vChar ~= npc then
local vHum = vChar:WaitForChild("Humanoid")
local vRoot = vChar:WaitForChild("HumanoidRootPart")
if vHum.Health > 0 then
local distance = (vRoot.Position - root.Position).Magnitude
if distance <= dist then
dist = distance
char = vChar
end
end
end
end
end
end
return char
end
function isTargetVisible(target)
if not target then return false end
local targetRoot = target:FindFirstChild("HumanoidRootPart")
if not targetRoot then return false end
local origin = root.Position
local direction = (targetRoot.Position - origin).Unit * 500
local ray = Ray.new(origin, direction)
local hit, _ = workspace:FindPartOnRayWithIgnoreList(ray, {npc})
return hit and hit:IsDescendantOf(target)
end
rs.Heartbeat:Connect(function()
if root.Anchored == false then
root:SetNetworkOwner(nil)
end
local target = getNearestTarget()
local now = os.clock()
if target then
currentTarget = target
lostTargetTime = 0
elseif currentTarget and (now - lostTargetTime) < MAX_TARGET_LOST_TIME then
target = currentTarget
else
currentTarget = nil
end
if target then
local targetRoot = target:FindFirstChild("HumanoidRootPart")
local targetHum = target:FindFirstChild("Humanoid")
if not targetRoot or not targetHum or targetHum.Health <= 0 then
currentTarget = nil
if chasing.Value then
chasing.Value = false
end
return
end
local distance = (root.Position - targetRoot.Position).Magnitude
if distance < 44.5 then
if not chasing.Value then
chasing.Value = true
end
local isVisible = isTargetVisible(target)
if isVisible or distance < 20 then
local createPath = pfs:CreatePath({
AgentHeight = hum.HipHeight,
AgentRadius = 1.6,
AgentCanJump = true,
WaypointSpacing = math.huge
})
createPath:ComputeAsync(root.Position, targetRoot.Position)
for i, v in pairs(createPath:GetWaypoints()) do
if i ~= 1 then
if v.Action == Enum.PathWaypointAction.Jump then
hum.Jump = true
end
hum:MoveTo(v.Position)
hum.MoveToFinished:Wait()
end
end
end
elseif distance > 46.0 and chasing.Value then
lostTargetTime = now
chasing.Value = false
end
elseif chasing.Value then
chasing.Value = false
end
end)
task.spawn(function()
while true do
task.wait()
local target = currentTarget
if root.Anchored == false then
root:SetNetworkOwner(nil)
end
if target then
local targetRoot = target:FindFirstChild("HumanoidRootPart")
local targetHum = target:FindFirstChild("Humanoid")
if not targetRoot or not targetHum then continue end
local distance = (root.Position - targetRoot.Position).Magnitude
if distance < 5.8 then
if attack == false and canAttack.Value == true then
attack = true
if swingSound then
swingSound:Play()
end
local random = math.random(1, 2)
if targetHum.Health > damage.Value then
if random == 1 then
anims.aRight:Play()
else
anims.aLeft:Play()
end
elseif targetHum.Health <= damage.Value then
anims.aHeavy:Play()
end
task.wait(0.25)
if distance < 5.4 then
local hitSound = hitSounds[math.random(1, #hitSounds)]
if hitSound then
hitSound:Play()
end
targetHum:TakeDamage(damage.Value)
end
task.spawn(function()
task.wait(attackDelay.Value)
attack = false
end)
end
end
end
end
end)
SpeedMain
local npc = script.Parent
local hum = npc:WaitForChild("Monster")
if not hum:IsA("Humanoid") then
hum:Destroy()
error("Monster is not a Humanoid!")
end
local animator = hum:FindFirstChildOfClass("Animator")
local screamAnim = script:WaitForChild("Scream")
local scream = animator and screamAnim and animator:LoadAnimation(screamAnim)
local chasing = npc:WaitForChild("Chasing")
local rSpeed = npc.Configuration.RunSpeed
local wSpeed = npc.Configuration.WalkSpeed
local root = npc.HumanoidRootPart
local screamSound = npc:WaitForChild("Head"):WaitForChild("Rake_Scream")
local isScreaming = npc:FindFirstChild("IsScreaming") or Instance.new("BoolValue")
isScreaming.Name = "IsScreaming"
isScreaming.Value = false
isScreaming.Parent = npc
local function updateSpeed()
if isScreaming.Value then
hum.WalkSpeed = 0
elseif chasing.Value then
hum.WalkSpeed = rSpeed.Value
else
hum.WalkSpeed = wSpeed.Value
end
end
local function handleChasing()
if chasing.Value and not isScreaming.Value then
isScreaming.Value = true
if screamSound then screamSound:Play() end
if scream then
scream:Play()
scream.Stopped:Wait()
end
isScreaming.Value = false
end
updateSpeed()
end
chasing.Changed:Connect(handleChasing)
isScreaming.Changed:Connect(updateSpeed)
updateSpeed()