❆ Freeze Module - Make a Cool Frozen Effect ❅

:wave: Introduction:
Hello Developers!

  • I’ve made a pretty cool frozen effect recently :snowflake:. But after checking out the Devforum, I couldn’t find any similar tutorials or open source system so I thought that if I made this a free resource, it would be helpful to some other devs, especially during the current Winter season and future usages! :snowman_with_snow:
  • This module has been completed! (All features: Create an ice layer :ice_cube:, freeze at current animation frame :film_strip:, useful settings and customization :gear:)
  • Documented :white_check_mark:, Has examples :white_check_mark:, Easy customization :white_check_mark:, Supports both R6 & R15 :white_check_mark:
    WORKS ON PLAYERS, NPCS & R6/R15/ALL TYPE OF RIGS!

:ice_cube:Thunder’s Freeze Module:
(Has everything listed in this post)

“An incredibly cool, bone-chilling, icy module that creates a frosty, frozen effect”

:ice_cube:Thunder’s Modified Freeze Module:
(No duration but it comes with an unfreeze function)

:cold_face:Mvke’s Modified Freeze Module:
(The modified version above but revamped once again. Please check for the one that suits you best! This one is better than Thunder’s modified version btw, although the ice layer is removed. Read his changes in his post)

Showcase (Higher resolution in the video link at the bottom):

NPC being frozen Player being frozen

Boss in my game (Using this module)

Click here to see all!

See more screenshots!

image

image

image

image

:memo: Notes & Features:

  • This mothod allows us to freeze rigs and it lets Roblox physics do the rest, so it looks more realistic than anchoring the target
  • Parts will be covered in a custom ice mesh, MeshPart will be cloned with their properties set to be similar to the ice mesh (You cannot change a MeshPart’s MeshID though a script and this is way cooler) & SpecialMesh will be cloned with its parent (Part) to keep the same shape
  • Animation is frozen (stopped) while being frozen (Works on Players/Rigs/NPCs, etc…)
  • There are some settings to help you customize the ice layer & effects to whatever you like!
  • This post is just a short tutorial for my module, you can modify it however you want but if you have any question, feel free to ask me for help!
Setup!

Everything we have in this Freeze Module include:

1. Set up the function to use it from any scripts

Let the module script stays in a specific place so you can edit once to apply changes to all of them and run the function just by calling it

  • First of all, you need to take the module from the link below and insert it into your experience from the Toolbox

    This will probably be the last step for the more experienced scripters out there but lets just continue lol
  • Now put the FreezeModule in somewhere like ServerStorage or ServerScriptService
    The module will not run by itself until it’s called by another script
  • How to call the function and pass arguments into it:
local FreezeModule = require(game:GetService("ServerStorage").FreezeModule)

FreezeModule.Freeze(workspace["Target"], 3)

Insert a new Script and simply require the module (I put the FreezeModule in ServerStorage)

  • You need 2 arguments: A target and a duration (Seconds)
    In case you need to send a target as an argument but its name has space (Admin command for example), move down to below, this module also has sanity checks for typos or wrong value types so it won’t break if you accidently make a mistake like using an admin command
  • Target can be a rig, a player’s character, an NPC model, etc… as long as they have a HumanoidRootPart. Make sure to check if the Target’s Health is higher than 0 if neccessary!

2. Stop the target’s movement & the animation

