Cover a part with models or parts for decor (with welding)


(covering the arms of a tree monster with twig models)


Made this and thought other people might find it useful.

--[[ Start of `CoverPart` function]]
local RANDOM = Random.new(os.clock())

local function weldPartTo(p1, p0, n)
	local w = p1:FindFirstChild(n)

	if w then
		w:Destroy()
	end

	w = Instance.new("WeldConstraint")
	w.Name = n
	w.Part0 = p0
	w.Part1 = p1
	w.Parent = p1
end

local function weldModelTo(m, p)
	if m.ClassName == "Model" then
		assert(m.PrimaryPart, "no primary part for model")

		for _, d in ipairs(m:GetDescendants()) do
			if d:IsA("BasePart") and d ~= m.PrimaryPart then
				weldPartTo(d, m.PrimaryPart, "WeldToPrimaryPart")
			end
		end

		weldPartTo(m.PrimaryPart, p, "WeldTo" .. p.Name)
	else
		weldPartTo(m, p, "WeldTo" .. p.Name)
	end
end

local function getFaceSize3D(partSize, dir)
	dir = dir:Abs()

	local getFaceSizeVec = Vector3.new(
		bit32.bxor(dir.X, 1),
		bit32.bxor(dir.Y, 1),
		bit32.bxor(dir.Z, 1)
	)
	
	local faceSize3D = partSize*getFaceSizeVec
	
	return faceSize3D
end

local function CoverPart(
	part: BasePart, --[[ The base part you want to cover randomly with objects]]
	numPerFace: NumberRange, --[[ The number of objects (range) you want to put per face]]
	maxLookAngle: number, --[[ The maximum angle (deg) the object should face towards from the normal of the face. This behaves similar to the `SpreadAngle` property of particle emitters]]
	dst: Instance, --[[ The new parent of all the created objects]]
	src: Instance --[[ The source container of objects to clone from]]
)
	local objs = src:GetChildren()
	
	--[[ !!WARNING!!]]
	
	--[[ Do not uncomment this unless you are positive you want all children]]
	--[[ of the `dst` instance to be destroyed upon calling this function.]]

	--[[ Useful for quick iteration of random placements.]]

	--[[----------------------]]
	--[[dst:ClearAllChildren()]]
	--[[----------------------]]
	
	local partCF = part.CFrame
	local partSize = part.Size

	local i = 0

	for _, normalId in ipairs(Enum.NormalId:GetEnumItems()) do
		for i = 1, math.random(numPerFace.Min, numPerFace.Max) do
			local dir = Vector3.FromNormalId(normalId)
			local faceSize = getFaceSize3D(partSize, dir)
			local os_faceOrigin = dir*partSize/2
			local os_randFaceVec = RANDOM:NextUnitVector()*faceSize/2
			local ws_randFacePos = partCF*(os_faceOrigin + os_randFaceVec)
			local ws_randLookPos = ws_randFacePos + partCF:VectorToWorldSpace(dir)
			local ws_randCF = CFrame.lookAt(ws_randFacePos, ws_randLookPos) 
				* CFrame.Angles(math.rad(math.random(-maxLookAngle, maxLookAngle)), math.rad(math.random(-maxLookAngle, maxLookAngle)), math.rad(360))

			local obj = objs[i%3+1]:Clone()
			obj:PivotTo(ws_randCF)
			obj.Parent = dst

			weldModelTo(obj, part)
		end
	end
end
--[[ End of `CoverPart` function]]

--[[ Using command line]]
for _, selectedPart in ipairs(game:GetService("Selection"):Get()) do
	CoverPart(selectedPart, NumberRange.new(1, 2), 45, workspace.ElderTree.Sticks, game.ServerStorage.GenerateSticks.Sticks)
end
1 Like