Main Question:
What is the best way to
- Communicate server positions to client displays and
- Move the server and client positions in the most efficient way (BodyMovers, CFrames, Lerping, ect…).
I’ve looked at multiple sources such as the following…
Some topics I’ve found suggest to try doing fully client sided mobs and use the server to validate their positions, though the issue I’ve run into with this method is that it only really works for single players since you cannot have multiple mob AIs on each client and expect it to behave the same.
Another ideas is having the positions of the mobs stored in a server sided script, however this would require excessive RemoteEvent firing to update client sided things.
Currently I create a part which is the size of the mob’s model extents size and then load in the actual mob models on each client. I then use lerp
to move the server sided blocks around and have the client constantly lerp ~30% toward the server block’s CFrame every renderstep. This provides a fairly okay connection between the server and the client however it lags astronomically. I’ve also taken further measures to not lerp/show client sided mobs that are x
distance away or off the screen of the player. It has even gotten so bad that if I don’t let the client load in first the renderstep function will cause everything else to starve and never load the client.
Any suggestions?
Mob Ai (very basic for testing)
local subject = script.Parent
while true do
local randomCFrame = CFrame.new(Vector3.new(math.random(-100,100), subject.Position.Y, math.random(-100,100)))
local newCFrame = CFrame.new(randomCFrame.Position, (subject.Position - randomCFrame.Position).Unit * 1000)
local count = 0
subject.CFrame = CFrame.new(subject.Position, newCFrame.Position)
repeat
subject.CFrame = subject.CFrame:lerp(newCFrame, count)
count = count + 0.0001
wait()
until (subject.Position - newCFrame.Position).Magnitude <= 5
end
Client
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
local _mobs = game.ReplicatedStorage:WaitForChild("_mobs")
local Player = game.Players.LocalPlayer
local Camera = workspace.CurrentCamera
local Character = Player.Character or Player.CharacterAdded:Wait() -- Not actually using this, just yielding the code for added event
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local CurrentMobs = CollectionService:GetTagged("Mob")
local DisplayedMobs = {}
local MAX_DISTANCE = 100
function addMobVisual(mob)
local index, info = find(mob, DisplayedMobs, "mob")
if not index then
local visual = _mobs:FindFirstChild(mob.Name):Clone()
if not visual then warn(mob.Name.." model not found") return end
visual:SetPrimaryPartCFrame(mob.CFrame)
visual.Parent = workspace
local entry = {mob = mob, visual = visual}
table.insert(DisplayedMobs, entry)
else
if info.mob.CFrame ~= info.visual.PrimaryPart.CFrame then
if info.visual ~= nil then
info.visual:SetPrimaryPartCFrame(info.visual.PrimaryPart.CFrame:lerp(info.mob.CFrame, 0.35))
end
end
end
end
function checkDuplicate(mob, list)
for i,v in pairs(list) do
if v == mob then
return true
end
end
return false
end
function find(obj, list, prop)
for i,v in pairs(list) do
if not prop then
if v == obj then
return i,v
end
else
if v[prop] == obj then
return i,v
end
end
end
return false
end
function getNearbyMobs()
local nearby = {}
local toofar = {}
for i,v in pairs(CurrentMobs) do
local vector, onScreen = Camera:WorldToScreenPoint(v.Position)
if (v.Position - Player.Character.HumanoidRootPart.Position).Magnitude <= MAX_DISTANCE and onScreen then
table.insert(nearby, v)
else
table.insert(toofar, v)
end
end
return nearby, toofar
end
function watchMobs()
for i,v in pairs(CurrentMobs) do
local vector, onScreen = Camera:WorldToScreenPoint(v.Position)
if (v.Position - Player.Character.HumanoidRootPart.Position).Magnitude <= MAX_DISTANCE and onScreen then
spawn(function()
addMobVisual(v)
end)
else
local index, info = find(v, DisplayedMobs, "mob")
if index then
info.visual:Destroy()
DisplayedMobs[index] = nil
end
end
end
end
CollectionService:GetInstanceAddedSignal("Mob"):Connect(function(mob)
if not checkDuplicate(mob, CurrentMobs) then
table.insert(CurrentMobs, mob)
end
if (mob.Position - Player.Character.HumanoidRootPart.Position).Magnitude <= MAX_DISTANCE then
if not find(mob, DisplayedMobs) then
addMobVisual(mob)
end
end
end)
wait(5)
RunService.RenderStepped:Connect(function()
watchMobs()
end)