This tutorial will be going over how to properly create an R15 morph rig that is able to be used in conjunction with an R15 auto-morph script. This tutorial is meant for users who wish to properly use working auto-morphs in their genres or game.
To begin setting up your rig, you’ll need to acquire a default one first. The easiest way of acquiring one is to click on the “Plugins” tab, click on “Rig Builder”, make sure it’s set to R15 and then click on the “Block Rig” option.
You’ll then want to open the dummy model up in Workspace to see this.
Start by removing the Humanoid inside the dummy as well as the HumanoidRootPart. After that, you’ll want to open each of the MeshParts inside of the dummy and remove everything inside of those as well. Each of the MeshParts should contain something like this inside.
Delete all of that for each one. Do not delete the mesh inside of the Head though! You’ll also want to open up the actual mesh inside of the Head and delete the OriginalSize value.
You should be left with just the MeshParts and the mesh inside of the Head itself.
Now you’ll want to right click each of the MeshParts and click “Group”. This will group the single MeshPart into a model of its own inside of the dummy. You’ll then want to rename the model to the name of the MeshPart. So if the name of the MeshPart is LeftFoot, you’ll name the model LeftFoot. Do this for each of the MeshParts.
Now you’ll want to rename each of the MeshParts inside of the models to “Middle” (without the quotations).
Your rig should now look like this.
You have successfully set up an R15 morph rig that is ready to be used with an auto-morph script. Auto-morph scripts spawn you in as the morph of your choosing. There are a plethora of ways to design your auto-morph script, but I use a compact and simple one that will work for you.
To begin setting up your auto-morph script, go to ServerStorage, make a new folder and name it “Morphs”. Now inside the Morphs folder you’ll want to make another folder and name it whatever you’d like, but I personally name mine the name of the game I’m working on. Inside of that folder you’ll want to make another folder and name it “PersonalMorphs” All of the morphs you’ll want to use with the auto-morph script will go inside of the PersonalMorphs folder. If you got a morph you want to use, then make another folder inside of the PersonalMorphs folder and name it whatever you like. I personally name mine the name of the character my morph is. It’s easier to find them if you have a lot of them in there.
Now if you have a morph that you want to put inside of the folder (mine being CalvinKadir), then you’ll want to copy every model inside of your morph model into the folder that you named.
Select all of those (not the dummy itself) then copy and paste them into your folder that you named.
Now let’s move onto the script I have created that you can create yourself with these photos. Start by going into ServerScriptService and making a script. Name that script “Morph”. Now open the script up, delete “print(“Hello world!”)” and we shall begin constructing it.
local Players = game:GetService('Players')
local Morphs = game:GetService('ServerStorage'):WaitForChild('Morphs') -- Looks for the "Morph" folder you've created earlier.
local visible = false
local recol = ''
function morph(plr, part, location, model, test)
if plr ~= nil then
if test == 'Morph' then
if plr:FindFirstChild('Morph') == nil then
local Folder = Instance.new('Folder')
Folder.Name = 'Morph'
Folder.Parent = plr
end
elseif test == 'Coat' then -- The "Coat" and "Pauld" statements can be completely ignored or removed without harming the script.
if plr:FindFirstChild('Coat') == nil then
local Folder = Instance.new('Folder')
Folder.Name = 'Coat'
Folder.Parent = plr
end
elseif test == 'Add' then
if plr:FindFirstChild('Add') == nil then
local Folder = Instance.new('Folder')
Folder.Name = 'Add'
Folder.Parent = plr
end
elseif test == 'Pauld' then
if plr:FindFirstChild('Pauld') == nil then
local Folder = Instance.new('Folder')
Folder.Name = 'Pauld'
Folder.Parent = plr
end
end
local Folder = (test == 'Morph' and plr:FindFirstChild('Morph')
or test == 'Coat' and plr:FindFirstChild('Coat')
or test == 'Add' and plr:FindFirstChild('Add')
or test == 'Pauld' and plr:FindFirstChild('Pauld'))
if Folder:FindFirstChild(model) == nil then
local g = location[model]:Clone()
g.Parent = Folder
for i, v in ipairs(g:GetChildren()) do
if v:IsA("BasePart") then
local W = Instance.new("Weld")
W.Part0 = g.Middle
W.Part1 = v
local CJ = CFrame.new(g.Middle.Position)
local C0 = g.Middle.CFrame:inverse() * CJ
local C1 = v.CFrame:inverse() * CJ
W.C0 = C0
W.C1 = C1
W.Parent = g.Middle
end
local Y = Instance.new("Weld")
Y.Part0 = plr:FindFirstChild(part)
Y.Part1 = g.Middle
Y.C0 = CFrame.new(0, 0, 0)
Y.Parent = Y.Part0
end
local h = g:GetChildren()
for i = 1, # h do
if h[i].className == "Part" or h[i].className == "UnionOperation" or h[i].className == "MeshPart" or h[i].className == "WedgePart" then
h[i].Anchored = false
h[i].CanCollide = false
end
end
end
end
end
local function RunThings(char,Model, test)
pcall(function()
if Model:findFirstChild("Head") then
morph(char, 'Head', Model, "Head",test)
end
if Model:findFirstChild("UpperTorso") then -- Looks for the body part models placed inside of the named folder you made.
morph(char, 'UpperTorso', Model, "UpperTorso",test)
end
if Model:findFirstChild("LowerTorso") then
morph(char, 'LowerTorso', Model, "LowerTorso",test)
end
if Model:findFirstChild("LeftUpperArm") then
morph(char, 'LeftUpperArm', Model, "LeftUpperArm",test)
end
if Model:findFirstChild("RightUpperArm") then
morph(char, 'RightUpperArm', Model, "RightUpperArm",test)
end
if Model:findFirstChild("LeftLowerArm") then
morph(char, 'LeftLowerArm', Model, "LeftLowerArm",test)
end
if Model:findFirstChild("RightLowerArm") then
morph(char, 'RightLowerArm', Model, "RightLowerArm",test)
end
if Model:findFirstChild("LeftHand") then
morph(char, 'LeftHand', Model, "LeftHand",test)
end
if Model:findFirstChild("RightHand") then
morph(char, 'RightHand', Model, "RightHand",test)
end
if Model:findFirstChild("LeftUpperLeg") then
morph(char, 'LeftUpperLeg', Model, "LeftUpperLeg",test)
end
if Model:findFirstChild("RightUpperLeg") then
morph(char, 'RightUpperLeg', Model, "RightUpperLeg",test)
end
if Model:findFirstChild("LeftLowerLeg") then
morph(char, 'LeftLowerLeg', Model, "LeftLowerLeg",test)
end
if Model:findFirstChild("RightLowerLeg") then
morph(char, 'RightLowerLeg', Model, "RightLowerLeg",test)
end
if Model:findFirstChild("LeftFoot") then
morph(char, 'LeftFoot', Model, "LeftFoot",test)
end
if Model:findFirstChild("RightFoot") then
morph(char, 'RightFoot', Model, "RightFoot",test)
end
end)
end
local function MorphUser(User,Team,Class,Morph,name)
local MorphRoot = Morphs[Team][Class]:WaitForChild(Morph)
local Model = MorphRoot:Clone()
local char = User.Character
RunThings(char,Model,name)
end
local function Body(depth,height,width,Char)
for _,v in pairs(Char.Humanoid:GetChildren()) do
if v.ClassName == 'NumberValue' then
if v.Name == 'BodyDepthScale' then -- Looks for any changes made to the depth, height and width variables.
v.Value = depth
elseif v.Name == 'BodyHeightScale' then
v.Value = height
elseif v.Name == 'BodyWidthScale' then
v.Value = width
end
end
end
end
local function Finale(Char)
for i,v in pairs(Char:GetChildren()) do
if v:IsA('Accessory') or v:IsA('Hat') then
v:Destroy()
end
end
end
local function Finale0(Char)
for i,v in pairs(Char:GetChildren()) do
if v.ClassName == 'MeshPart' or v.ClassName == 'n/a' then
v.Transparency = 1
if v:FindFirstChild('n/a') then
v.face:remove()
end
end
end
end
local function Finale1(Char)
for i,v in pairs(Char:GetChildren()) do
if v.ClassName == 'MeshPart' or v.ClassName == 'Part' then
v.Transparency = 1
if v:FindFirstChild('face') then
v.face:remove()
end
end
end
end
local function Finale2(Char)
for i,v in pairs(Char:GetChildren()) do
if v.ClassName == 'MeshPart' or v.ClassName == 'Part' and v.Name ~= 'Head' or v.Name ~= 'LeftHand' or v.Name ~= 'RightHand' then
v.Transparency = 1
end
end
end
local function Head(head,Char)
for _,v in pairs(Char.Humanoid:GetChildren()) do
if v.ClassName == 'NumberValue' then
if v.Name == 'HeadScale' then
v.Value = head
end
end
end
end
Players.PlayerAdded:connect(function(Player)
Player.CharacterAdded:connect(function(Character)
wait(2)
visible = false
if Player.Name == 'PLAYER NAME' then -- Changing these variables alter the morph functions entirely.
Body(1,1,1,Character)
MorphUser(Player,"MAP NAME","PersonalMorphs","MORPH NAME","Morph")
Finale(Character)
Finale1(Character)
end
end)
end)
In the if Player.Name == ‘CalvinKadir’ statement, you’ll want to replace CalvinKadir with your own Roblox username or somebody else’s username. You can easily replace that line entirely with a group or group rank statement so that specific groups or group ranks will receive the morph instead.
if Player:GetRankInGroup(5025607) == 255
^ That line of code is an example of what you can replace the name statement with.
You can also entirely remove the Body(1,1,1,Character) statement if you don’t ever plan on changing the height, width and depth of your morph. Do keep in mind that by changing those values, you’ll have to also properly scale the morph model itself, or you’ll end up spawning in with your arms or legs floating away from your torso. I will explain how to do that in a future advanced tutorial.
On line 190 is where the folders you’ve created previously in ServerStorage come in.
MorphUser(Player,“The Void”,“PersonalMorphs”,“CalvinKadir”,“Morph”) should be changed to the name of the folders you have created. “The Void” would be changed and “CalvinKadir” would be changed. The rest should stay the same.
Basically the Finale statements are there to determine which part of the morph is visible and which part isn’t. This is useful at times. Say you want to make a morph, but you don’t want to make a custom head, you can change the Finale statement to make the head on the morph invisible so that you can spawn in with the custom body, but still have your own Roblox face, accessories and head. Or you can just make it where you have your head and face, but not any accessories.
Finale, Finale1, Finale2 and Finale3 are all the types of Finale statements you can switch between. This won’t mess up the script any, so just experiment and choose which one you’d like. Notice that I have two Finales in the code below. One Finale adds onto or negates the effect of the other Finale. It’s always a good idea to keep the Finale(Character) on there, but it can be switched for different effects like I explained above.
if Player.Name == ‘CalvinKadir’ then – Entire section is changeable.
Body(1,1,1,Character)
MorphUser(Player,“The Void”,“PersonalMorphs”,“CalvinKadir”,“Morph”)
Finale(Character)
Finale1(Character)
if Player.Name == ‘’ then
Body(1,1,1,Character)
MorphUser(Player,“Map Name”,“PersonalMorphs”,“Morph Name”,“Morph”)
Finale(Character)
Finale1(Character)
Be sure to change if to elseif on the second one and beyond.
Once you have thoroughly completed each of the steps above, the complicated part is out of the way. When you join the game via test or server, you will spawn in as the morph you placed within the named folder you created. You’ll continue to spawn in as this morph until you change it within Studio.
This setup is particularly useful for roleplaying genres, such as a Star Wars or Game of Thrones genre. With the rig functioning, you can begin building and shaping it into whatever character or person you’d like. For example, me and my friend have built some Dishonored morphs, as well as many others. Your morph will go as far as your creativity.
When you’re building your morph, be sure to put the parts you’re adding into the correct body part model. So if you’re building something on the upper left arm, you’d place those parts within the LeftUpperArm model.
I’d recommend not allowing one part to extend to another body part. If you’re building something on the upper arm, it shouldn’t extend down to the lower arm. It’ll look a bit odd in-game. You can still do it, and I usually build from the torso onto the shoulders of each arm all the time. But areas such as the arms might look a bit off.
If you have any other questions, please toss me a PM. I’ll get back with you as soon as I can.