Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

[SOLVED] Why does the Monster AI doesn't chase when a player is near?

Asked by 1 year ago
Edited 1 year ago

I am making the AI for the monster in my horror maze game. It works fine, but it follows the waypoint instead of chasing me when I get close. And the AI keeps bumping into walls when they can choose a longer way to get to that waypoint without bumping in walls.

Here is the video recording, the photo of all waypoints in the maze, and the AI Script:

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local monster = script.Parent
local monsterHumanoid = monster:WaitForChild("Humanoid")
local monsterWaypoints = workspace:WaitForChild("MonsterWaypoints")
local monsterRoot = monster:WaitForChild("HumanoidRootPart")

for index, bodyPart in pairs(monster:GetDescendants()) do
    if bodyPart:IsA("BasePart") then
        bodyPart:SetNetworkOwner(nil)
    end
end

local function CheckIfAlive(character)
    if ((character ~= nil) and (Players:GetPlayerFromCharacter(character) ~= nil) and (character:FindFirstChild("Head") ~= nil) and (character:FindFirstChild("HumanoidRootPart") ~= nil) and (character:FindFirstChildOfClass("Humanoid") ~= nil) and ((character:FindFirstChildOfClass("Humanoid")).Health > 0)) then
        return true
    end
end

local function CanSeeTarget(target)
    local origin = monsterRoot.Position
    local direction = (target:WaitForChild("HumanoidRootPart").Position - monsterRoot.Position).Unit * 40
    local ray = Ray.new(origin, direction)

    local hit, pos = workspace:FindPartOnRay(ray, monster)

    if (hit ~= nil) then
        if hit:IsDescendantOf(target) then
            return true
        end
    else
        return false
    end
end

local function FindTarget()
    local maxDistance = 40
    local nearestTarget

    for index, player in pairs(Players:GetPlayers()) do
        local character = player.Character or player.CharacterAdded:Wait()

        if (character ~= nil) then
            local target = character
            local distance = (monsterRoot.Position - character:WaitForChild("HumanoidRootPart").Position).Magnitude

            if (distance < maxDistance) and (CanSeeTarget(target) == true) then
                nearestTarget = target
                maxDistance = distance
            end
        end
    end

    return nearestTarget
end

local function GetPath(destination)
    local agentParameters = {
        ["AgentHeight"] = 5,
        ["AgentRadius"] = 4,
        ["AgentCanJump"] = false,
        ["Costs"] = {
            ["SafeSpot"] = math.huge
        }
    }

    local path = PathfindingService:CreatePath(agentParameters) 
    path:ComputeAsync(monsterRoot.Position, destination.Position)

    return path
end

function Attack(target)
    local distance = (monsterRoot.Position - target:WaitForChild("HumanoidRootPart").Position).Magnitude

    if distance > 4 then
        monsterHumanoid:MoveTo(target:WaitForChild("HumanoidRootPart").Position)
    else
        target:FindFirstChildOfClass("Humanoid"):TakeDamage(target:FindFirstChildOfClass("Humanoid").MaxHealth)
    end
end

function WalkTo(destination)
    local path = GetPath(destination)

    if path.Status == Enum.PathStatus.Success then
        for index, waypoint in pairs(path:GetWaypoints()) do
            local target = FindTarget()

            if (target ~= nil) and (CheckIfAlive(target) == true) then
                Attack(target)
                break
            else
                monsterHumanoid:MoveTo(waypoint.Position)
                monsterHumanoid.MoveToFinished:Wait()
            end
        end
    else
        monsterHumanoid:MoveTo((destination.Position - (monsterRoot.CFrame.LookVector * 10)))
    end
end

