Most Efficient Way to Create a Rainbow Effect

Hello!

I’ve recently made a rainbow gamepass for a game I’m working on, and everything works well apart from one thing; the purpose of the gamepass itself.

The rainbow applies to all the parts in a specific model (~60 parts) and is server-sided. I figured out how to make that work, but it would cause massive lag as it was a while wait() do loop.

I don’t really know any other ways to make a rainbow, so could someone please teach me one of the fastest and most efficient way to turn a couple dozens of parts’ colour into a nice, smooth rainbow?

Any help is greatly appreciated! This feature is also the last one on the list before I start working on the game’s content itself before its Beta release, so I’d like to finally get done with it.

2 Likes

if your problem is lag you could use client-sided effects.

I’ve thought of that, but the rainbow is actually part of a customization gamepass and I doubt anyone would be interested in buying it if the rainbow would only appear to the client.

1 Like

There’s a few ways to go about it however all the ones I know are kinda janky for one reason or another.

Personally, the best way I can think of doing it is starting off with a hue, setting all the parts to that hue, then shifting the hue forwards by x amount (more = faster, but more noticable shift in colour) and looping that forever
Only issue with that is the more parts you need to colour, the slower it is and the more noticable the colour change may be since it would be changing all the parts one by one.

A kind of hacky way (in other words, the worst way) to do it would be having a script in each part listening to one value (the colour) and just changing the colour to it every time it changes, then just having one final script to slowly shift the hue along. Would be faster, since it’s all individual threads, but it’s atrocious practice since it’s using a billion scripts instead of just one (takes up way more memory and all that)

Oh also, replacing wait() with task.wait() will be significantly faster, to the point where I daresay you shouldn’t need to worry about lag for the most part.

The lag isn’t caused by wait() being slow, but by wait() being fast (30 Hz IIRC). That means it updates roughly 60 parts 30 times a second on the server, which is what causes a lot of lag.

You can use TweenService to make the rainbow bigger and change its position if needed.

Before I start I’m going to address a few things:

This isn’t exactly how this works. Regardless of how many threads are running you are enacting the same processes either way. You could defer 100 threads from an individual script to the same end result. Roblox runs about its task scheduler, if something is holding up the task scheduler because its calculations take time- there will be a delay regardless of how many bazaar scenarios you try to fix it that don’t directly address the problem.

This would have the opposite effect of what you think it would have. task.wait() is directly equivalent to RunService.Heartbeat:Wait()- this means that every single heartbeat that the task scheduler cycles will run these changes. IE- you are running this more often = more consistent processing = > chance of lag. That doesn’t mean that it isn’t part of the solution, it just means it doesn’t cause less “game lag”.

cpguy is correct in saying that you should transfer from wait. Not for that exact reason that they stated- but because global wait is either deprecated or on-track to receive deprecation. I can’t keep up with deprecations so consistently. Working more directly with Roblox’s task scheduler gives you more control over your game and is in general better.


Okay, so what is the solution?

The first thing worth noting is that at the end of the day having so many parts cycling color is going to hold its innate performance regardless of how you handle it. You will need to accept that. That said, you can benchmark which solution works best fairly easily (use os.clock()-timestamp on each option and weigh its performance). Also keep in mind that certain things will process heavier than others. Semi-tansparent parts process heavier than solid parts. I imagine neon would impact processing negatively. Etc…

I would personally steer clear of TweenService, but that’s just my opinion, that many variables and that much code clutter when working with a lot of parts just impacts readability to me. And I imagine that if you benchmarked it against most other choices you would see the difference immediately.

The best solution is going to end up being whatever does as little math as possible and can apply its changes fast. This probably means you’re going to want to manipulate the part’s color directly from the script. You can create a table of all applicable parts and who they belong to, or whatever else might be needed and just iterate across that, per task cycle, to achieve your desired result.

The other option, depending on the rainbow’s functionality, is to create a rainbow out of other objects than parts. For instance you could probably make a pretty nice Rainbow with an individual beam object. In fact if it’s at all possible I would steer you in that direction over a bunch of parts. It’s easier to manage and just makes more sense.

All this to say, if you learn about benchmarking code you can actually test and answer this question for yourself.

2 Likes

Thank you for the reply.
There is a couple of things to over over here.

The first thing I’d like to say is that I found a quick and efficient enough way to create a rainbow effect. It refreshes at a slower rate, but is still fast enough to make it look smooth. The hue of the colour depends on the tick(). Here’s the important part of the code for anyone who’s interested:

while rainbow.Value do task.wait(1/20)
	for i = 1, #parts do
		parts[i].Color = Color3.fromHSV(tick() % 20/20, 1, 1)
	end
end
if not rainbow.Value then
	for i = 1, #parts do
		parts[i].Color = Color3.fromRGB(200, 200, 200)
	end
end

0.1% to 0.3% activity average - not great but not terrible
Animation
(Compression might mess with the framerate and make it look less smooth)

I think that your os.clock() and Beam ideas are good, and I’ll most likely use both in the future (os.clock() to determine the best solution when working with loops and Beams for future customization)
I’d also like to thank you for the valuable info regarding Roblox’s Task Scheduler, and I’ll definitely be wary of using wait() in the future.

Thank you very much!

6 Likes