So, recently, I tried to add a purely visual system that creates a bounding box in UI when player is near an object with assigned tag. It worked well with a couple of items, but in my game there could be hundreds of items with that tag. I knew that I would need optimization, but I was unable to decrease the script’s activity to less than 3%, and it peaks at 40% in actual gameplay.
So far I tried to get items with tags in a certain distance from the player on server, but that doesn’t update properly and firing a function every frame for 8 players doesn’t seem to benefit anything.
Here’s my code (in Local Script):
local camera = workspace.CurrentCamera
local player = game.Players.LocalPlayer
local ui = player.PlayerGui.BoundingBoxes
local originalFrame = ui.BoundingBoxOrig:Clone()
local rs = game:GetService("RunService")
local ts = game:GetService("TweenService")
local cs = game:GetService("CollectionService")
local d = game:GetService("Debris")
local createdFrames = {}
local createdAdornees = {}
local items = {}
local op1 = OverlapParams.new()
op1.FilterDescendantsInstances = {}
op1.FilterType = Enum.RaycastFilterType.Include
function removeFrame(f, pos)
table.remove(createdFrames, pos)
table.remove(createdAdornees, pos)
ts:Create(f, TweenInfo.new(0.125), {ImageTransparency = 1}):Play()
d:AddItem(f, 0.5)
end
function removeNotInWorld()
for pos, add in pairs(createdAdornees) do
if not add:IsDescendantOf(workspace) then
removeFrame(createdFrames[pos], pos)
end
end
end
function removeBox(thing)
local found = table.find(createdAdornees, thing)
if found then
removeFrame(createdFrames[found], found)
end
end
rs.PreRender:Connect(function()
removeNotInWorld()
for _, thing in pairs(cs:GetTagged("HasBoundingBoxUI")) do
if not thing:IsDescendantOf(workspace) then continue end
local actdistance = thing:GetAttribute("BBActivationDistance")
local usesphere = thing:GetAttribute("BBUseSphere")
local color = thing:GetAttribute("BBColor")
local screenPos
local cframe
local xdist
local ydist
local zdist
if usesphere then
op1.FilterDescendantsInstances = {thing}
local sphere = workspace:GetPartBoundsInRadius(
camera.CFrame.Position, actdistance, op1)
if #sphere == 0 then
removeBox(thing)
continue
end
elseif (cframe.Position - camera.CFrame.Position).Magnitude > actdistance then
removeBox(thing)
continue
end
if thing:IsA("Model") then
local bbframe, bbsize = thing:GetBoundingBox()
screenPos = camera:WorldToScreenPoint(bbframe.Position)
cframe = bbframe
xdist = bbsize.X / 2
ydist = bbsize.Y / 2
zdist = bbsize.Z / 2
else
screenPos = camera:WorldToScreenPoint(thing.Position)
cframe = thing.CFrame
xdist = thing.Size.X / 2
ydist = thing.Size.Y / 2
zdist = thing.Size.Z / 2
end
local creating = true
local frame = nil
local found = table.find(createdAdornees, thing)
if found then
creating = false
frame = createdFrames[found]
end
if creating then
frame = originalFrame:Clone()
frame.Parent = ui
frame.Visible = true
frame.ImageColor3 = color
frame.ImageTransparency = 1
frame.Name = "BoundingBox"
ts:Create(frame, TweenInfo.new(0.125), {ImageTransparency = 0.5}):Play()
table.insert(createdFrames, frame)
table.insert(createdAdornees, thing)
end
-- Yea this is bad
local verticies = {}
table.insert(verticies, cframe:ToWorldSpace(CFrame.new( xdist, -ydist, zdist)))
table.insert(verticies, cframe:ToWorldSpace(CFrame.new( xdist, ydist, zdist)))
table.insert(verticies, cframe:ToWorldSpace(CFrame.new(-xdist, -ydist, zdist)))
table.insert(verticies, cframe:ToWorldSpace(CFrame.new(-xdist, ydist, zdist)))
table.insert(verticies, cframe:ToWorldSpace(CFrame.new( xdist, -ydist, -zdist)))
table.insert(verticies, cframe:ToWorldSpace(CFrame.new( xdist, ydist, -zdist)))
table.insert(verticies, cframe:ToWorldSpace(CFrame.new(-xdist, -ydist, -zdist)))
table.insert(verticies, cframe:ToWorldSpace(CFrame.new(-xdist, ydist, -zdist)))
-- Point 1, Point 2
local boundingBox = {Vector2.new(screenPos.X, screenPos.Y), Vector2.new(screenPos.X, screenPos.Y)}
local visibleVerticies = 0
-- Yea this is also bad
for _, v in pairs(verticies) do
local vPos :Vector2, visible = camera:WorldToScreenPoint(v.Position)
if vPos.X < boundingBox[1].X then
boundingBox[1] = Vector2.new(vPos.X, boundingBox[1].Y)
end
if vPos.Y < boundingBox[1].Y then
boundingBox[1] = Vector2.new(boundingBox[1].X, vPos.Y)
end
if vPos.X > boundingBox[2].X then
boundingBox[2] = Vector2.new(vPos.X, boundingBox[2].Y)
end
if vPos.Y > boundingBox[2].Y then
boundingBox[2] = Vector2.new(boundingBox[2].X, vPos.Y)
end
if visible then visibleVerticies += 1 end
end
if visibleVerticies > 4 then
local pos = UDim2.fromOffset((boundingBox[1].X + boundingBox[2].X) / 2, (boundingBox[1].Y + boundingBox[2].Y) / 2)
local size = UDim2.new(0.05, boundingBox[2].X - boundingBox[1].X, 0.05, boundingBox[2].Y - boundingBox[1].Y)
frame.Position = pos
frame.Size = size
ts:Create(frame, TweenInfo.new(0.125), {ImageTransparency = 0.5}):Play()
else
ts:Create(frame, TweenInfo.new(0.125), {ImageTransparency = 1}):Play()
end
end
end)
Any help would be appreciated! (even if I would be recommended to throw this idea into the fire)