Model
Models are container objects, meaning they group objects together. They are best used to hold collections of BaseParts and have a number of functions that extend their functionality.
Models are intended to represent geometric groupings. If your grouping has no geometric interpretation, for instance a collection of Scripts, use a Folder instead.
Models whose constituent parts are joined together with joints (so that they can move around or be destroyed via physics simulation) usually have a PrimaryPart set, as it specifies which part within the model the pivot and bounding box will "follow" as the model moves. Static models which stay in one place do not benefit from having a primary part set.
Models have a wide range of applications, including Roblox player characters. They also have a number of unique behaviors that are important to keep in mind:
- When a Humanoid and a Part named Head are parented under a model, a name/health GUI will appear over the model; see Character Name/Health Display for details.
- If a part's position on the Y axis hits the Workspace.FallenPartsDestroyHeight value, and it was the last object inside of a Model, the model will be destroyed as well.
- When used in a place with Workspace.StreamingEnabled set to true, the value of ModelStreamingMode controls various behaviors around how the model and any descendants are replicated and/or removed from clients. In addition, the value of LevelOfDetail impacts rendering of the model.
As with all Instance types, the fact that a parent Model is replicated to a client does not guarantee that all its children are replicated. This is particularly important if these instances are being accessed by code running on the client, such as in a LocalScript. Using ModelStreamingMode with values such as Atomic can ensure that the entire model and all of its descendants are present if the parent model exists on the client, or you can use WaitForChild() when atomicity is not desired.
Code Samples
The following sample includes a basic function that takes a table of objects and parents them into a new Model, returning that Model.
local function groupObjects(objectTable)
local model = Instance.new("Model")
for _, object in pairs(objectTable) do
object.Parent = model
end
return model
end
local objects = {
Instance.new("Part"),
Instance.new("Part"),
}
groupObjects(objects)
Summary
Properties
Sets the level of detail on the model for experiences with instance streaming enabled.
Controls the model streaming behavior on Models when instance streaming is enabled.
The primary part of the Model, or nil if not explicitly set.
Editor-only property used to scale the model around its pivot. Setting this property will move the scale as though Model/ScaleTo was called on it.
Determines where the pivot of a Model which does not have a set Model.PrimaryPart is located.
Properties
Methods
Sets this model to be persistent for the specified player. ModelStreamingMode must be set to PersistentPerPlayer for behavior to be changed as a result of addition.
Returns a description of a volume that contains all parts of a Model.
Returns the size of the smallest bounding box that contains all of the BaseParts in the Model, aligned with the Model.PrimaryPart if it is set.
Returns all the Player objects that this model object is persistent for. Behavior varies based on whether this method is called from a Script or a LocalScript.
Returns the canonical scale of the model, which defaults to 1 for newly created models and will change as it is scaled via Model/ScaleTo.
Moves the PrimaryPart to the given position. If a primary part has not been specified, the root part of the model will be used.
Makes this model no longer persistent for the specified player. ModelStreamingMode must be set to PersistentPerPlayer for behavior to be changed as a result of removal.
Sets the scale factor of the model, adjusting the sizing and location of all descendant Instances such that they have that scale factor relative to their initial sizes and locations when scale factor was 1.
Shifts a Model by the given Vector3 offset, preserving the model's orientation. If another BasePart or Terrain already exists at the new position then the Model will overlap said object.
Methods
Gets the pivot of a PVInstance.
Transforms the PVInstance along with all of its descendant PVInstances such that the pivot is now located at the specified CFrame.
Properties
LevelOfDetail
ModelStreamingMode
PrimaryPart
Code Samples
-- Create a dice model with two halves and attach them together
local diceModel = Instance.new("Model")
diceModel.Name = "ChanceCube"
local diceTop = Instance.new("Part")
diceTop.Size = Vector3.new(4, 2, 4)
diceTop.Position = Vector3.new(0, 1, 0)
diceTop.Color = Color3.new(0, 0, 1)
diceTop.Parent = diceModel
local diceBottom = diceTop:Clone()
diceBottom.Position = Vector3.new(0, -1, 0)
diceBottom.Color = Color3.new(1, 0, 0)
diceBottom.Parent = diceModel
local weld = Instance.new("WeldConstraint")
weld.Part0 = diceTop
weld.Part1 = diceBottom
weld.Parent = diceModel
-- Put the dice up in the air above the workspace origin (does not require a primary part)
diceModel.Parent = workspace
diceModel:PivotTo(CFrame.new(0, 10, 0))
-- Assign the primary part before physical simulation
-- Without this line, the script will always output the same thing and the bounding box of the model will not change orientation
diceModel.PrimaryPart = diceTop
-- Wait a bit before rolling the dice (let it settle onto the floor)
for i = 5, 1, -1 do
print("Rolling dice in...", i)
task.wait(1)
end
diceTop:ApplyAngularImpulse(Vector3.new(15000, 1000, 5000))
diceTop:ApplyImpulse(Vector3.new(0, 3000, 0))
task.wait(1)
-- Wait for the roll to complete
while diceTop.AssemblyLinearVelocity.Magnitude > 0.1 or diceTop.AssemblyAngularVelocity.Magnitude > 0.1 do
task.wait()
end
-- Get the dice orientation, impacted by the primary part
local orientation = diceModel:GetBoundingBox()
if orientation.YVector.Y > 0.5 then
print("It's the boy!")
else
print("It's his mother!")
end
Scale
WorldPivot
Code Samples
local function resetPivot(model)
local boundsCFrame = model:GetBoundingBox()
if model.PrimaryPart then
model.PrimaryPart.PivotOffset = model.PrimaryPart.CFrame:ToObjectSpace(boundsCFrame)
else
model.WorldPivot = boundsCFrame
end
end
resetPivot(script.Parent)
Methods
GetExtentsSize
Returns
Code Samples
local model = Instance.new("Model")
model.Parent = workspace
local RNG = Random.new()
for _ = 1, 5 do
local part = Instance.new("Part")
part.Anchored = true
part.Size = Vector3.new(RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5))
part.Parent = model
end
print(model:GetExtentsSize())
GetPersistentPlayers
Returns
GetScale
Returns
Code Samples
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Find all the models with the tag we want to replace
local items = CollectionService:GetTagged("Tree")
local newModel = ReplicatedStorage.FancyTreeReplacementModel
for _, item in items do
-- Make the new item and scale / position it where the old one was
local newItem = newModel:Clone()
newItem:ScaleTo(item:GetScale())
newItem:PivotTo(item:GetPivot())
-- Add the same tag to the replacement
CollectionService:AddTag(newItem, "Tree")
-- Delete the old item and parent the new one
newItem.Parent = item.Parent
item:Destroy()
end
MoveTo
Parameters
Returns
Code Samples
local START_POSITION = Vector3.new(-20, 10, 0)
local END_POSITION = Vector3.new(0, 10, 0)
local model = Instance.new("Model")
model.Parent = workspace
local part1 = Instance.new("Part")
part1.Size = Vector3.new(4, 4, 4)
part1.Position = START_POSITION
part1.Anchored = true
part1.BrickColor = BrickColor.new("Bright yellow")
part1.Parent = model
local part2 = Instance.new("Part")
part2.Size = Vector3.new(2, 2, 2)
part2.Position = START_POSITION + Vector3.new(0, 3, 0)
part2.Anchored = true
part2.BrickColor = BrickColor.new("Bright blue")
part2.Parent = model
model.PrimaryPart = part1
model.Parent = workspace
local obstruction = Instance.new("Part")
obstruction.Name = "Obstruction"
obstruction.Size = Vector3.new(10, 10, 10)
obstruction.Position = Vector3.new(0, 10, 0)
obstruction.Anchored = true
obstruction.BrickColor = BrickColor.new("Bright green")
obstruction.Parent = workspace
task.wait(3)
model:MoveTo(END_POSITION)
TranslateBy
Parameters
Returns
Code Samples
local START_POSITION = Vector3.new(-20, 10, 0)
local END_POSITION = Vector3.new(0, 10, 0)
local model = Instance.new("Model")
local part1 = Instance.new("Part")
part1.Size = Vector3.new(4, 4, 4)
part1.CFrame = CFrame.new(START_POSITION) * CFrame.Angles(0, math.rad(45), 0)
part1.Anchored = true
part1.BrickColor = BrickColor.new("Bright yellow")
part1.Parent = model
local part2 = Instance.new("Part")
part2.Size = Vector3.new(2, 2, 2)
part2.CFrame = part1.CFrame * CFrame.new(0, 3, 0)
part2.Anchored = true
part2.BrickColor = BrickColor.new("Bright blue")
part2.Parent = model
model.PrimaryPart = part1
model.Parent = workspace
local obstruction = Instance.new("Part")
obstruction.Name = "Obstruction"
obstruction.Size = Vector3.new(10, 10, 10)
obstruction.Position = Vector3.new(0, 10, 0)
obstruction.Transparency = 0.5
obstruction.Anchored = true
obstruction.BrickColor = BrickColor.new("Bright green")
obstruction.Parent = workspace
task.wait(3)
-- use TranslateBy to shift the model into the obstruction
model:TranslateBy(END_POSITION - START_POSITION)