I’m currently trying to make a VR grab system, but encountering a problem. I made a table that is automatically empty that will later contain the distances between a close grabbable object and the players hand. Whenever I add a distance number to the table, it assigns it a key, making it a dictionary. Just so I can grab the closest object, I unpack the table and use math.min to get the smallest distance, giving me which object is closest. But table.unpack only works with arrays, not dictionaries.
I’ve tried adding a key and that is the distance number and assigning its value to nil, but that just gives me a blank table.
local Grabbables = script:FindFirstChild("Grabbables")
local maxDistance = 1
local objectDistances = {} --> All objects that are grabbable and close to the hand that includes their distances
--local numDistances = {} --> All distances in a simply array for later reference
local objectToGrab = nil
local handGrabbingWith = nil
--> 1. Get all objects within radius of hand
local function checkHandRadius(hand)
local PartsInRadius = game.Workspace:GetPartBoundsInRadius(hand.Position, maxDistance)
for _, v in pairs(PartsInRadius) do --> Checks for parts within hand radius
local grabbable = v:FindFirstChild("grabbable")
if (grabbable) and grabbable:IsA("BoolValue") then --> Checks whether one of the objects is grabbable
if v:FindFirstChild("grabbable").Value then
local distance = (v.Position - hand.Position).Magnitude --> Distance between the object and the hand
if not Grabbables:FindFirstChild(v.Name) then --> Checks if the object doesn't exist yet in the table
--> Temporary value for object
local TempValue = Instance.new("NumberValue")
TempValue.Name = v.Name
TempValue.Value = distance
TempValue.Parent = Grabbables
else
local TempValue = Grabbables[v.Name]
TempValue.Value = distance
end
objectDistances[distance] = nil --> Adds object's distance to table
end
end
end
return
end
coroutine.wrap(function()
while true do
checkHandRadius(leftHand)
checkHandRadius(rightHand)
wait()
end
end)()
Grabbables.ChildAdded:Connect(function()
--> Get closest object
print(table.unpack(objectDistances)) --> PRINTS BLANK
local smallestDistance = math.min( --> MISSING ARGUMENT #1 (NUMBER EXPECTED)
table.unpack(objectDistances)
)
for object, distance in pairs(objectDistances) do
if distance == smallestDistance then
print("found closest object!")
objectToGrab = object
--> Create highlight for the object
local Highlight = Instance.new("Highlight")
Highlight.FillColor = Color3.fromRGB(
0,
255,
255
)
Highlight.FillTransparency = 0
Highlight.OutlineTransparency = 1
Highlight.Parent = objectToGrab
end
end
end)
Wasted my time also reformatting this and fixing performance issues. Hope this works.
local Grabbables = script:FindFirstChild("Grabbables")
local maxDistance = 1
local objectDistances = {} --> All objects that are grabbable and close to the hand that includes their distances
--local numDistances = {} --> All distances in a simply array for later reference
local objectToGrab = nil
local handGrabbingWith = nil
--> 1. Get all objects within radius of hand
local function checkHandRadius(hand)
local PartsInRadius = game.Workspace:GetPartBoundsInRadius(hand.Position, maxDistance)
for _, v in pairs(PartsInRadius) do --> Checks for parts within hand radius
local grabbable = v:FindFirstChild("grabbable")
if (grabbable) and grabbable:IsA("BoolValue") then --> Checks whether one of the objects is grabbable
if v:FindFirstChild("grabbable").Value then
local distance = (v.Position - hand.Position).Magnitude --> Distance between the object and the hand
if not Grabbables:FindFirstChild(v.Name) then --> Checks if the object doesn't exist yet in the table
--> Temporary value for object
local TempValue = Instance.new("NumberValue")
TempValue.Name = v.Name
TempValue.Value = distance
TempValue.Parent = Grabbables
else
local TempValue = Grabbables[v.Name]
TempValue.Value = distance
end
objectDistances[distance] = grabbable --> Adds object's distance to table
end
end
end
return
end
local handle --> Use :Disconnect() on this to stop checking hands (if necessary)
local checkTimer = 0
local checkDelay = 10 --> This checks both hands every 10 frames
handle = game:GetService("RunService").RenderStepped:Connect(function()
if checkTimer < (checkDelay - 1) then checkTimer += 1
else
checkTimer = 0
checkHandRadius(leftHand)
checkHandRadius(rightHand)
end
end)
Grabbables.ChildAdded:Connect(function()
--> Get closest object
local closestDistance = maxDistance
for distance, grabbable in objectDistances do
closestDistance = math.min(closestDistance,distance)
end
local closestObject = objectDistances(closestDistance)
--> Create highlight for the object
local Highlight = Instance.new("Highlight")
Highlight.FillColor = Color3.fromRGB(0, 255, 255)
Highlight.FillTransparency = 0
Highlight.OutlineTransparency = 1
Highlight.Parent = closestObject
end)
I modified the code and was able to get the highlight working, but now I have to remove the highlight when the object leaves the part’s radius. Also for some reason, TWO parts are highlight instead of one.
local Grabbables = script:FindFirstChild("Grabbables")
local maxDistance = 2
local objectDistances = {} --> All objects that are grabbable and close to the hand that includes their distances
local objectToGrab = nil
local handGrabbingWith = nil
--> 1. Get all objects within radius of hand
local function checkHandRadius(hand)
local PartsInRadius = game.Workspace:GetPartBoundsInBox(hand.CFrame, hand.Size * 2)
for _, v in pairs(PartsInRadius) do --> Checks for parts within hand radius
local grabbable = v:FindFirstChild("grabbable")
if (grabbable) and grabbable:IsA("BoolValue") then --> Checks whether one of the objects is grabbable
if v:FindFirstChild("grabbable").Value then
local distance = (v.Position - hand.Position).Magnitude --> Distance between the object and the hand
if not Grabbables:FindFirstChild(v.Name) then --> Checks if the object doesn't exist yet in the table
--> Temporary value for object
local TempValue = Instance.new("ObjectValue")
TempValue.Name = v.Name
TempValue.Value = v
TempValue.Parent = Grabbable
else
local TempValue = Grabbables[v.Name]
TempValue.Value = v
end
objectDistances[distance] = v --> Adds object's distance to table
end
end
end
return
end
--> 2. Get object to grab + add and remove highlight
local handle --> Use :Disconnect() on this to stop checking hands (if necessary)
local checkTimer = 0
local checkDelay = 10
handle = RunService.RenderStepped:Connect(function()
if checkTimer < (checkDelay - 1) then checkTimer += 1
else
checkTimer = 0
checkHandRadius(leftHand)
checkHandRadius(rightHand)
end
end)
Grabbables.ChildAdded:Connect(function(child)
--> Get closest object
local OGValue = script:FindFirstChild("ObjectToGrab") --> Object value for "ObjectToGrab" for use in value change
local closestDistance = maxDistance
local function getSmallestDistance()
for distance, obj in pairs(objectDistances) do
closestDistance = math.min(
closestDistance,
distance
)
if closestDistance ~= maxDistance then
objectToGrab = obj
OGValue.Value = objectToGrab
print("ObjectToGrab:", objectToGrab)
end
end
end
getSmallestDistance()
child:GetPropertyChangedSignal("Value"):Connect(getSmallestDistance)
--> Set "objectToGrab"
OGValue:GetPropertyChangedSignal("Value"):Connect(function()
print("value changed!")
if objectToGrab then
print("Created highlight!")
--> Create highlight for the object
local Highlight = Instance.new("Highlight")
Highlight.FillColor = Color3.fromRGB(
0,
255,
255
)
Highlight.FillTransparency = 0
Highlight.OutlineTransparency = 1
Highlight.Parent = objectToGrab
end
end)
end)
Grabbables.ChildRemoved:Connect(function(child)
if child:IsA("ObjectValue") then
local Highlight = child.Value:FindFirstChild("Highlight")
if Highlight then
print('Removed highlight!')
Highlight:Destroy()
end
end
end)