How to make a system that selects a block

Apologies if the title does not explain much. I’m making a destroy system that requires you to select a part that you’ve built. I need it so a selection box appears at selecting specific parts that you’ve built. I’ve tried some code but it doesn’t seem to work. I’d be really pleased if I’d gather some help.

1 Like

Heres some articles that should help!

Mouse | Roblox Creator Documentation (mouse.Hit) is what you need to use ( i believe )
Just create a selection box in a localscript on the object that was hit ( mouse.Hit ).

The knowledge you’ll need for this may include the following:

  1. UserInputService | Roblox Creator Documentation
  2. Mouse
  3. Highlighting Objects | Roblox Creator Documentation
  4. Tables | Roblox Creator Documentation

Basically what you want to do is have a table like so:

local Selected = {}

And then whenever the player selects a part (using Mouse | Roblox Creator Documentation if you want a quick and easy way and UserInputService if you want a more universal method) you can add it to the table. This would look something like this:

local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()

local Selected = {}

Mouse.Button1Down:Connect(function()
    local Target = Mouse.Target -- The part the mouse may be hovering over

    if Target and Target.Parent then
        Selected = {Target}
    else -- This else statement deselects all parts if we aren't clicking on any parts
        Selected = {}
    end
end)

However, what if you wish to select multiple parts? We need a way to easily do this if it is a feature you want. We can use the leftshift key to toggle this behavior. We will be using UserInputService | Roblox Creator Documentation to detect if this key is being pressed down. If it is then we will instead add the part to the selection rather than resetting it. This may look like this:

local UserInputService = game:GetService("UserInputService")

local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()

local Selected = {}

Mouse.Button1Down:Connect(function()
    local Target = Mouse.Target
    local SelectMultiple = UserInputService:IsKeyDown(Enum.Keycode.LeftShift) -- This will detect if we are holding down the leftshift

    local check = table.find(Selected, Target) -- This checks if the part is already in the table

    if Target and Target.Parent then
        if SelectMultiple then
            if check then -- If it is already selected then we remove it from the table
                table.remove(Selected, check) -- removes an already selected item
            else
                table.insert(Selected, Target) -- adds the part to the table
            end
        else
            Selected = {Target}
        end
    elseif not SelectMultiple then -- We have changed this so it doesn't deselect all the parts if we are trying to select multiple parts and did not select one
        Selected = {}
    end
end)

Great! Our code should be working now. However, there is one last thing that needs to be done. We need a way to visualize the parts selected to let the user know which ones are selected. Otherwise they may lose track of the parts they selected! We will do this using SelectionBox | Roblox Creator Documentation. If you want to add a system that also highlights the part the mouse is hovering over you can use Mouse | Roblox Creator Documentation, although you will have to make this on your own. Anyways, to do this we can use a function. This will help you later on if you need to use selection boxes in a different part of your code. Also, if we want to reduce the potential lag creating by instancing then we should keep track of the selection boxes not in use so we can use them later to prevent creating new ones. Here are two functions you can use to control what parts are highlighted:

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

P.S. - This code is untested and may not work. However, you should be able to get a general idea of what needs to happen to make a selection system

P.P.S. - If you want to use UserInputService instead of the Mouse object (I strongly recommend this) you can use UserInputService | Roblox Creator Documentation, UserInputService | Roblox Creator Documentation, and/or UserInputService | Roblox Creator Documentation to get the users mouse position. You will have to convert the Vector2 into a Vector3 though.

5 Likes

So shall I insert code to check which part you’ve selected?

I edited my original post. Also, what do you mean by this?

Do you mean should you use UserInputService in place of the Mouse object? If so then that’s up to you. Personally I’ve never cared enough to figure out how to convert a Vector2 into a Vector3, mostly because I just code for fun. I’ll probably learn one of these days though. I would encourage you to use UserInputService instead of the Mouse object though.

If you mean add a way to visualize what parts are selected then sure. You can add your own code or use the two functions I provided in my edited post.

EDIT: I just looked at the Selection Boxes link I provided to you in my post. You should check it out, as it apparently had a code sample for selecting parts as well.

Alright, I’ve tested my code and edited it to survive the infant mortality rate that code suffers from. I’ll also edit my original post so it doesn’t error if anyone in the future stumbles across this post and wants to use the code. Anyways, here’s the final script:

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) -- This will detect if we are holding down the leftshift

	local check = table.find(Selected, Target) -- This checks if the part is already in the table

	if Target and Target.Parent then
		if SelectMultiple then
			if check then -- If it is already selected then we remove it from the table
				UnhightlightPart(Target)
				table.remove(Selected, check) -- removes an already selected item
			else
				HightlightPart(Target)
				table.insert(Selected, Target) -- adds the part to the table
			end
		elseif not check then -- If it is not selected then we select it
			HightlightPart(Target)
			table.insert(Selected, Target) -- adds the part to the table
		end
	elseif not SelectMultiple then -- We have changed this so it doesn't deselect all the parts if we are trying to select multiple parts and did not select one
		for _,part in pairs(Selected) do
			UnhightlightPart(part)
		end

		table.clear(Selected)
	end
end)

You don’t even need table for that just store it in variable

local Selected
local Mouse = game:GetService("Players").LocalPlayer:GetMouse() 

if Selected ~= Mouse.Target and Mouse.Target ~= nil and Mouse.Target:IsA("BasePart") then
Selected = Mouse.Target
end

Only case I think you will ever need table for something like this is finding nearby parts but other than that well explained!

1 Like

I know, but this was meant to be more of a tutorial that steadily introduced each part. I used tables to help to allow for more customization. If they don’t need tables then they will still grasp the basic concepts and be able to edit it so that it only used one.

1 Like

It’s… a little complex but I’ll try cope

Can you maybe… compress the code or explain it more thourghly

This code is perfect for me! Except, one thing, my fps drops to 30 when I select multiple new parts in succession. I suspect it has to do something with the Instance.new("SelectionBox"), because the effect goes away once I have quite a few boxes stored up in my cache. Thanks!