萝卜说 - 罗布乐思 - 口袋核心

查看: 1665|回复: 0

[讨论] 自动寻路NPC与追击,能够穿越各种障碍,有效防止卡顿滞后

[复制链接]

0

收听

0

听众

37

帖子

正式用户

Rank: 1

萝卜币
58
发表于 2021-6-17 10:23:45 | 显示全部楼层 |阅读模式
该源码是从国际服看到的,但是源码后一个致命的问题,想必不少用过寻路的开发者都遇到过,Ai运行一段时间就会出现滞后,每走一步就卡顿大概0.1秒,这里我用设置网络所有权解决了,顺便用国际友人的源码加上我对源码的一些修改,解决了卡顿问题。
源码:
local myHuman = script.Parent:WaitForChild("Humanoid")
local myRoot = script.Parent:WaitForChild("HumanoidRootPart")
local head = script.Parent:WaitForChild("Head")
local lowerTorso = script.Parent:WaitForChild("LowerTorso")

--local grab = script.Parent:WaitForChild("Grab")
--local grabAnim = myHuman:LoadAnimation(grab)
--grabAnim.Priority = Enum.AnimationPriority.Action

--local grabSound = head:WaitForChild("Attack")
--local screamSound = head:WaitForChild("Scream")

local clone = script.Parent:Clone()
--设置网络所有权,防止滞后,也就是防止NPC走一步就卡一下
for _, object in pairs(script.Parent:GetChildren()) do
        if object:IsA("BasePart") then
                object:SetNetworkOwner()
        end
end
function walkRandomly()
        local xRand = math.random(-50,50)
        local zRand = math.random(-50,50)
        local goal = myRoot.Position + Vector3.new(xRand,0,zRand)

        local path = game:GetService("PathfindingService"):CreatePath()
        path:ComputeAsync(myRoot.Position, goal)
        local waypoints = path:GetWaypoints()

        if path.Status == Enum.PathStatus.Success then
                for _, waypoint in ipairs(waypoints) do
                        if waypoint.Action == Enum.PathWaypointAction.Jump then
                                myHuman.Jump = true
                        end
                        myHuman:MoveTo(waypoint.Position)
                        local timeOut = myHuman.MoveToFinished:Wait(1)
                        if not timeOut then
                                print("Got stuck")
                                myHuman.Jump = true
                                walkRandomly()
                        end
                end
        else
                print("Path failed")
                wait(1)
                walkRandomly()
        end
end

function findPath(target)
        local path = game:GetService("PathfindingService"):CreatePath()
        path:ComputeAsync(myRoot.Position,target.Position)
        local waypoints = path:GetWaypoints()

        if path.Status == Enum.PathStatus.Success then
                for _, waypoint in ipairs(waypoints) do
                        if waypoint.Action == Enum.PathWaypointAction.Jump then
                                myHuman.Jump = true
                        end
                        myHuman:MoveTo(waypoint.Position)
                        local timeOut = myHuman.MoveToFinished:Wait(1)
                        if not timeOut then
                                myHuman.Jump = true
                                print("Path too long!")
                                findPath(target)
                                break
                        end
                        if checkSight(target) then
                                repeat
                                        print("Moving directly to the target")
                                        myHuman:MoveTo(target.Position)
                                        attack(target)
                                        wait(0.1)
                                        if target == nil then
                                                break
                                        elseif target.Parent == nil then
                                                break
                                        end
                                until checkSight(target) == false or myHuman.Health < 1 or target.Parent.Humanoid.Health < 1
                                break
                        end
                        if (myRoot.Position - waypoints[1].Position).magnitude > 20 then
                                print("Target has moved, generating new path")
                                findPath(target)
                                break
                        end
                end
        end
end

function checkSight(target)
        local ray = Ray.new(myRoot.Position, (target.Position - myRoot.Position).Unit * 40)
        local hit,position = workspace:FindPartOnRayWithIgnoreList(ray, {script.Parent})
        if hit then
                if hit:IsDescendantOf(target.Parent) and math.abs(hit.Position.Y - myRoot.Position.Y) < 3 then
                        print("I can see the target")
                        return true
                end
        end
        return false
end

function findTarget()
        local dist = 50
        local target = nil
        local potentialTargets = {}
        local seeTargets = {}
        for i,v in ipairs(workspace:GetChildren()) do
                local human = v:FindFirstChild("Humanoid")
                local torso = v:FindFirstChild("Torso") or v:FindFirstChild("HumanoidRootPart")
                if human and torso and v.Name ~= script.Parent.Name then
                        if (myRoot.Position - torso.Position).magnitude < dist and human.Health > 0 then
                                table.insert(potentialTargets,torso)
                        end
                end
        end
        if #potentialTargets > 0 then
                for i,v in ipairs(potentialTargets) do
                        if checkSight(v) then
                                table.insert(seeTargets, v)
                        elseif #seeTargets == 0 and (myRoot.Position - v.Position).magnitude < dist then
                                target = v
                                dist = (myRoot.Position - v.Position).magnitude
                        end
                end
        end
        if #seeTargets > 0 then
                dist = 200
                for i,v in ipairs(seeTargets) do
                        if (myRoot.Position - v.Position).magnitude < dist then
                                target = v
                                dist = (myRoot.Position - v.Position).magnitude
                        end
                end
        end
        if target then
                if math.random(20) == 1 then
                        --screamSound:Play()
                end
        end
        return target
end

function attack(target)
        if (myRoot.Position - target.Position).magnitude < 5 then
                --grabAnim:Play()
                --grabSound:Play()
                if target.Parent ~= nil then
                        target.Parent.Humanoid:TakeDamage(25)
                end
                wait(0.4)
        end
end

function died()
        wait(5)
        clone.Parent = workspace
        game:GetService("Debris"):AddItem(script.Parent,0.1)
end

myHuman.Died:Connect(died)

lowerTorso.Touched:Connect(function(obj)
        if not obj.Parent:FindFirstChild("Humanoid") then
                myHuman.Jump = true
        end
end)

function main()
        local target = findTarget()
        if target then
                myHuman.WalkSpeed = 16
                findPath(target)
        else
                myHuman.WalkSpeed = 8
                walkRandomly()
        end
end

while wait(0.1) do
        if myHuman.Health < 1 then
                break
        end
        main()
end
解决滞后的代码:
--设置网络所有权,防止滞后,也就是防止NPC走一步就卡一下
for _, object in pairs(script.Parent:GetChildren()) do
        if object:IsA("BasePart") then
                object:SetNetworkOwner()
        end
end
AI源码经过本人修改过小部分,目的是不需要加入任何东西就能让AI跑起来,解决滞后的代码是自己加进去的。
感谢国际友人AI源码,源码原帖子:https://devforum.roblox.com/t/my-pathfinding-zombie-does-not-work/1234091
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋| |京公网安备11010502045240号

Copyright © 2001-2013 Comsenz Inc.   All Rights Reserved.

Powered by Discuz! X3.4  备案:京ICP备2021013067号-2

快速回复 返回顶部 返回列表