Freeze the animation at the current frame
Stop the movement (Walking/Jumping)
Set HumanoidStateType to Physics so the target can fall down, get pushed, etc…
Disable active scripts in the character (Not necessary but this can prevent some bugs, errors or prevent the target from performing actions while being frozen

3. Create an ice layer that covers the target based on its size

Cover every single body Part & MeshPart with customizable, randomizable ice layer
Use Debris service to clean up the ice (I also have alternative methods here like task.delay())
Tween the ice layer to make it cooler

4. Other freezing effects & sounds based on the freeze duration

Freezing + Ice shattering effect
Sound plays faster if the freezing duration is shorter than its length
Make it even cooler

:scroll: 3/4 Examples (From the examples that come with the module):
image

Code snippets from the examples in the module!
  • #1: Call the Function & Pass the arguments & Target
local Duration = 5
local Target = workspace:WaitForChild("Name", 10)

local FreezeModule = require(game:GetService("ServerScriptService").FreezeModule)

if Target then
	FreezeModule.Freeze(Target, Duration)
end
  • #2: Freeze on hit
-- Put this in a Part or anything that can use Touched event and modify it to what you want
-- Don't worry about the debounce/cooldown/delay we already check for that in the FreezeModule
-- Want to add time to the freeze duration? Work for it! I'm just a modeler with a bit of scripting experience
local Duration = 2

local FreezeModule = require(game:GetService("ServerScriptService").FreezeModule)

script.Parent.Touched:Connect(function(Hit)
	if Hit and Hit.Parent and Hit.Parent:IsA("Model") then
		local Target = Hit.Parent
		
		if Target:FindFirstChildOfClass("Humanoid") then
			local Humanoid = Hit.Parent:FindFirstChildOfClass("Humanoid")
			FreezeModule.Freeze(Target, Duration)
		end
	end
end)
  • #3: Freeze with loop (All rigs, can ignore Players if you want)
-- Don't worry about the debounce/cooldown/delay we already check for that in the FreezeModule
local Duration = 5

local FreezeModule = require(game:GetService("ServerScriptService").FreezeModule)

-- Freeze all models in the workspace if they have a Humanoid & HumanoidRootPart (Both players and NPCS)
for _, v in pairs(workspace:GetChildren()) do
	if v:IsA("Model") and v:FindFirstChildOfClass("Humanoid") then
		-- if game:GetService("Players"):GetPlayerFromCharacter(v) then return end -- If the child is a Player, it's ignored (Only freeze NPCs)
		-- Remove "return end", add "not" above and put another "end" below if it fails to check lol
		coroutine.wrap(function() -- Freeze all of them at the same exact time
			local Target = v
			FreezeModule.Freeze(Target, Duration)
		end)()
	end
end

:space_invader: Full code/script:

-- // Quick notes // --
--[[
	Normal version. Want an unfreeze function? Get the modified version from the devforum post
	By Thunder (@ThunderDaNub)
	DevForum post: https://devforum.roblox.com/t/%E2%9D%86-freeze-module-make-a-cool-frozen-effect-%E2%9D%85/2778467
	Showcase video: In the DevForum post
	No credits required. Free to use in your experiences. But credits are still appreciated. I'd love to know what cool creations you've made using this!

	Notes: Animation is frozen (stopped) while being frozen (Works on Players/Rigs/NPCs, etc....)
]]

-------------------------------------------------------------------------------------

-- // Simple Customizations // --
local AnchorIfNotMoving = false --[[
==> If the Target barely moves or not moving at all (Velocity.Magnitude < 2) then the ice layer will be anchored, making the Target stays in place
- Set AnchorIfNotMoving to false to make the Target moveable, fall down, pushable, etc (Physics stuff, I suggest you to set it to false)
- If AnchorIfNotMoving is true, Players won't be able to rotate around while frozen
]]
local DisableScripts = true --[[
==> Disable Scripts & LocalScripts in the Target to prevent it from performing actions
- Can also prevent some glitches, bugs and errors
- Players' animations can still play if you don't disable the animation script (Player rigs are special lol)
]]
local DisableToolScripts = false --[[
==> Disable Scripts & LocalScripts inside any Tool/Gear that the target is currently holding
- Can break stuff so just set it to FALSE
]]

local ClassNamesToFreeze = {
	"Part",
	"WedgePart",
	"CornerWedgePart",
	"TrussPart",
	"UnionOperation",
}
--> Types of parts that can be frozen. MeshParts & SpecialMeshes are for another section so please don't add them

local IceSettings = {
	IceSize = 1.2;
	--> Determine how thick the ice layer is (IceSize * Target's Size)
	--| Example: 1 = Same size as the Target's Parts/MeshParts/SpecialMeshes, will create Z-Fighting | 0.5 is half of the Target's size (Smaller) | 1.2 = 20% bigger
	SpecialMeshSize = 1.2;
	--> Determine how thick the ice layer is (SpecialMeshSize * Target's SpecialMeshes' Scale)
	-- Meshes sometimes have really weird shapes so they can make the ice layer look ugly if it's too big
	Name = "Ice";
	TextureID = "";
	--> We don't want the MeshParts to keep their original texture so we set to nothing. You can use your ice texture if you want (Doesn't apply for the IceBlock meshes)
	Color = Color3.fromRGB(128, 187, 219);
	-- = BrickColor.new("Pastel Blue")
	Material = Enum.Material.Ice;
	CanCollide = false;
	--> Can physically interact with other objects?
	CanTouch = false;
	--> Can use Touched event?
	CanQuery = false;
	--> Can interact with Raycast? (Will effect hitbox!)
	CastShadow = false;
	Massless = true;
	--> No mass?
	Transparency = 0.5;
	--> The ice layer's transparency is set to 1 first, then will be tweened to this value
}
-- Effect customization is near the bottom of the module, it's pretty simple to understand

-------------------------------------------------------------------------------------

local Debris = game:GetService("Debris")
local Running = game:GetService("RunService")
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")

local Module = {}

-- Don't like using Debris service for whatever reason? Use this
--[[task.delay(Duration, function()
	Object:Destroy()
end)]]

local function CheckClassName(Object)
	for _, ClassName in ipairs(ClassNamesToFreeze) do
		if Object:IsA(ClassName) then
			return true
		end
	end
	return false
end

-- Create a weak table to store the old walkspeed and jumppower values
local OldValues = setmetatable({}, {__mode = "k"})

-- Function to change the player's walkspeed and jumppower
local function ChangeValues(player, NewWalkspeed, NewJumppower)
	-- Store the old walkspeed and jumppower values in the table
	OldValues[player] = {
		walkspeed = player:FindFirstChildOfClass("Humanoid").WalkSpeed,
		jumppower = player:FindFirstChildOfClass("Humanoid").JumpPower
	}

	-- Change the player's walkspeed and jumppower
	player:FindFirstChildOfClass("Humanoid").WalkSpeed = NewWalkspeed
	player:FindFirstChildOfClass("Humanoid").JumpPower = NewJumppower
end

-- Function to set the player's walkspeed and jumppower back to the original values
local function SetBackValues(player)
	if OldValues[player] then
		-- Find the stored old values for the player
		local OldWalkspeed = OldValues[player].walkspeed
		local OldJumppower = OldValues[player].jumppower

		-- Set the walkspeed and jumppower back to the original values
		player:FindFirstChildOfClass("Humanoid").WalkSpeed = OldWalkspeed
		player:FindFirstChildOfClass("Humanoid").JumpPower = OldJumppower

		-- Remove the old values from the table
		OldValues[player] = nil
	end
end

-- // Functions // --
-- This will check if we sent nothing for the Duration argument to prevent errors
Module.IsArgumentBlank = function(Argument)
	-- Remove all spaces from the argument
	local TrimmedArgument = string.gsub(Argument, "%s", "")

	-- Check if the resulting string is empty
	if TrimmedArgument == "" then
		return true
	else
		return false
	end
end

-- This will check if we sent number for the Duration argument to prevent errors
Module.IsArgumentNumber = function(Argument)
	-- Attempt to convert the argument into a number
	local Number = tonumber(Argument)

	-- Check if the conversion succeeded
	if Number ~= nil then
		return true
	else
		return false
	end
end

-- 2 arguments: Target (Model with a Humanoid object & HumanoidRootPart) + Duration (Number - Seconds)
Module.Freeze = function(Target, Duration)
	-- Check to prevent errors
	if Module.IsArgumentBlank(Duration) then return end
	if not Module.IsArgumentNumber(Duration) then return end
	if not Duration or not Target then return end
	Duration = Duration or 1

	--[[
	Later on, we'll disable all Scripts & LocalScripts in the Target (Not neccessary)
	This is a whitelist (It'll ignore these names, converted to string.lower())
	You don't have to worry about uppercase letters (ABC) as we'll use string.lower (ABC --> abc)
	]]
	local IgnoreList = {"badgereward", "stunscript"}
	local DisableList = {}


	--Check if the Target is already frozen
	local Ignore = false

	for i, v in pairs(Target:GetChildren()) do
		if v.Name == "FrozenTag" and v:IsA("ObjectValue") and v.Value == Target then
			Ignore = true
		end
	end

	-- If not frozen, we'll freeze it
	if not Ignore and Target:FindFirstChild("HumanoidRootPart") then
		-- Frozen tag so the Target can't be frozen again while being frozen (Yk what I mean)
		local Frozen = Instance.new("ObjectValue")
		Frozen.Name = "FrozenTag"
		Frozen.Value = Target
		Frozen.Parent = Target
		Debris:AddItem(Frozen, Duration)

		-- If the Duration is too short, we'll make the tween time of the ice layer even shorter
		local TweenTime
		if tonumber(Duration) >= 1 then
			TweenTime = 0.5
		else
			TweenTime = tonumber(Duration)/5
		end

		-- TweenInfo for all of the ice layer
		local TI = TweenInfo.new(TweenTime, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut)

		local Root = Target:FindFirstChild("HumanoidRootPart")

		-- This is important, if you ONLY want a SINGLE ICE CUBE then this is the size for it. Remove the other parts if so
		local CharacterSize = Target:GetExtentsSize().Magnitude
		if CharacterSize >= 20 then
			CharacterSize = 20
		end

		--[[
		A single ice cube that covers the entire Target model, I make this invisible because I want a cooler frozen effect
		You can remove the other parts and keep this for a single ice cube
		I'm only creating this for the effects
		]]
		local CoverPart = Instance.new("Part")
		CoverPart.Name = "IceCover"
		CoverPart.Color = IceSettings.Color
		CoverPart.Material = IceSettings.Material
		CoverPart.CanCollide = IceSettings.CanCollide
		CoverPart.CanTouch = IceSettings.CanTouch
		CoverPart.CanQuery = IceSettings.CanQuery
		CoverPart.CastShadow = IceSettings.CastShadow
		CoverPart.Massless = IceSettings.Massless
		CoverPart.Transparency = 1
		CoverPart.Size = Vector3.new(CharacterSize, CharacterSize, CharacterSize)
		-- Multiply by a number if you want it to be bigger
		CoverPart.Position = Root.Position
		CoverPart.Parent = Root

		-- Weld it to the HumanoidRootPart
		local Weld = Instance.new("WeldConstraint")
		Weld.Part0 = CoverPart
		Weld.Part1 = Root
		Weld.Parent = CoverPart

		-- If the Duration is shorter than the time length of the freezing sound, we'll make the sound plays faster (Higher pitch as well)
		task.spawn(function()
			local FreezingSound = script:FindFirstChild("Freeze"):Clone()
			FreezingSound.Parent = CoverPart
			if tonumber(Duration) < FreezingSound.TimeLength then
				FreezingSound.PlaybackSpeed = FreezingSound.TimeLength / tonumber(Duration)
				FreezingSound:Play()
			else
				FreezingSound:Play()
			end
		end)

		Debris:AddItem(CoverPart, Duration)

		-- All ice meshes we need to randomize the ice layer
		local IceFolder = script.FreezeEffects["Ice Blocks"]
		local IceBlocks = {IceFolder.IceBlock1, IceFolder.IceBlock2}
		-- Remember to put the names here if you want to add more ice meshes

		for _, v in ipairs(Target:GetDescendants()) do
			-- If we find a part, cover it in a randomized ice mesh
			if CheckClassName(v) and not v:FindFirstChildOfClass("SpecialMesh") then
				if v.Transparency ~= 1 then
					coroutine.wrap(function()
						local IceBlock = IceBlocks[math.random(1, #IceBlocks)]
						local Ice = IceBlock:Clone()
						-- If the Target wasn't moving then anchor the ice to make the Target stay in place (Not neccessary)
						if Root.Velocity.Magnitude < 2 and AnchorIfNotMoving == true then
							Ice.Anchored = true
						else
							Ice.Anchored = false
						end
						-- We set the size to (0, 0, 0) then tween it to the actual size we want for a nice effect
						Ice.Name = IceSettings.Name
						Ice.TextureID = IceSettings.TextureID
						Ice.Color = IceSettings.Color
						Ice.Material = IceSettings.Material
						Ice.CanCollide = IceSettings.CanCollide
						Ice.CanTouch = IceSettings.CanTouch
						Ice.CanQuery = IceSettings.CanQuery
						Ice.CastShadow = IceSettings.CastShadow
						Ice.Massless = IceSettings.Massless
						Ice.Transparency = 1
						Ice.Size = Vector3.new(0, 0, 0)
						Ice.Position = v.Position
						Ice.Orientation = v.Orientation
						Ice.Parent = v

						-- Size is a bit bigger so we can see it and prevent Z-Fighting parts
						-- Set its orientation and position to be like the Part's, then set its parent to the Part)
						local NewSize = Vector3.new(v.Size.X, v.Size.Y, v.Size.Z) * IceSettings.IceSize

						local Tween = TweenService:Create(Ice, TI, {Transparency = IceSettings.Transparency, Size = NewSize})
						Tween:Play()

						-- Weld it to the Part
						local Weld = Instance.new("WeldConstraint")
						Weld.Part0 = Ice
						Weld.Part1 = v
						Weld.Parent = Ice

						Debris:AddItem(Ice, Duration)

						-- The only way to complete stop a player's animation I could find (Only took a few hours because I was editing the wrong script :( bruh)
						local Weld2 = Instance.new("WeldConstraint")
						Weld2.Part0 = Root
						Weld2.Part1 = v
						Weld2.Parent = Ice
					end)()
				end
				-- Same as the Part but we clear its children if it's a MeshPart
				-- We don't need an ice block here because it'll be too blocky, we make it looks like a thin layer of ice covering instead
			elseif v:IsA("MeshPart") and not v:FindFirstChildOfClass("WrapLayer") then
				if v.Transparency ~= 1 then
					coroutine.wrap(function()
						local Ice = v:Clone()
						Ice:ClearAllChildren()
						Ice.Name = IceSettings.Name
						Ice.TextureID = IceSettings.TextureID
						Ice.Color = IceSettings.Color
						Ice.Material = IceSettings.Material
						Ice.CanCollide = IceSettings.CanCollide
						Ice.CanTouch = IceSettings.CanTouch
						Ice.CanQuery = IceSettings.CanQuery
						Ice.CastShadow = IceSettings.CastShadow
						Ice.Massless = IceSettings.Massless
						Ice.Transparency = 1
						Ice.Size = Vector3.new(0, 0, 0)
						Ice.Position = v.Position
						Ice.Orientation = v.Orientation
						Ice.Parent = v

						local NewSize = Vector3.new(v.Size.X, v.Size.Y, v.Size.Z) * IceSettings.IceSize

						local Tween = TweenService:Create(Ice, TI, {Transparency = IceSettings.Transparency, Size = NewSize})
						Tween:Play()

						local Weld = Instance.new("WeldConstraint")
						Weld.Part0 = Ice
						Weld.Part1 = v
						Weld.Parent = Ice

						Debris:AddItem(Ice, Duration)

						local Weld2 = Instance.new("WeldConstraint")
						Weld2.Part0 = Root
						Weld2.Part1 = v
						Weld2.Parent = Ice
					end)()
				end
				-- This is just a bit different
			elseif v:IsA("SpecialMesh") then
				if v.Parent:IsA("Part") and v.Parent.Transparency ~= 1 then
					coroutine.wrap(function()						
						local Ice = v.Parent:Clone()
						for i, v in pairs(Ice:GetChildren()) do
							if not v:IsA("SpecialMesh") then
								v:Destroy()
							end
						end
						local IceMesh = Ice:FindFirstChildOfClass("SpecialMesh")
						Ice.Name = IceSettings.Name
						IceMesh.TextureId = IceSettings.TextureID
						Ice.Color = IceSettings.Color
						Ice.Material = IceSettings.Material
						Ice.CanCollide = IceSettings.CanCollide
						Ice.CanTouch = IceSettings.CanTouch
						Ice.CanQuery = IceSettings.CanQuery
						Ice.CastShadow = IceSettings.CastShadow
						Ice.Massless = IceSettings.Massless
						Ice.Transparency = 1
						IceMesh.Scale = Vector3.new(v.Scale.X, v.Scale.Y, v.Scale.Z) * IceSettings.SpecialMeshSize
						Ice.Position = v.Parent.Position
						Ice.Orientation = v.Parent.Orientation
						Ice.Parent = v.Parent

						local Tween = TweenService:Create(Ice, TI, {Transparency = IceSettings.Transparency})
						Tween:Play()

						local Weld = Instance.new("WeldConstraint")
						Weld.Part0 = Ice
						Weld.Part1 = v.Parent
						Weld.Parent = Ice

						Debris:AddItem(Ice, Duration)

						local Weld2 = Instance.new("WeldConstraint")
						Weld2.Part0 = Root
						Weld2.Part1 = v.Parent
						Weld2.Parent = Ice
					end)()
				end
				--[[
				In here, I disable active Scripts & LocalScripts to prevent the Target from performing actions and possible errors
				They are added to a list and will be disabled later
				Simply remove this and the similar sections below if you don't want this
				]]
			elseif v:IsA("Script") or v:IsA("LocalScript") then
				if DisableScripts == true and not v.Parent:IsA("Tool") then
					if v.Enabled == true then
						-- Ignore if its name is listed in the mentioned list
						if not IgnoreList[string.lower(v.Name)] then
							table.insert(DisableList, v.Name)
						end
					end
				end
				if DisableToolScripts == true and v.Parent:IsA("Tool") then
					if v.Enabled == true then
						-- Ignore if its name is listed in the mentioned list
						if not IgnoreList[string.lower(v.Name)] then
							table.insert(DisableList, v.Name)
						end
					end
				end
			end
		end

		-- Attachment for some of the effects (Like the "Shock Wave", we want it to stay in the center
		local Attachment = Instance.new("Attachment")
		Attachment.Parent = Root

		Debris:AddItem(Attachment, Duration)

		-- Customize your own freezing effects
		-- EmitCount attribute is a Number value. Edit them from the Properties pannel, higher number = more effect particles
		for i, v in pairs(script.FreezeEffects:GetChildren()) do
			if v:IsA("ParticleEmitter") then
				local EffectClone = v:Clone()				

				if EffectClone.Name == "Smoke" then
					local SizeMultiplier = CharacterSize * 1 -- Line 77 (Actually just use Control + F to search for anything you can't find lol)

					EffectClone.Size = NumberSequence.new(0, SizeMultiplier)
					EffectClone.Parent = Attachment
					EffectClone.Enabled = true

					Debris:AddItem(EffectClone, Duration)
				elseif EffectClone.Name == "Sparkles" then					
					EffectClone.Parent = CoverPart
					EffectClone.Enabled = true

				elseif EffectClone.Name == "Shock Wave" then
					local SizeMultiplier = CharacterSize * 1

					EffectClone.Size = NumberSequence.new(0, SizeMultiplier)					

					EffectClone.Parent = Attachment
					EffectClone:Emit(EffectClone:GetAttribute("EmitCount")) -- These ParticleEmitters have an attribute called "EmitCount" (Number value)

					Debris:AddItem(EffectClone, Duration)
				elseif EffectClone.Name == "Specs" then
					local SizeMultiplier = CharacterSize * 0.2

					EffectClone.Size = NumberSequence.new(SizeMultiplier, SizeMultiplier)					

					EffectClone.Parent = Attachment
					EffectClone:Emit(EffectClone:GetAttribute("EmitCount"))
				else
					EffectClone.Parent = Root
					EffectClone:Emit(EffectClone:GetAttribute("EmitCount"))

					Debris:AddItem(EffectClone, Duration)
				end
			end
		end

		-- Disable the Scripts and LocalScripts
		for i, v in ipairs(DisableList) do
			if Target:FindFirstChild(v, true) then
				local Object = Target:FindFirstChild(v, true)
				if Object:IsA("Script") or Object:IsA("LocalScript") then
					Object.Enabled = false
				end
			end
		end

		-- I don't need this but you can use a HighLight for the effect
		--[[
		local Highlight = Instance.new("Highlight")
		Highlight.FillColor = Color3.new(0, 1, 1)
		Highlight.OutlineTransparency = 1
		Highlight.Parent = Target
		Debris:AddItem(Highlight, Duration)
		]]

		-- Save the Target's current WalkSpeed & JumpPower so we can set them back later
		if Target:FindFirstChildOfClass("Humanoid") then
			local Humanoid = Target:FindFirstChildOfClass("Humanoid")
			local Animator = Humanoid:WaitForChild("Animator", 10)
			Humanoid.UseJumpPower = true

			-- Disable the movement. You can try disabling the local player's controls in another LocalScripts (DevForum to learn more)
			ChangeValues(Target, 0, 0)
			-- Freeze any playing animation at the current frame
			if Animator then
				for i, v in pairs(Animator:GetPlayingAnimationTracks()) do
					v:AdjustSpeed(0)
					v:Stop()
				end
			end
			-- Roblox Creator Hub to learn more about all the HumanoidStateTypes
			Humanoid:ChangeState(Enum.HumanoidStateType.Physics)

			-- Wait for the duration to end, then set the WalkSpeed & JumpPower back to before
			-- This may not be the best way to do it as other scripts can overlap this one but I, ThunderDaNub, is just a modeler with a bit of scripting experience
			-- Good luck with creating a new, better system! I hope you can also contribute in this part if you're a more advanced scripter
			task.wait(Duration)	
			Humanoid.UseJumpPower = true
			SetBackValues(Target)
			-- Continue playing the animation
			if Animator then
				for i, v in pairs(Animator:GetPlayingAnimationTracks()) do
					v:AdjustSpeed(1)
				end
			end
			Humanoid:ChangeState(Enum.HumanoidStateType.Freefall)

		elseif Target:FindFirstChildOfClass("AnimationController") then
			local AnimationController = Target:FindFirstChildOfClass("AnimationController")
			local Animator = AnimationController:WaitForChild("Animator", 10)

			if Animator then
				for i, v in pairs(Animator:GetPlayingAnimationTracks()) do
					v:AdjustSpeed(0)
					v:Stop()
				end
			end

			task.wait(Duration)	
			-- Continue playing the animation
			if Animator then
				for i, v in pairs(Animator:GetPlayingAnimationTracks()) do
					v:AdjustSpeed(1)
				end
			end
		end

		task.spawn(function()
			local ShatterSound = script:FindFirstChild("Ice Shatter"):Clone()
			ShatterSound.Parent = Root
			ShatterSound:Play()

			Debris:AddItem(ShatterSound, 2)
		end)

		for i, v in pairs(script.FreezeEffects:GetChildren()) do
			if v:IsA("ParticleEmitter") then
				local EffectClone = v:Clone()				
				if EffectClone.Name == "Shock Wave" then
					local SizeMultiplier = CharacterSize * 1

					EffectClone.Size = NumberSequence.new(0, SizeMultiplier)					

					local Attachment = Instance.new("Attachment")
					Attachment.Parent = Root

					EffectClone.Parent = Attachment
					EffectClone:Emit(EffectClone:GetAttribute("EmitCount"))

					Debris:AddItem(Attachment, Duration)
				elseif EffectClone.Name == "Specs" then
					local SizeMultiplier = CharacterSize * 0.2

					EffectClone.Size = NumberSequence.new(SizeMultiplier, SizeMultiplier)			

					local Attachment = Instance.new("Attachment")
					Attachment.Parent = Root

					EffectClone.Parent = Attachment
					EffectClone:Emit(EffectClone:GetAttribute("EmitCount"))

					Debris:AddItem(Attachment, Duration)
				end
			end
		end

		-- Enable the Scripts & LocalScripts we disabled before.
		-- Beware that this is not a good way to do so because I'm only checking for the names, some of them may share a similar name and cause issues
		task.wait()
		for i, v in ipairs(DisableList) do
			if Target:FindFirstChild(v, true) then
				local Object = Target:FindFirstChild(v, true)
				if Object:IsA("Script") or Object:IsA("LocalScript") then
					Object.Enabled = true
				end
			end
		end
		table.clear(DisableList)
	end
end

return Module

:film_projector: Showcase videos:

:cool: Credits:
Feel free to use and modify in your experiences. Any credits are appreciated

Sorry for mass pinging but I appreciate your help!

64 Likes

I’ll update this if necessary. The script is kinda long so it’s up to you to improve it
I’m just a modeler with a bit of scripting experience so any feedbacks or contributions are appreciated!

1 Like

Very cool! I’ll add the model to my inventory in case I need it for the future. Thanks!

2 Likes

Thank you for this awesome resource!

This is the smoothest public resource for a freeze debuff I’ve seen. Your contribution to the community is much appreciated! Good luck to all developers who use this resource for their games, and good luck to you Thunder for your future projects. :slight_smile:

1 Like

Very cool effect!

Space frozen!

Thank you very much for sharing it!

4 Likes

Awesome I gonna use this right now!

1 Like

:snowflake: Thank you all for the kind feedbacks and especially the extremely cool demo of using this module! I really like them and I hope this module can help you guys as well! :cool:

To clear up some confusions (Apologize for that), I just added some extra info about the Freeze Module

  • Examples (There are 3 examples that come along with the module, I’ll add more soon and make the script easier to customize)
  • Check Code snippets spoiler part to see 2 of them
    image
  • Improved the ice layer!
  • New very simple settings!
    image
2 Likes

I cannot figure out how to scale/position the SpecialMeshes and MeshParts properly so there will be some parts that aren’t completely covered in the ice layer
Also it’ll just be an ice block if the Target has CharacterMesh (Old R6 stuff)
Any help would be really nice if you know how to fix that

to do that you should check out the humanoidDescription.
or you can calculate the new size based off a coparison of the original size sample and the new size sample. Divide the new size by the original size. This ratio will reflect the scale difference. So if you NPC has a Left Arm of 10 units x and the orignal is 1 units x the scale would be 10.
I also wrote some code that will scale pretty much anything including bones, welds, humanoids, hipheight, motor6Ds and particles.

2 Likes

Final update for the Freeze Module!

  • Now can also freeze/stop Player’s animations
  • 1 more example script (Parented in the module like the other 3)

image

1 Like

Important bug fix!
Make sure you get the current version from this post or the marketplace model (Updated)

  • Fixed the bug that would let players continue moving if they were holding a tool/gear
  • New setting for disabling tool/gear scripts (Not recommended so it’s false by default)

image

Also, thank you all so much for the support! :D

Update: Added a limit for the CharacterSize calculation so that it cannot crash the game in case the character is too massive or its body parts fling off

It seems that the effect can somehow crash you if it’s too big
I’ve changed the max size from 100 to 20 (Yes once again)

if CharacterSize >= 20 then
	CharacterSize = 20
end

Changed “Part” on line 173 to “BasePart”
I did not think about rigs that use WedgePart & Sphere parts, also just learned this recently

for _, v in ipairs(Target:GetDescendants()) do
			-- If we find a part, cover it in a randomized ice mesh
			if v:IsA("BasePart") and not v:FindFirstChildOfClass("SpecialMesh") then

IsA("Part") --> IsA("BasePart")

Now also freezes the animation of a rig without Humanoid object by checking their AnimationController

elseif Target:FindFirstChildOfClass("AnimationController") then
			local AnimationController = Target:FindFirstChildOfClass("AnimationController")
			local Animator = AnimationController:WaitForChild("Animator", 10)

			for i, v in pairs(Animator:GetPlayingAnimationTracks()) do
				v:AdjustSpeed(0)
				v:Stop()
			end
			
			task.wait(Duration)	
			-- Continue playing the animation
			for i, v in pairs(Animator:GetPlayingAnimationTracks()) do
				v:AdjustSpeed(1)
			end
		end

Before:
image

After:
image

Huge update!
Since someone asked me, I spent quite a while to make this, introducing…
The secondary, modified version that comes with an UNFREEZE function (No duration)

  • Separate Freeze & Unfreeze functions, so there’s no duration in this version
  • Targets’ Walkspeed & JumpPower are stored in a weak table (No worries they don’t overlap each other) and then set back to the stored WS & JP when you call the unfreeze function on the same targets

Make sure to check the new examples (Parented inside the modified module) if you don’t know how to use!

Frozen:
image
The mech has no Humanoid, just an AnimationController, works perfectly

Unfrozen:
image
Walkspeed & JumpPower were randomly assigned before running, and they went back to the original values without any issues!

Note: This modified version has nothing to do with the first version. Both are up-to-date without issues from my play testing. The choice is yours, feel free to modify them to your liking

1 Like

I’m well impressed at how well-made this is.


But you should at least make it readable, like this:


Compared to this:


And add sections:


Ngl, for a modeler, you earned my respect. I can’t be bothered reading the entire ModuleScript but the first few blocks of code impressed me a lot.

1 Like

I see, will try to make it more readable soon
Thanks for the feedback

1 Like

Hi,

I am trying the new version and it jacks up my pants after being frozem

Looks like they are somehow twisted…

How they look normally

image

It does not happen every time but is repeatable to see the issue

1 Like

Hi
Thanks for reporting
It seems like Roblox layered clothing is quite weird so after doing some testing for an hour, I decided to exclude them from the freezable parts and added an extra setting

They will always be buggy while being frozen if an extra part is added to the character
But they return to normal after being unfrozen so I think that shouldn’t be a problem
Who needs to freeze clothes anyways?
image

(Yes I used your character and also wore some layered clothes)
image

Update:

  • Added the function that store the character’s old Walkspeed & JumpPower values in a weak table to set back later (From the modified version)
  • Also added an extra settings to let you change freezable parts (TrussPart, WedgePart, etc…)
  • Fixed ice cubes being very big due to the “Part to BasePart” from the previous update. Now meshes shouldn’t look like a cube anymore

Removed amogus
image

Added giga mech
image

1 Like