My fps drops to around 40 and stays there for a few seconds after the game starts, and disabling the script fixes it, so I think it has to do something with the script.
My fps drops to around 30 when quickly selecting parts, but I think this is only caused by the Instance.new("SelectionBox"), because once they’re all in the ‘cache’ (once they’re all generated), it stops lagging.
local UserInputService = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Selected = {}
local Boxes = { InUse = {} , Cache = {} }
local function HightlightPart(part)
local box = table.remove(Boxes.Cache, 1) -- retrieves an unused selection box if there is one
if not box then -- creates a box if there wasn't one in the cache
box = Instance.new("SelectionBox")
box.LineThickness = 0.05
box.Adornee = part
box.Parent = workspace
end
box.Adornee = part
table.insert(Boxes.InUse, box)
end
local function UnhightlightPart(part)
local position, box
for i,selection in pairs(Boxes.InUse) do
if selection.Adornee == part then
position = i
box = selection
end
end
if box then
box.Adornee = nil
table.insert(Boxes.Cache, table.remove(Boxes.InUse, position))
end
end
Mouse.Button1Down:Connect(function()
local Target = Mouse.Target
local SelectMultiple = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
local check = table.find(Selected, Target)
if Target and Target.Parent then
if SelectMultiple then
if check then
UnhightlightPart(Target)
table.remove(Selected, check)
else
HightlightPart(Target)
table.insert(Selected, Target)
end
elseif (check and #Selected>1) or (not check) then -- deselects all except the one that was just clicked
for _,part in pairs(Selected) do
UnhightlightPart(part)
end
table.clear(Selected)
HightlightPart(Target)
table.insert(Selected, Target)
elseif check then -- deselects only the clicked one
UnhightlightPart(Target)
table.remove(Selected, check)
end
elseif not SelectMultiple then
for _,part in pairs(Selected) do
UnhightlightPart(part)
end
table.clear(Selected)
end
end)
Put this in a localscipt under StarterPlayerScripts (the character doesn’t spawn in my game)
I believe you overengineered it by adding a cache for the selection boxes. You also should’ve used a dictionary instead of an array because it would perform faster and easier to implement.
Code:
local UserInputService = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Boxes = {}
local function HightlightPart(part)
local box = Instance.new("SelectionBox")
box.LineThickness = 0.05
box.Adornee = part
box.Parent = workspace
Boxes[part] = box
end
local function UnhightlightPart(part)
Boxes[part]:Destroy()
Boxes[part] = nil
end
Mouse.Button1Down:Connect(function()
local Target = Mouse.Target
local SelectMultiple = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
if Target and Target.Parent then
local check = Boxes[Target]
if SelectMultiple then
if check then
UnhightlightPart(Target)
else
HightlightPart(Target)
end
else -- deselects all except the one that was just clicked
for part in Boxes do
UnhightlightPart(part)
end
HightlightPart(Target)
end
elseif not SelectMultiple then
for part in Boxes do
UnhightlightPart(part)
end
end
end)
Sorry for asking for the third time but why do you need to know the length of a dictionary? The functionality in your original code seems to exactly match the one in mine, so I have 0 clue what needs to be changed.
I can bet a lot of money that the functionality of your code does not exactly match my original
No worries though, I can show you
open up a new world and put my script into StarterPlayerScripts
and then spawn a bunch of parts in side by side
hold shift, and select all of them with my script, and then let go of shift, and click on an already selected part. All of them deselect but the part I just clicked
yours doesn’t do that
Thanks!
Wow! You’re right! Sorry about that! I assumed it didn’t work because I couldn’t really see any changes to it. Guess I lost money on that
Thank you so much!
I still feel like the logic could be simplified, especially at:
Mouse.Button1Down:Connect(function()
local Target = Mouse.Target
local SelectMultiple = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
if Target and Target.Parent then
local check = Boxes[Target]
if SelectMultiple then
if check then
UnhightlightPart(Target)
else
HightlightPart(Target)
end
else
for part in Boxes do
UnhightlightPart(part)
end
HightlightPart(Target)
end
elseif not SelectMultiple then
for part in Boxes do
UnhightlightPart(part)
end
end
end)
if SelectMultiple is false it deselects all highlights in all cases. So if we move it a bit we get:
Mouse.Button1Down:Connect(function()
local Target = Mouse.Target
local SelectMultiple = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
if not SelectMultiple then
for part in Boxes do
UnhightlightPart(part)
end
end
if Target and Target.Parent then
local check = Boxes[Target]
if SelectMultiple then
if check then
UnhightlightPart(Target)
else
HightlightPart(Target)
end
else
HightlightPart(Target)
end
end
end)
That’s better, but if we add function named ToggleHighlight we could condense the code further.
local function ToggleHighlight(part)
if Boxes[part] then
RemoveHighlight(part)
else
AddHighlight(part)
end
end
Mouse.Button1Down:Connect(function()
local Target = Mouse.Target
local SelectMultiple = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
if not SelectMultiple then
for part in Boxes do
UnhightlightPart(part)
end
end
if Target and Target.Parent then
if SelectMultiple then
ToggleHighlight(Target)
else
HightlightPart(Target)
end
end
end)
But now HighlightPart could be replaced with ToggleHighlight since all parts are deselected if we are not selecting multiple which would highlight the part when used with ToggleHighlight.
local function ToggleHighlight(part)
if Boxes[part] then
RemoveHighlight(part)
else
AddHighlight(part)
end
end
Mouse.Button1Down:Connect(function()
local Target = Mouse.Target
local SelectMultiple = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
if not SelectMultiple then
for part in Boxes do
UnhightlightPart(part)
end
end
if Target and Target.Parent then
ToggleHighlight(Target)
end
end)
The logic could still be streamlined a bit better by moving the loop into its own function:
local function UnhighlightAllParts()
for part in Boxes do
UnhighlightPart(part)
end
end
and with using a bit of Roblox Lua Style guide for naming and styling with some generally better naming we get:
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local localPlayer = Players.LocalPlayer
local mouse = localPlayer:GetMouse()
local boxes = {}
local function addHighlight(part)
boxes[part] = Instance.new("SelectionBox")
boxes[part].LineThickness = 0.05
boxes[part].Adornee = part
boxes[part].Parent = workspace
end
local function removeHighlight(part)
boxes[part]:Destroy()
boxes[part] = nil
end
local function toggleHighlight(part)
if boxes[part] then
removeHighlight(part)
else
addHighlight(part)
end
end
local function removeAllHighlights()
for part in boxes do
removeHighlight(part)
end
end
mouse.Button1Down:Connect(function()
local target = mouse.Target
local isSelectingMultiple = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
if not isSelectingMultiple then
removeAllHighlights()
end
if target and target.Parent then
toggleHighlight(target)
end
end)
is this better for fps? I feel like it might be slightly worse cuz there’s more functions to jump around to (if that makes sense). Because that’s my main focus, as I kinda want my friend to be able to play at 60 fps, and he has a laptop from the mid 2000s
oh, I also just realized something! When you click on an already selected part, but you aren’t holding the leftshift down, it doesn’t deselect it. That might be the only difference between yours and mine. Thanks!
Edit: There’s actually no need for that, but Imma just point that out
Oh, and by the way guys, there’s a limit on how many parts can be highlighted at a time (apparently 31) so there needs to be a way to limit it. Since this is waaay above my paygrade, I’d like y’all to figure out how to implement that, because I feel like anything I’d do would just ruin it :р https://create.roblox.com/docs/reference/engine/classes/Highlight
Actually, I just realized a more optimized solution.
The problem with counting like that is you’ll have to loop through every single instance in the dictionary to get a count, which is inefficient. A more optimized way would just to add and subtract from a counter variable.
Code:
local UserInputService = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local boxesCount = 0
local Boxes = {}
local function HightlightPart(part)
boxesCount += 1
local box = Instance.new("SelectionBox")
box.LineThickness = 0.05
box.Adornee = part
box.Parent = workspace
Boxes[part] = box
end
local function UnhightlightPart(part)
boxesCount -= 1
Boxes[part]:Destroy()
Boxes[part] = nil
end
Mouse.Button1Down:Connect(function()
local Target = Mouse.Target
local SelectMultiple = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
if Target and Target.Parent then
local check = Boxes[Target]
if SelectMultiple then
if check then
UnhightlightPart(Target)
else
HightlightPart(Target)
end
else -- deselects all except the one that was just clicked
for part in Boxes do
UnhightlightPart(part)
end
HightlightPart(Target)
end
elseif not SelectMultiple then
for part in Boxes do
UnhightlightPart(part)
end
end
print(boxesCount)
end)