function Patrol()
    local waypoints = monsterWaypoints:GetChildren()
    local randomWaypoint = waypoints[math.random(1, #waypoints)]
    WalkTo(randomWaypoint)
end

while true do
    task.wait()
    Patrol()
end
0
Check in the script if you haven't set something that makes the AI moving to the waypoint. DarkSide_091 0 — 1y
0
I literally checked everything in the script and everything’s fine. That’s why I’m asking for help. If I had knew already I would’ve not created this question in the first place. T3_MasterGamer 2189 — 1y
0
you might want to disable the function patrol when pathfinding to the player Puppynniko 1059 — 1y
0
the patrol function should be activated when Target == nil so it does not interfere with the pathfinding to the target Puppynniko 1059 — 1y
View all comments (2 more)
0
ok thx i’ll try that T3_MasterGamer 2189 — 1y
0
puppynniko thx for the help, it worked :) T3_MasterGamer 2189 — 1y

1 answer

Log in to vote
0
Answered by 1 year ago
Edited 1 year ago

I finally fixed it! @Puppynniko suggested detecting if the target is nill or not in the patrol function, and it worked! Thanks to @Puppynniko! This is my new AI script:

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local monster = script.Parent
local monsterHumanoid = monster:WaitForChild("Humanoid")
local monsterWaypoints = workspace:WaitForChild("MonsterWaypoints")
local monsterRoot = monster:WaitForChild("HumanoidRootPart")

local chasing = false
local hipHeight = monsterHumanoid.HipHeight
local HitboxLength = 4

local agentParameters = {
    ["AgentHeight"] = ((hipHeight > 0 and hipHeight) or 5),
    ["AgentRadius"] = (monsterRoot.Size.X or 2),
    ["AgentCanJump"] = false,
    ["Costs"] = {
        ["SafeSpot"] = math.huge
    }
}

for index, bodyPart in pairs(monster:GetDescendants()) do
    if bodyPart:IsA("BasePart") or bodyPart:IsA("MeshPart") or bodyPart:IsA("UnionOperation") then
        bodyPart:SetNetworkOwner(nil)
    end
end

local function CheckIfAlive(character)
    if ((character ~= nil) and (Players:GetPlayerFromCharacter(character) ~= nil) and (character:FindFirstChild("Head") ~= nil) and (character:FindFirstChild("HumanoidRootPart") ~= nil) and (character:FindFirstChildOfClass("Humanoid") ~= nil) and ((character:FindFirstChildOfClass("Humanoid")).Health > 0)) then
        return true
    else
        return false
    end
end

local function CheckIfTargetIsSafe(target)
    if (target ~= nil) and (Players:GetPlayerFromCharacter(target) ~= nil) and (target:FindFirstChild("Head") ~= nil) and (target:FindFirstChild("HumanoidRootPart") ~= nil) and (target:FindFirstChildOfClass("Humanoid") ~= nil) then
        if Players:GetPlayerFromCharacter(target):FindFirstChild("Safe") then
            if Players:GetPlayerFromCharacter(target):FindFirstChild("Safe").Value == true then
                return true
            else
                if target:FindFirstChildOfClass("ForceField") then
                    return true
                else
                    return false
                end
            end
        else
            if target:FindFirstChildOfClass("ForceField") then
                return true
            else
                return false
            end
        end
    else
        return false
    end
end

local function CanSeeTarget(target)
    local origin = monsterRoot.Position
    local direction = (target:WaitForChild("HumanoidRootPart").Position - monsterRoot.Position).Unit * 1000
    local ray = Ray.new(origin, direction)

    local hit, pos = workspace:FindPartOnRayWithIgnoreList(ray, {monster})

    if hit then
        if hit:IsDescendantOf(target) then
            if target:FindFirstChildOfClass("ForceField") then
                return true
            else
                local plr = Players:GetPlayerFromCharacter(target)

                if plr then
                    local safeValue = plr:FindFirstChild("Safe")

                    if safeValue then
                        if safeValue.Value == false then
                            return true
                        else
                            return false
                        end
                    else
                        return false
                    end
                else
                    return false
                end
            end
        end
    else
        return false
    end
end

local function FindTarget()
    local maxDistance = 10000
    local nearestTarget

    for index, player in pairs(Players:GetPlayers()) do
        local character = player.Character or player.CharacterAdded:Wait()

        if character then
            local target = character
            local distance = (monsterRoot.Position - character:WaitForChild("HumanoidRootPart").Position).Magnitude

            if (distance < maxDistance) and (CanSeeTarget(target) == true) then
                nearestTarget = target
                maxDistance = distance
            end
        end
    end

    return nearestTarget
end

local function GetPath(destination)
    local path = PathfindingService:CreatePath(agentParameters) 
    path:ComputeAsync(monsterRoot.Position, destination.Position)

    return path
end

function Attack(target)
    local distance = (monsterRoot.Position - target:WaitForChild("HumanoidRootPart").Position).Magnitude

    if distance > (HitboxLength or 1) then
        monsterHumanoid:MoveTo(target:WaitForChild("HumanoidRootPart").Position)
    else
        target:FindFirstChildOfClass("Humanoid"):TakeDamage(target:FindFirstChildOfClass("Humanoid").MaxHealth)
    end
end

function WalkTo(destination)
    local path = GetPath(destination)

    if path.Status == Enum.PathStatus.Success then
        for index, waypoint in pairs(path:GetWaypoints()) do
            local target = FindTarget()

            if target and CanSeeTarget(target) and (CheckIfAlive(target) == true) and (CheckIfTargetIsSafe(target) == false) then
                break
            else
                monsterHumanoid:MoveTo(waypoint.Position)
                monsterHumanoid.MoveToFinished:Wait()
            end
        end
    else
        monsterHumanoid:MoveTo((destination.Position - (monsterRoot.CFrame.LookVector * 10)))
    end
end

function Patrol()
    local target = FindTarget()

    if target and CanSeeTarget(target) and (CheckIfAlive(target) == true) and (CheckIfTargetIsSafe(target) == false) then
        Attack(target)
    else
        local waypoints = monsterWaypoints:GetChildren()
        local randomWaypoint = waypoints[math.random(1, #waypoints)]
        WalkTo(randomWaypoint)
    end
end

while true do
    task.wait()
    Patrol()
end

Also, you can use this script too to make your own Monster AI! Don't exactly copy-paste mine because it could cause errors.

If you're wondering what game it is, here's the game!

Ad

Answer this question