How do you detect parts around another part with a certain radius?

I know that I can use .Magnitude, but, I think .Magnitude can only work by directly referencing parts. Another reason is that there are going to be so many parts and referencing each one is going to be such a pain. I cannot use partsinregion because the part is moving. Here’s a quick(yet awesome) illustration:

Is there any way of doing it? The blue is the radius, the part highlighted in blue is the part that does the detection, the parts that are highlighted in yellow are the detected parts.

2 Likes

A potential solution after a small amount of digging is to:

  1. Create a circular part that covers the size of your radius and weld it to your “blue” part.
  2. Set the CanCollide to false, and then use the GetTouchingParts method to discover what parts it is intersecting.
  3. You need to add a touch interest for the non-collidable circle to be able to trigger collisions with other parts.

See https://developer.roblox.com/en-us/api-reference/function/BasePart/GetTouchingParts

I will continue looking for another solution if you do not like this method.

4 Likes

I would recommend using GetTouchingParts() and magnitude checking to detect those parts.

You can define the hitbox of the radius using a sphere or block, and run the GetTouchingParts() function to retrieve a table of all objects that are intersecting the hitbox.

If it is cancollide == false, then read this helpful article

Because hitboxes are naturally square, you can use .magnitude to compare the distance in relation to the origin/position of the hitbox.

Hope this helped

2 Likes
2 Likes

@overflowed @Hazania
how can I do it so, that, if I have multiple parts in a model, and I only want one of them to be detected, how would I do that?

I would suggest setting a PrimaryPart for each model, and ignore any other parts that are part of model (but not the PrimaryPart) using an if statement.

Edit: If that is not feasible due to the amount of models in your game, you could alternatively loop through all the parts found and ignore any extra parts that pertain to the same model a part was already found in.

1 Like

what if I wanted to have all of them to be touched, but if they are in the same model, it only fires once?

Muahahahaha…

The cursed knowledge presents itself to you…

( Probably don’t use this lol, just funny that it happened to come up. )

3 Likes

When using GetTouchingParts(), you cannot ignore any of the parts that are touching it. What you can do is use if statements to ignore any parts that pertain to a model that was already found by another part.

Edit: Would you like an example?

local objectsFound = {}
for i, part in pairs(partToCheck:GetTouchingParts()) do
    if part.Parent:IsA(“Model”) then
        local foundObject = false
        for i, object in pairs(objectsFound) do
            if object == part.Parent then
                foundObject = true
                break
            end
        end
        if not foundObject then
            table.insert(objectsFound, part.Parent)
        end
    else
        table.insert(objectsFound, part)
    end
end

This example would assume that all of your models do not go deeper than 1 child (if you have parts within parts within models, you will need to check for more than just one parent up to see if it is within a model, potentially by using the IsDescendentOf() method or the FindFirstAncestorWhichIsA() method.

Edit: The objectsFound table is going to be a list of your parts found, no more than one part per model. Your blue part will be one of these, you probably want to add an if statement to ignore that part as well.

1 Like

Is there any way to make it more efficient/ less resource intensive?

It is probably most efficient to just use all the parts found rather than eliminate repeating model’s parts considering this is going to be checked very frequently as the “blue part” moves.

Why is it important for you to only get one part per model, if you don’t mind me asking? This may help with me determining the best solution for this problem.

4 Likes

Suuuper sorry for the late reply. Here is the function that I use to check collisions:

Similarly to @Hazania’s reply, I use sanity checking to filter out parts. If you only want to detect a single part within a model, you can set its name to a specific name that makes it easily distinguishable in a script

local desiredpartname = "name of part you want to detect in the function"
local connection = hitbox.Touched:Connect(function() end) --just in case your parts' collisions are off
local touching = hitbox:GetTouchingParts() --gettouchingparts() will return a table of everything intersecting the part
if touching ~= nil then
    for _,detected in ipairs(touching) do --I personally use ipairs to skip anything that may have become nil at the time of running the function
        if detected.Name == desiredpartname then
            --run function or whatever here
        end
    end
end
4 Likes

Bless you for using ipairs. I don’t think it should really be about potential nils but rather what you’re iterating over and understanding the difference between ipairs/pairs. ipairs should be used for arrays.

ipairs is designed to iterate over arrays, where the keys are numeric and incremental from 1 to the length of the table. Therefore, your iterations are occurring where your keys are known at [i+1]. It is also, compared to the old VM, significantly faster. A benchmark reading at RDC showed around 6.49 speedup.

pairs should be used in cases where you’re working with dictionaries, or otherwise where your keys are not known from the beginning and can be arbitrary. pairs calls next and gets the next element based on the last key.

Another thing: ipairs will iterate your elements in order. Order is not guaranteed nor known when it comes to pairs-based iteration. Even if you have numeric keys and you use pairs, it will not default to incremental iteration. There may be some cases where order is important!

:slightly_smiling_face:

5 Likes

I actually forgot all about ipairs! Thank you for all of that info, I was pleasantly surprised. :grin:

Ok, how do I add a touch interest? I cannot find it. Sorry, this just occurred because I forgot that I needed to set the can collide to false.

Touch Interests are created automatically by connecting a BasePart to a Touched or Touch Ended event.

https://developer.roblox.com/en-us/api-reference/class/TouchTransmitter

But how would I implement that as GetTouchingParts() ?

It’s kind of a strange situation where you don’t need to connect a .Touched event, but you will have to anyways to create a Touch Interest.

Sadly, I don’t think there is another way to get one.

I would just create a .Touched event connected to the invisible part you made and let it be; it’s a waste, but it’s not going to be hampering performance.

2 Likes

If I don’t have .Touched it still detects what is touching it, but says that it is nil