Hello, I am trying to make a game where there is an enemy npc that is using raycast to detect whenever the npc can see the player. If the npc loses sight of the player, it will start a countdown to delete the npc. However, if the npc can see the player again, I would want to cancel the countdown and make the npc resume chasing the player and avoid deletion. How do I achieve this?
Here is the script:
local function canSeeTarget(target)
local origin = killer.HumanoidRootPart.Position
local direction = (target.HumanoidRootPart.Position - killer.HumanoidRootPart.Position).unit * 100
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
rayParams.FilterDescendantsInstances = {game.Workspace.Foliage:GetChildren(), game.Workspace["OutsideShed/Fence"].ShedItself:GetChildren()}
local rayCastResult = workspace:Raycast(origin, direction, rayParams)
if rayCastResult and rayCastResult.Instance then
if rayCastResult.Instance:IsDescendantOf(target) then
FirstSight = true
LostSight = false
CountDown = false
print("Player spotted")
return true
else
LostSight = true
CountDown = true
if FirstSight == true then
print("player lost")
while CountDown do
for i = 4, 0 , -1 do
if CountDown then
print(i.." seconds before deletion")
task.wait(1)
else
break
end
--[[if i == 0 then
Deletion = true
print("killer will be deleted")
else
CountDown = false
Deletion = false
break
end]]
end
task.wait()
end
end
end
else
return false
end
end
I appreciate any help/advice I can receive for this. Thank you.
There is no error. The script endlessly counts down from 4 to 0 seconds if the npc cannot see the player and npc does not continue pursuing the player until it reaches zero seconds. I would like to break/stop the countdown mid countdown so it can continue chasing the player.
It seems to be working though, it’s just the main problem here is I don’t know how to break the for loop mid countdown, it has to finish the countdown before the npc checks to see if they can see the player again and continue chasing. I would like for the npc to be able to chase the player immediately once they can see them and cancel out the countdown so the npc doesn’t end up getting deleted.
Yes. Once the countdown reaches zero, the npc chases the player, I would want it to do it mid countdown to cancel it. Since once it reaches zero, I will be making the npc get deleted. So basically I want the npc to avoid deletion if they can see the player and get deleted if they can’t see any player in 4 seconds.
So this is what I see wrong, you’re using a loop for an “for loop” so remove the “while countdown do” then I’d would add a If statement, checking if the Countdown is set to true and if so then return to the chasing part.
local function canSeeTarget(target)
local origin = killer.HumanoidRootPart.Position
local direction = (target.HumanoidRootPart.Position - killer.HumanoidRootPart.Position).unit * 100
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
rayParams.FilterDescendantsInstances = {game.Workspace.Foliage:GetChildren(), game.Workspace["OutsideShed/Fence"].ShedItself:GetChildren()}
local rayCastResult = workspace:Raycast(origin, direction, rayParams)
if rayCastResult and rayCastResult.Instance then
if rayCastResult.Instance:IsDescendantOf(target) then
FirstSight = true
LostSight = false
print("Player spotted")
return true
else
LostSight = true
if FirstSight == true then
print("player lost")
local timer
timer = task.defer(function()
for i = 4, 0 , -1 do
if LostSight and i > 0 then
print(i.." seconds before deletion")
task.wait(1)
elseif i <= 0 then
print("Countdown ended")
--// Do your deletion
timer:Disconnect()
elseif not LostSight then
timer:Disconnect()
end
end
end)
end
end
else
return false
end
end
I’m unable to test this in studio because I don’t have the models, but let me know if it works! Note: defer is delayed a cycle for performance, if you want it to be immediate use task.spawn()
You should use tick() to check for the elasped time since something happened, instead of having a for loop countdown,
With this usage, you dont have to reset the loop, and you can simply set the time to now, and then check for a specific number under that elapsed time.
Another thing you can do is utilize task or coroutines, and cancel ir using task.cancel or coroutine.close.
I tried using tick() and it seems to be the closest I’ve gotten to getting it to work, however the very first time the enemy loses sight of the player, it errors. The 2nd time it loses sight of the player, it works just fine. I’ve tried reordering stuff around a bunch of times and honestly I’m out of ideas at this point.
Here’s the changed script:
local function canSeeTarget(target)
local origin = killer.HumanoidRootPart.Position
local direction = (target.HumanoidRootPart.Position - killer.HumanoidRootPart.Position).unit * 100
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
rayParams.FilterDescendantsInstances = {game.Workspace.Foliage:GetChildren(), game.Workspace["OutsideShed/Fence"].ShedItself:GetChildren()}
local rayCastResult = workspace:Raycast(origin, direction, rayParams)
if rayCastResult and rayCastResult.Instance then
if rayCastResult.Instance:IsDescendantOf(target) then
FirstSight.Value = true
LostSight = false
CountDown.Value = false
print("Player spotted")
return true
else
LostSight = true
CountDown.Value = true
if FirstSight.Value == true then
print("player lost")
CountDown:GetPropertyChangedSignal("Value"):Connect(function()
if CountDown.Value == true and LostSight == true then
CountStarter = tick()
print("count started")
elseif CountDown.Value == false and LostSight == false then
countDownSeconds = (tick() - CountStarter)
print(countDownSeconds)
end
end)
--[[if CountDown and LostSight == true then
coroutine.resume(countDownCorountine)
elseif CountDown == false then
coroutine.yield(countDownCorountine)]]
--[[for i = 4, 0 , -1 do
if CountDown == true and LostSight == true then
print(i.." seconds before deletion")
task.wait(1)
elseif CountDown == false and LostSight == false then
break
end
end]]
end
end
else
return false
end
end
And there’s the screenshot of the error I receive. As I said, it errors on first time the enemy loses sight of player, but works as it should if enemy loses sight of player the 2nd time.