Making Rainbow Text - jorjic/fivem-docs GitHub Wiki

Please stop abusing math.random to create "rainbow" text. Today, I'll be outlining using math.sin to create visually appealing rainbows. For the lazy, I'll post the full example code.

local function RGBRainbow( frequency )
	local result = {}
	local curtime = GetGameTimer() / 1000

	result.r = math.floor( math.sin( curtime * frequency + 0 ) * 127 + 128 )
	result.g = math.floor( math.sin( curtime * frequency + 2 ) * 127 + 128 )
	result.b = math.floor( math.sin( curtime * frequency + 4 ) * 127 + 128 )
	
	return result
end

Citizen.CreateThread( function()
	while true do
		Wait( 0 )
		
		SetTextFont( 4 )
		SetTextScale( 1.0, 1.0 )
		local rainbow = RGBRainbow( 1 )
		SetTextColour( rainbow.r, rainbow.g, rainbow.b, 255 )
		SetTextOutline()
		SetTextEntry( "STRING" )
		AddTextComponentString( "Rainbow Text" )
		DrawText( 0.029, 0.75 )
	end
end )

Explanation

Time to break this down. Let's build a function to create a rainbow sine wave. For those of you that skipped trigonometry, sine waves look like this:

Sine Wave

We can create a basic sine wave by using the math.sin function and passing the current up time in milliseconds as the first argument.

math.sin( GetGameTimer() )

This gives us a range of values, depending on when we run it, ranging between -1 and 1. By applying a little bit of math, we can get it to return between 0 and 255.

math.sin( GetGameTimer() ) * 127 + 128

Now we can directly apply this value to create an RGB value, without violating the numerical boundaries of 0 and 255. However, using this value for red, blue, and green at the same time will cause our text to change between black and white. We can tweak our code above to produce an out-of-phase sine wave, which will get us the results we want.

math.sin( GetGameTimer() + 0 ) * 127 + 128
math.sin( GetGameTimer() + 2 ) * 127 + 128
math.sin( GetGameTimer() + 4 ) * 127 + 128

By combining these out-of-phase waves into an RGB value, we end up following this path on the hue-saturation wheel:

Hue Saturation Wheel

With the above information in our knowledge, we can finally build a function to handle the work for us. In the below example, I'll be doing things a little differently than I did above. I've added comments in the code to explain my reasoning.

local function RGBRainbow( frequency )
	--Create a table to store our values, so that we can give them as a result.
	local result = {}
	--Convert the millisecond result of GetGameTimer() into seconds, purely to make frequencies nicer
	local curtime = GetGameTimer() / 1000
	
	--Create new entries in the results table, and assign values to them.
	--I've added math.floor() to each equation, which will chop off the remaining decimal and leave us with a nice integer.
	--( GTA will otherwise treat the value as a float and produce yucky colors )
	result.r = math.floor( math.sin( curtime * frequency + 0 ) * 127 + 128 )
	result.g = math.floor( math.sin( curtime * frequency + 2 ) * 127 + 128 )
	result.b = math.floor( math.sin( curtime * frequency + 4 ) * 127 + 128 )
	
	return result
end

Result

Now, we can simply call our new function and use the values to make aesthetically-appealing rainbow text. Below is an example usage of the function:

Citizen.CreateThread( function()
	while true do
		Wait( 0 )
		
		SetTextFont( 4 )
		SetTextScale( 1.0, 1.0 )
		local rainbow = RGBRainbow( 1 )
		SetTextColour( rainbow.r, rainbow.g, rainbow.b, 255 )
		SetTextOutline()
		SetTextEntry( "STRING" )
		AddTextComponentString( "Rainbow Text" )
		DrawText( 0.029, 0.75 )
	end
end )

Here's how it looks:

Rainbow Example

Source and Thanks

Huge thanks to krazydad! http://krazydad.com/tutorials/makecolors.php