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
BreakJoints
Returns
Code Samples
local Players = game:GetService("Players")
local function onCharacterAdded(character)
task.wait(3)
character:BreakJoints()
end
local function onPlayerAdded(player)
player.CharacterAdded:Connect(onCharacterAdded)
end
Players.PlayerAdded:Connect(onPlayerAdded)
local JointsService = game:GetService("JointsService")
local partA = script.Parent.PartA
local partB = script.Parent.PartB
local function join(part0, part1, jointClass, parent)
local newJoint = Instance.new(jointClass or "ManualWeld")
newJoint.Part0 = part0
newJoint.Part1 = part1
newJoint.C0 = CFrame.new()
newJoint.C1 = part1.CFrame:toObjectSpace(part0.CFrame)
newJoint.Parent = parent or part0
return newJoint
end
-- Create some joints and break them
join(partA, partB)
partA:BreakJoints()
-- Glue joints are wobbly
join(partA, partB, "Glue")
partA:BreakJoints()
-- Most of the time, joints ought to be put in JointsService
join(partA, partB, "Weld", JointsService)
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())
GetModelSize
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.Parent = model
part.Anchored = true
part.Size = Vector3.new(RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5), RNG:NextNumber(0.05, 5))
end
print(model:GetModelSize())
GetPersistentPlayers
Returns
GetPrimaryPartCFrame
Returns
Code Samples
local START_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)
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
-- set the primary part
model.PrimaryPart = part1
model.Parent = workspace
while true do
local primaryPartCFrame = model:GetPrimaryPartCFrame()
local newCFrame = primaryPartCFrame * CFrame.Angles(0, math.rad(1), 0)
model:SetPrimaryPartCFrame(newCFrame)
task.wait()
end
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
MakeJoints
Returns
Code Samples
local model = Instance.new("Model")
-- create one part on top of another
local topPart = Instance.new("Part")
topPart.Size = Vector3.new(5, 1, 5)
topPart.Position = Vector3.new(0, 10, 0)
topPart.BrickColor = BrickColor.new("Bright green")
topPart.Anchored = true -- anchor the top part
topPart.Parent = model
local bottomPart = Instance.new("Part")
bottomPart.Size = Vector3.new(8, 1, 8)
bottomPart.Position = Vector3.new(0, 9, 0)
bottomPart.BrickColor = BrickColor.new("Bright green")
bottomPart.Anchored = false -- leave bottom unanchored
bottomPart.Parent = model
topPart.BottomSurface = Enum.SurfaceType.Smooth
topPart.TopSurface = Enum.SurfaceType.Smooth
bottomPart.BottomSurface = Enum.SurfaceType.Smooth
bottomPart.TopSurface = Enum.SurfaceType.Weld -- 'Weld' to create a joint
model.Parent = workspace
model:MakeJoints()
task.wait(2)
-- unanchor the bottom part - part does not fall
print("Unanchored!")
bottomPart.BrickColor = BrickColor.new("Bright red")
bottomPart.Anchored = false
task.wait(2)
-- break the joints using an explosion - part falls
local explosion = Instance.new("Explosion")
explosion.Position = bottomPart.Position
explosion.Parent = workspace
local partA = script.Parent.PartA
local partB = script.Parent.PartB
-- Move PartB on top of PartA
partB.CFrame = partA.CFrame * CFrame.new(0, partB.Size.Y / 2 + partA.Size.Y / 2, 0)
-- Studs and Inlet will make joints
partA.TopSurface = Enum.SurfaceType.Studs
partB.BottomSurface = Enum.SurfaceType.Inlet
-- Automatically create a joint between PartA and PartB
partA:MakeJoints()
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)
ResetOrientationToIdentity
Returns
SetIdentityOrientation
Returns
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)