Need help optimizing afterimage effect

I need help optimizing my after image effect
So i have this afterimage effect in my battlegrounds game but whenever i use it my frames drop instantly from 144 to ~90, I tried everything i could but the performance drop is still huge


Heres the shadow model

Heres the script:

local Lighting = game:GetService("Lighting")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

local Packages = ReplicatedStorage.Packages
local Assets = ReplicatedStorage.Assets

local Signal = require(Packages.Signal)
local Trove = require(Packages.Trove)

local EdgerunnerAssets = Assets:WaitForChild("Edgerunner")

local Shadow = EdgerunnerAssets.Shadow

local FX = workspace.Terrain:FindFirstChild("FX")

local EndSandevistanSignal = Signal.new()

local SandevistanGradients = {
	Color3.fromRGB(83, 255, 103),
	Color3.fromRGB(83, 255, 226),
	Color3.fromRGB(0, 34, 255),
	Color3.fromRGB(255, 42, 74),
}

local FullTransition = 6.0

return {
	["SandevistanStart"] = function(Params: { Character: Model, UserId: number })
		local Character = Params.Character
		local UserId = Params.UserId

		if not Character then
			return
		end

		local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid

		if Humanoid.Health <= 0 then
			return
		end

		local Clones = {} :: { [Model]: number }
		local GradientCount = #SandevistanGradients
		local End = false

		local EffectTrove = Trove.new()

		local CharacterShadow = EffectTrove:Clone(Shadow) :: Model
		CharacterShadow.Parent = FX

		local ShadowHumanoid = CharacterShadow:FindFirstChild("Humanoid") :: Humanoid
		local PlayerDescription = Humanoid:GetAppliedDescription()

		ShadowHumanoid:ApplyDescription(PlayerDescription)

		local ColorCorrection = Instance.new("ColorCorrectionEffect")
		local ScreenEffect = TweenService:Create(ColorCorrection, TweenInfo.new(1), {
			TintColor = Color3.fromRGB(121, 255, 119),
		})

		ColorCorrection.Parent = Lighting

		EffectTrove:Add(ColorCorrection)
		ScreenEffect:Play()

		local EndConnection
		do
			EndConnection = EndSandevistanSignal:Connect(function(ID: number)
				if ID == UserId then
					EndConnection:Disconnect()
					End = true
				end
			end)
		end

		local DeathConnection = Humanoid.Died:Once(function()
			EndConnection:Disconnect()
			End = true
		end)

		local DeltaConnection
		do
			local ElapsedTime = 0
			local Progress = 0

			DeltaConnection = RunService.Heartbeat:Connect(function(DeltaTime: number)
				if End == true then
					DeltaConnection:Disconnect()
					EffectTrove:Destroy()

					if DeathConnection.Connected then
						DeathConnection:Disconnect()
					end

					table.clear(Clones)

					return
				end

				ElapsedTime += DeltaTime
				Progress += DeltaTime

				for Clone, Data in pairs(Clones) do
					local TimePassed = ElapsedTime - Data.Created

					if TimePassed >= 1 then
						local Alpha = (TimePassed - 1) / 0.5
						Alpha = math.clamp(Alpha, 0, 1)

						for _, BodyPart: BasePart in ipairs(Data.BodyParts) do
							BodyPart.Transparency = Alpha
						end

						Data.Highlight.FillTransparency = 0.4 + (0.6 * Alpha)

						if Alpha >= 1 then
							Clone:Destroy()
							Clones[Clone] = nil
						end
					end
				end

				if Progress > 0.15 then
					Progress = 0

					local Position = ((ElapsedTime % FullTransition) / FullTransition) * GradientCount

					local Index = math.floor(Position) + 1
					local Alpha = Position - math.floor(Position)

					local NextIndex = (Index % GradientCount) + 1

					local StartColor = SandevistanGradients[Index]
					local NextColor = SandevistanGradients[NextIndex]

					local Clone = EffectTrove:Clone(CharacterShadow) :: Model

					local CloneColor = Clone:FindFirstChild("Color") :: Highlight

					local BodyParts = {}

					for _, BodyPart: BasePart in ipairs(Clone:GetChildren()) do
						local CharacterBodyPart = Character:FindFirstChild(BodyPart.Name) :: BasePart

						if BodyPart:IsA("BasePart") and CharacterBodyPart then
							BodyPart.CFrame = CharacterBodyPart.CFrame

							table.insert(BodyParts, BodyPart)
						elseif BodyPart:IsA("Accessory") then
							local Handle = BodyPart:FindFirstChild("Handle") :: BasePart

							table.insert(BodyParts, Handle)
						end
					end

					CloneColor.FillColor = StartColor:Lerp(NextColor, Alpha)
					Clone.Parent = FX

					Clones[Clone] = {
						Created = ElapsedTime,
						BodyParts = BodyParts,
						Highlight = CloneColor,
					}
				end
			end)
		end
	end,
	["SandevistanEnd"] = function(UserId: number)
		EndSandevistanSignal:Fire(UserId)
	end,
}

Thanks!

1 Like

First off, humanoids are costly. An optimization I did for my game was removing everything that’s not essential in keeping the characters appearance. I got rid of humanoids, and other things that my character had that was unnecessary to the appearance. So basically just keep the baseparts and the accessories in the clone.

1 Like

Cant do that, i need to keep the clothes of the character.

Removing the humanoid won’t remove the clothes.

This doesn’t work for me either. Do i have to make a custom player rig?

No you don’t. What are method are you using? It should be as simple as this:

local function afterImage(character: Model, duration: number?)
  --Also don't forget to make the character Archivable
 
  local characterClone = character:Clone()
  
  for _, descendant in ipairs(characterClone:GetDescendants()) --Or pairs
    
    if not descendant:FindFirstDescendantWhichIsA("Basepart") and not descendant:Is("Basepart") then 
    --Guard against body accessories but don't destroy them since destroying them will destroy the basepart descendants
      
      descendant:Destroy()
      
      continue

    end


    if descendant:IsA("Basepart") then --Guard against body accessories 
      descendant.Transparency = 0.5
      descendant.Anchored = true
      descendant.Cancollide = false

    end

    if duration then
      task.delay(duration, function()
        characterClone:Destroy()
      end)
    end

    return characterClone --Optional

  end

This code isn’t even valid…
You are using a custom character.

Can’t really say for certain if this has any effect, but you’re destroying and cloning the same model very frequently. You should pre-generate every clone and recycle them instead. Also, using a sequential list for them would then be a straightforward upgrade and slightly improve performance, too. The algo would be keeping track of the last used clone and stepping through the list one at a time with an index always pointing to the freshest clone (which implies the next clone is the oldest).

I’ve also heard that Instance.Clone is pretty slow. Maybe you could have your own Clone building function? You could, of course, keep the same logic of building clones progressively, it’s just that I think you’d need to start recycling once they die instead of destroying.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.