Can't get CFrame?

I’m trying to check the surroundings of a part, and if there is an unoccupied space, put the position of that space into a list, then choose a random space position, and spawn part there accordingly. But for some reason, the CFrame turns nil. Here is my code, its kind of messy, but I hope is understandable:

local TweenService = game:GetService("TweenService")

local RootList = {}

local heart = workspace.Overgrowth.OverGrowthHeart

table.insert(RootList, heart)

script.Parent.MouseClick:Connect(function()
	
	repeat
		local overlapParams = OverlapParams.new()
		overlapParams.FilterDescendantsInstances = workspace.Overgrowth:GetChildren()
		overlapParams.FilterType = Enum.RaycastFilterType.Include
		
		
		local availableSpots = {}
		
		-- Check Boxes
		local UpCheckBoxResult = workspace:GetPartBoundsInBox(RootList[#RootList].CFrame * CFrame.new(0, 1, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
		local DownCheckBoxResult = workspace:GetPartBoundsInBox(RootList[#RootList].CFrame * CFrame.new(0, -1, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
		local LeftCheckBoxResult = workspace:GetPartBoundsInBox(RootList[#RootList].CFrame * CFrame.new(-1, 0, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
		local RightCheckBoxResult = workspace:GetPartBoundsInBox(RootList[#RootList].CFrame * CFrame.new(1, 0, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
		local FrontCheckBoxResult = workspace:GetPartBoundsInBox(RootList[#RootList].CFrame * CFrame.new(0, 0, -1), Vector3.new(0.8, 0.8, 0.8), overlapParams)
		local BackCheckBoxResult = workspace:GetPartBoundsInBox(RootList[#RootList].CFrame * CFrame.new(0, 0, 1), Vector3.new(0.8, 0.8, 0.8), overlapParams)
		--
		
		if #UpCheckBoxResult == 0 then
			table.insert(availableSpots, (RootList[#RootList].CFrame * CFrame.new(0, 1, 0)))
		else
			continue
		end
		
		if #DownCheckBoxResult == 0 then
			table.insert(availableSpots, (RootList[#RootList].CFrame * CFrame.new(0, -1, 0)))
		else
			continue
		end
		
		if #LeftCheckBoxResult == 0 then
			table.insert(availableSpots, (RootList[#RootList].CFrame * CFrame.new(-1, 0, 0)))
		else
			continue
		end
		
		if #RightCheckBoxResult == 0 then
			table.insert(availableSpots, (RootList[#RootList].CFrame * CFrame.new(1, 0, 0)))
		else
			continue
		end
		
		if #FrontCheckBoxResult == 0 then
			table.insert(availableSpots, (RootList[#RootList].CFrame * CFrame.new(0, 0, -1)))
		else
			continue
		end
		
		if #BackCheckBoxResult == 0 then
			table.insert(availableSpots, (RootList[#RootList].CFrame * CFrame.new(0, 0, 1)))
		else
			continue
		end
		
		if #availableSpots > 0 then
			
			local nextRootPosition = table.find(availableSpots, math.random(1, #availableSpots))
			
			local spawnPosition
			
			if nextRootPosition == RootList[#RootList].CFrame * CFrame.new(0, 1, 0) then
				spawnPosition = nextRootPosition * CFrame.new(0, -0.5, 0)
				
			elseif nextRootPosition == RootList[#RootList].CFrame * CFrame.new(0, -1, 0) then
				spawnPosition = nextRootPosition * CFrame.new(0, 0.5, 0)
			elseif nextRootPosition == RootList[#RootList].CFrame * CFrame.new(-1, 0, 0) then
				spawnPosition = nextRootPosition * CFrame.new(0.5, 0, 0)
			elseif nextRootPosition == RootList[#RootList].CFrame * CFrame.new(1, 0, 0) then
				spawnPosition = nextRootPosition * CFrame.new(-0.5, 0, 0)
			elseif nextRootPosition == RootList[#RootList].CFrame * CFrame.new(0, 0, -1) then
				spawnPosition = nextRootPosition * CFrame.new(0, 0, 0.5)
			elseif nextRootPosition == RootList[#RootList].CFrame * CFrame.new(0, 0, 1) then
				spawnPosition = nextRootPosition * CFrame.new(0, 0, -0.5)
			end
			
			print(spawnPosition)
			
			local newRoot = Instance.new("Part")
			newRoot.Anchored = false
			newRoot.Size = Vector3.new(0.002, 0.002, 0.002)
			newRoot.CFrame = spawnPosition
			newRoot.Color = Color3.fromRGB(80, 109, 84)
			newRoot.Parent = workspace
			newRoot.Name = tostring("root".. tostring(#RootList + 1))

			local weld = Instance.new("WeldConstraint")
			weld.Part0 = newRoot
			weld.Part1 = RootList[#RootList]
			weld.Parent = newRoot

			local growthTweenGoals = {}
			growthTweenGoals.CFrame = nextRootPosition
			growthTweenGoals.Size = Vector3.new(1, 1, 1)

			local growthTweenInfo = TweenInfo.new(1, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out, 0, false, 0)

			local growthTween = TweenService:Create(newRoot, growthTweenInfo, growthTweenGoals)

			growthTween:Play()

			table.insert(RootList, newRoot)
			print(RootList)
			
		else
			print("smth went wrong")
			break
		end
		task.wait(1)
	until #RootList == 100
end)

The nextRootPosition is the final destination where the part needs to be positioned, while the spawnPosition is a slightly changed nextRootPosition, where part is initially spawned, and then moved to the nextRootPosition with tweenService.

Try replacing

local nextRootPosition = table.find(availableSpots, math.random(1, #availableSpots))

with

local nextRootPosition = availableSpots[math.random(1, #availableSpots)]
2 Likes

It did work, surprisingly. Could you please explain why previous method did not work, and did not even notify me about any error?

table.find is used to find the index of a certain value. You’re attempting to do the opposite; finding a value at a certain index.

What your original code is doing, is:

  1. Generating a random number
  2. Trying to find if the value of step 1 exists, returning its index if it does.
  3. Failing step 2 as it cannot find the specified value, and returning nil

Since your table doesn’t contain any valued that would match, it returns nil. It doesn’t error since nil is a valid return value.

Essentially, you’re using table.find wrong. It’s purpose is for finding the index of a known value, not the opposite, if that makes sense!

What the code snippet that was suggested does, is grab a value at a randomly generated index. That’s what it looks like you were originally trying to do, so it works out.

1 Like

I believe table find is pretty opposite? You give it the list to search in and an index to get the value of that index? The value itself can be found too, but not in my case. If you search for value, it returns idnex, and if you look for index it returns value

1 Like

Quoting the docs: “Within the given array-like table haystack, find the first occurrence of value

First occurrence = index. The code is finding the index of the specified value.

The image from the documentation that you linked displays this in motion. table.find is called, with the first parameter being the table t, and the second parameter being d. The script looks through the table to find the value d, in which it succeeds. It then returns the index of d, which would be 4.

It doesn’t work back and forth, because a script cannot logically determine whether you intend to search for an index or a value. It only works to find indexes of values.

1 Like

Please try this in studio.

local list = {"A", "B", "C", "D", "E"}
print(table.find(list, 3)) --> "C"

Nevermind, I actually was wrong about this one.