What is the most efficient way to tween a lot of objects

So, I’m coding a ability for one of my game’s classes, Phasewave, that ability allows him to shoot ziplines and make them discharge a electrical pulse, which stuns enemies on top of it


it have that long red trail that quickly speeds up, each segment needs to create their own tween due to the properties not always being the same (sizes don’t always match)
I was able to decrease the segment creation lag by making a object pooling module, which allowed me to make the whole zipline flash instantly without lagging

but I still wanted to be able to optimize it even more, is it possible to i make the tween creation more optimized? or am I over-optimizing it? there are probably gonna be a lot of Phasewaves per match, so I wanted to make sure the game is still running smoothly

1 Like

Have you considered using BulkMoveTo to animate parts?

1 Like

If the final product is only like the first video (not flashing the whole zipline at once) I think the cheapest way with a similar 2D result would be a Trail instance moving down the zipline via setting the attachment’s world positions every RenderStepped.

If you want the same 3D look I think using BoxHandleAdornments instead of parts should be faster.

One last note and you may already be doing this, you should be running all visual effects on the clients and NEVER the server. Otherwise the server wastes resources replicating every instance change from the effect.

uhh… its actually being ran on the server… it does that because the trail doubles as a hitbox

Just use TweenService! Tried to do this before with vector math but it just made it 10x slower.

If you want to improve the performance you should definitely move the vfx onto the client. You could even have the hitbox calculation done on the client for the player’s own character and have it fire back to the server if a hit happens. This would mean a few things though:

  1. Players would be able to dodge the attack more accurately as the visual and hitbox is all on the client, this improves the experience for the majority of the playerbase.
  2. Exploiters could falsely say they never got hit, which is a flaw.

Another thing is you don’t really need to use parts as a hitbox if you know where the player is on the zipline and where the attack currently is, which is another performance boost if you adapt this.

gonna try doing this then, thanks!

1 Like

Never knew this was a thing, wow.

How is your ui Like Thiss?? bruh

Rotated parts with Surface Gui’s, attached to the players camera if I’m not mistaken? Looks very cool btw! Wish I had thought of something like that myself.

Surface GUIs! and some funky CFrame math to calculate position, rotation, wobble and offset

1 Like

Yes but how to make it scalable for widescreens like phone i need a code

i just use some size converter algorithm, like this

if typeof(size) == "UDim2" then
			local aspectRatio = viewportSize.X / viewportSize.Y

			local radVerticalFOV = rad(camera.FieldOfView)
			local horizontalFOV = 2 * math.atan(math.tan(radVerticalFOV / 2) * aspectRatio)

			local pixelSize = Vector2.new(
				size.X.Scale * viewportSize.X + size.X.Offset,
				size.Y.Scale * viewportSize.Y + size.Y.Offset
			) 

			local sizeWeights = Vector2.new(
				pixelSize.X / viewportSize.X, 
				pixelSize.Y / viewportSize.Y
			)

			local studSize = Vector2.new(
				2 * depth * math.tan(horizontalFOV / 2),
				2 * depth * math.tan(radVerticalFOV / 2)
			)			

			local stretchFactors = Vector2.new(
				math.tan(rad(rotation.Y)),
				math.tan(rad(rotation.X))
			)

			local adjustedSize = Vector2.new(
				studSize.X * sizeWeights.X * (stretchFactors.X + 1),
				studSize.Y * sizeWeights.Y * (stretchFactors.Y + 1)
			)

			size = Vector3.new(adjustedSize.X, adjustedSize.Y, 0.1)
		end

you could probably use parallel threads (which im not gonna talk abt) or/and a custom tween

in using a custom tween, you could save on a lot of resources by negating the amount of individual-yet-similar calculations that would otherwise happen using TweenService. something like this (lots of arguably unnecessary micro-optimizations present, srry):

local startTime = time()
local tweenDuration = 1.0
local goalSizeIncrease = 3.0 -- in studs, just a float since X/Y size are gonna have the same increase & Z size wont be changing
local originalSize = 0.5 -- in studs
local Vector3New = Vector3.new()
local CustomTween = RunService.Heartbeat:Connect(function(_)
	local alpha = (time() - startTime()) / tweenDuration
	if alpha > 1 then -- if tween finished
		CustomTween:Disconnect()
		-- reinsert objects into object pool or w/e
	end)
	-- apply ur favorite easing to `alpha` here if you want
	local newSize = originalSize + goalSizeIncrease*alpha
	for _, RailVisualObject in ipairs(rail_visuals) do -- might be able to use another iterator? idk off the top of my head. yay microoptimizations
		RailVisualObject.Size = Vector3New(newSize, newSize, RailVisualObject.Size.Z) -- could store Z sizes in an array to avoid `RailVisualObject.Size.Z`
		-- color and transparency are pretty self-explanatory i think, remember to calculate the `Color` outside of this loop
	end
end)

the raw amount of objects involved means its always gonna be O(n), which is just a hard limit on the visual you chose

also this, very much this ^

PS: have you got a module you’re using for the splines/ziplines

I was already using coroutine.wrap on my recursive search function, but i recently removed as I felt it was doing more harm than good
and I tried to make a custom tween module that I could use for it, but i accidentally forgot about optimizing it well enough so it made the lag increase a lot, I’m probably gonna retry making it
and I don’t really have any module for the pulse flash, at least none that I can remember this moment

i meant for generating/following the splines lol, assuming they are splines

it’s just some funky bezier curve module one of my friends made, but yea there’s a module for that, but no function that actually follows the path