I have a script that updates every frame to cast a ray down and see if there is a ground under them. If so, it would fire a remote event to the server to update the server position. But if not, it would lerp the character down on the client until it finds a ground.
My code is very laggy with 50 NPC’s raycasting down every frame and I want a better way of doing this.
Client:
local RunService = game:GetService("RunService")
local character = script.Parent.Parent
local HumanoidRootPart = character:WaitForChild("HumanoidRootPart")
local lerpCoroutine = nil
local lerpSpeed = 200
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local function StopLerpCoroutine()
if lerpCoroutine and coroutine.status(lerpCoroutine) ~= "running" then
coroutine.close(lerpCoroutine)
lerpCoroutine = nil
end
end
local function GetGroundPosition()
local HipHeight = character:GetAttribute("HipHeight")
local rayOrigin = HumanoidRootPart.Position
local rayDirection = Vector3.new(0, -HipHeight, 0)
local raycast = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
if raycast then
local position = raycast.Position
return position
end
end
local function LerpToGround()
StopLerpCoroutine()
local origin = HumanoidRootPart.Position
local oldPos = origin
local foundGround = GetGroundPosition()
if not foundGround then
lerpCoroutine = coroutine.create(function()
repeat
origin = HumanoidRootPart.Position - Vector3.new(0, 1, 0)
local distance = (oldPos - origin).Magnitude
local timeToReachTarget = distance / lerpSpeed
local alpha = math.clamp(timeToReachTarget, 0, 1)
local lerp = oldPos:Lerp(origin, alpha)
character:MoveTo(lerp)
oldPos = HumanoidRootPart.Position
until GetGroundPosition()
local position = GetGroundPosition()
if position then
script.Parent.UpdateHeight:FireServer(position)
end
end)
coroutine.resume(lerpCoroutine)
else
script.Parent.UpdateHeight:FireServer(foundGround)
end
end
while true do
LerpToGround()
RunService.Heartbeat:Wait()
end
Server:
local character = script.Parent
script.UpdateHeight.OnServerEvent:Connect(function(_, position)
local HipHeight = character:GetAttribute("HipHeight")
local newPosition = position + Vector3.new(0, HipHeight, 0)
character:MoveTo(newPosition)
end)
Video: