I wrote this algorithm today to manage transformations.
The transformation included in the model is called “Shadow Form”. It is triggered when you have 1 health and you cannot equip tools while you are in this form and you crawl.
I designed this as a system to allow support for other transformations and easy code refactoring into a module.
This is the source code of the transformation system.
local Character=script.Parent
local formname="Form"
local Forms={}
local function Form(Character,FormName,bool)
local FormObject=Character:FindFirstChild(FormName) or Instance.new("BoolValue")
if FormObject.Name~=FormName then
FormObject.Name=FormName
FormObject.Parent=Character
end
if bool then
FormObject.Value=bool
end
return FormObject
end
local FormData={}
local animcache=script.AnimationCache
local function ReplaceAnimations(library,AnimationScript)
local payload={}
local objects={}
for i,v in library:GetChildren() do
local cachethis= AnimationScript:FindFirstChild(v.Name)
if cachethis then
table.insert(payload,cachethis)
cachethis.Parent=animcache
v.Parent=AnimationScript
table.insert(objects,v)
end
end
return {payload=payload,objects=objects}
end
local faces={"Front","Left","Right","Bottom","Top","Back"}
local ts=game:GetService("TweenService")
local debris=game:GetService("Debris")
local imagetrans=TweenInfo.new(5)
local function covertexture(imageobject,subject)
local images={}
for i,v in faces do
local imageclone=imageobject:Clone()
imageclone.Face=v
imageclone.Transparency=1
imageclone.Parent=subject
table.insert(images,imageclone)
ts:Create(imageclone,imagetrans,{Transparency=0.3}):Play()
end
return images
end
local function playsound(sound)
sound.Volume=0
sound.Pitch=math.random(75,125)/100
sound.PlaybackSpeed=math.random(75,125)/100
--sound.Parent=Character.PrimaryPart
sound:Play()
ts:Create(sound,imagetrans,{Volume=math.random(30,100)/100}):Play()
end
FormData={
["Dark Form"]={
[true]=function(Character)
local payload={}
local colorhash={}
local texturepayload={}
local particlepayload={}
for i,v in Character:GetChildren() do
if v:IsA("BasePart") and v.Transparency~=1 then
table.insert(payload,{object=v,Color=v.Color})
ts:Create(v,imagetrans,{Color=Color3.fromRGB(0,0,0)}):Play()
colorhash[v.Name]=true
for t,o in script["Dark Form Particles"]:GetChildren() do
local c=o:Clone()
c.Parent=v
c.Enabled=true
table.insert(particlepayload,c)
end
end
end
local sound=script["Dark Form Sounds"]["Hollow Rumble 1 (SFX)"]:Clone()
sound.Parent=Character.PrimaryPart
playsound(sound)
for i,v in Character:GetDescendants() do
if v:IsA("BasePart") and v.Transparency~=1 and colorhash[v.Name]==nil then
table.insert(texturepayload,covertexture(script.Black,v))
end
end
local animpayload=ReplaceAnimations(script["Dark Form"],Character.Animate)
FormData["Dark Form"].Data["Colors"]=payload
FormData["Dark Form"].Data["Animations"]=animpayload
FormData["Dark Form"].Data["Textures"]=texturepayload
FormData["Dark Form"].Data["Particles"]=particlepayload
FormData["Dark Form"].Data["Sounds"]={sound}
end,
[false]=function(Character)
if FormData["Dark Form"].Data.Colors and #FormData["Dark Form"].Data.Colors>1 then
for i,v in FormData["Dark Form"].Data.Colors do
ts:Create(v.object,imagetrans,{Color=v.Color}):Play()
end
for i,v in FormData["Dark Form"].Data.Textures do
for t,o in v do
ts:Create(o,imagetrans,{Transparency=1}):Play()
debris:AddItem(o,7)
end
end
FormData["Dark Form"].Data.Textures={}
for i,v in FormData["Dark Form"].Data.Sounds do
ts:Create(v,imagetrans,{Volume=0}):Play()
debris:AddItem(v,8)
end
FormData["Dark Form"].Data.Sounds={}
for i,v in FormData["Dark Form"].Data.Particles do
v.Enabled=false
debris:AddItem(v,5)
--v:Destroy()
end
FormData["Dark Form"].Data.Particles={}
FormData["Dark Form"].Data.Colors={}
local v =FormData["Dark Form"].Data.Animations-- do
for t,o in v.payload do
o.Parent=Character.Animate
end
for t,o in v.objects do
o.Parent=script["Dark Form"]
end
--end
FormData["Dark Form"].Data.Animations={}
end
end,
["Data"]={},
Connections=function(Character)
local a=Character.ChildAdded:Connect(function(v)
if v:IsA("Tool") then
Character.Humanoid:UnequipTools()
end
end)
local b=Character.Humanoid:GetPropertyChangedSignal("Health"):Connect(function()
if Character.Humanoid.Health<=1 then
Character.Humanoid.Health=1
Forms.Toggle(Character,"Dark Form",true)
elseif Character.Humanoid.Health>=Character.Humanoid.MaxHealth*.25 then
Forms.Toggle(Character,"Dark Form",false)
end
end)
return {a,b}
end,
},
}
function Forms.Toggle(Character,FormName,bool)
local formobject=Form(Character,FormName)
if bool==nil then
if formobject.Value==false then
bool=true
formobject.Value=true
else bool=false
end
--FormData[FormName][bool](Character)
elseif formobject==bool then
return
end
FormData[FormName][bool](Character)
end
function Forms.Initalize(Character,FormHash)
local connections={}
for i,v in FormData do
if FormHash==nil or FormHash[i]~=nil then
Form(Character,formname)
table.insert(connections,v.Connections(Character))
end
end
local function disconnect()
for i,group in connections do
for t,connection in group do
connection:Disconnect()
end
end
end
table.insert(connections,Character.AncestryChanged:Connect(function()
if Character.Parent~=workspace then
disconnect()
end
end))
end
This is the model you can try out by placing it in StarterCharacterScripts
PlaceScriptIn_StarterCharacterScripts - Creator Store (roblox.com)
If you want to use the animations you can import them with my free plugin bulk animation importer.
Bulk Animation Importer - Creator Store (roblox.com)
It is based off Sora’s Shadow form design from Kingdom Hearts II