Working script - Moving models on mass during game design asset placement

Sharing a successful script

I couldn’t find a script to do this after searching so I thought I’d share for anyone else wanting to achieve similar and try to explain it for others quite new to this.

As part of setting up the build/assets of the project I wanted to reposition nearly 200 tree models in a folder by the y-coordinate in one fell swoop.
(in the future it will be more felly at least, learning my way around ModuleScripts for the first time took a while).

I wanted to elevate the models by different amounts, within a range, at random (rather than by a constant value) and to preserve the x- and z-coordinates and orientation / angles.

Tried SetPrimaryPartCFrame with some success before reading it was deprecated but I realised it had reset all the model CFrame angles so I’d lost my rotations and tilts.

I moved the original models into a folder in ServerStorage, ensured they all had a PrimaryPart set, that everything was checked Archivable. Moved all the models to the same starting y-coordinate (the minimum height I wanted across the range of trees).

  • Folder containing models in ServerStorage
  • ModuleScript in ReplicatedStorage
local module = {}

module.posUpdate = function()
	local serverStorage = game:GetService("ServerStorage")
	local folder = serverStorage:WaitForChild("PineTrees") -- the folder models are in
	local treeArray = folder:GetChildren() -- creates an array of the models in the folder
	local treeCopy -- I figure this is a variable that holds the clones allowing us to work with them
	local ran = nil -- variable for my random number I'll use to move the models
	
-- The below runs a "for" loop applying the script to each of the models in turn
-- the "_" just means I don't need to index the models in the list
-- i.e. where they fall in the table doesn't matter, I'm not going to go searching for the tenth model
-- and I'm not trying to match things in a table like ... index: Fruit, object: Apple

-- I tell the for loop I'm going to call each model "tree", from the table created above called "treeArray"
	for _, tree in treeArray do
		
		-- clone the trees, holding them in the variable treeCopy
		treeCopy = tree:Clone()
		
		-- generate a random number between 0 and 5
		ran = Random.new():NextNumber(0, 5)

		-- the below just removes most decimal places
		local rd = ran
		rd *= 10
		rd = math.floor(rd)
		ran = rd / 10
		
		-- Moves the cloned tree model by taking the current CFrame position of
		-- its PrimaryPart and adds to its CFrame y-coordinate using a vector
		-- ... (a vector is a combination of direction and distance)
		treeCopy:PivotTo(treeCopy:GetPivot() + Vector3.new(0, ran, 0))
		-- the new vector only has one positive value "ran" in the y-coordinate
		-- so it only moves up

		-- sets the clone's parent as the folder I want them to end up in
		treeCopy.Parent = game.Workspace.Trees

		wait(.1) -- waiting just makes it look cool as I watch them appear in the Workspace
		
		local ran = nil -- resets the random number to nil
	end
end

return module

In the command bar at the base of the Studio window:
local module = require(game.ReplicatedStorage.ModuleScript) module.posUpdate()