shaio Posted July 20, 2016 Share Posted July 20, 2016 I'm trying to make a script that changes the color of the car automatically, but I want it to be rainbow colored. I've only gotten it to do random colors. I've seen on many servers where they have rainbow colors, it like switches from turquoise blue to blue and then purple, and then green, and then yellow and what not.. function rgbToggle(player,cmd,value) if not value then outputChatBox("Syntax: /rgb (on/off)",player,0,255,255) end if (value == "on") then setElementData(getPedOccupiedVehicle(player),"rgb","on") outputChatBox("Enabled.",player,0,255,255) elseif (value == "off") then setElementData(getPedOccupiedVehicle(player),"rgb","off") outputChatBox("Disabled.",player,0,255,255) end end addCommandHandler("rgb",rgbToggle) setTimer(function() for _,v in ipairs(getElementsByType("vehicle")) do if (getElementData(v,"rgb") == "on") then setVehicleColor(v,math.random(0,255),math.random(0,255),math.random(0,255),math.random(0,255),math.random(0,255),math.random(0,255)) end end end,300,0) Link to comment
Discord Moderators AlexTMjugador Posted July 20, 2016 Discord Moderators Share Posted July 20, 2016 Firstly, in order to the color transition look smooth, you need to do it clientside using the onClient(Pre/Hud)Render family of events. Timers can be too fast for clients with low FPS and too slow for clients with high FPS, so smooth transition is not guaranteed when using them. About the actual question, I guess that you want your transition to look like a real rainbow. Due to the sun light composition and phenomena which occurs when it hits water in a certain way, a rainbow allows you to see the whole visible color spectrum: As you can see, the highest frecuency (lowest wavelength, 400 nanometers) color is violet, while the lowest frecuency (highest wavelength, 700 nanometers) color is red. We can use interpolateBetween to get the intermediate colors' wavelength and therefore get a rainbow colored car, but how the hell can we transform back the wavelength to actual RGB values usable in setVehicleColor? The answer is simple: the wavelengthToRGBA useful function (I assume truncating the alpha value does not break the color translation in this case). So the code you need to get everything working is: -- Ensure this variable gets set to the vehicle you want the effect on local veh = getPedOccupiedVehicle(localPlayer) -- USEFUL FUNCTIONS -- local function wavelengthToRGBA(length) -- Copied and pasted from the wiki local r, g, b, factor if (length >= 380 and length < 440) then r, g, b = -(length - 440)/(440 - 380), 0, 1 elseif (length < 489) then r, g, b = 0, (length - 440)/(490 - 440), 1 elseif (length < 510) then r, g, b = 0, 1, -(length - 510)/(510 - 490) elseif (length < 580) then r, g, b = (length - 510)/(580 - 510), 1, 0 elseif (length < 645) then r, g, b = 1, -(length - 645)/(645 - 580), 0 elseif (length < 780) then r, g, b = 1, 0, 0 else r, g, b = 0, 0, 0 end if (length >= 380 and length < 420) then factor = 0.3 + 0.7*(length - 380)/(420 - 380) elseif (length < 701) then factor = 1 elseif (length < 780) then factor = 0.3 + 0.7*(780 - length)/(780 - 700) else factor = 0 end return r*255, g*255, b*255, factor*255 end -- ACTUAL SCRIPT -- local startTime = getTickCount() local function rainbowColorVehicle() -- Periodic [0, 1] progress value with 3000 ms period local progress = math.fmod(getTickCount() - startTime, 3000) / 3000 -- You can invert the color order replacing 400 with 700 and viceversa -- The transition can look more interesting by using another easing function local length = interpolateBetween(400, 0, 0, 700, 0, 0, progress, "Linear") -- Get and apply our color local r, g, b = wavelengthToRGBA(length) setVehicleColor(veh, r, g, b, r, g, b, r, g, b, r, g, b) end addEventHandler("onClientPreRender", root, rainbowColorVehicle) A disclaimer: this might not be the most efficient algorithm out there to achieve this, but providing that you know what the undolatory theory of light is it should be very understandable and easy to modify or mantain. Link to comment
shaio Posted July 21, 2016 Author Share Posted July 21, 2016 Holy moly, I was not expecting that. I'm like a script kiddie and ur a pro This is blowin my mind, and I would never think of this, thank you so much! Link to comment
shaio Posted July 21, 2016 Author Share Posted July 21, 2016 Firstly, in order to the color transition look smooth... You're original code didnt work. I tried to make it work both serverside and client side with the cmd i made for it. I want to have an enable and disable feature, to do that I use element data on the vehicle and then loop all vehicles. function rgbToggle(player,cmd,value) if not value then outputChatBox("Syntax: /rgb (on/off)",player,0,255,255) end if (value == "on") then setElementData(getPedOccupiedVehicle(player),"rgb","on") outputChatBox("Enabled.",player,0,255,255) elseif (value == "off") then setElementData(getPedOccupiedVehicle(player),"rgb","off") outputChatBox("Disabled.",player,0,255,255) else outputChatBox(value.." is not a valid argument!",player,0,255,255) end end addCommandHandler("rgb",rgbToggle) local function wavelengthToRGBA(length) local r, g, b, factor if (length >= 380 and length < 440) then r, g, b = -(length - 440)/(440 - 380), 0, 1 elseif (length < 489) then r, g, b = 0, (length - 440)/(490 - 440), 1 elseif (length < 510) then r, g, b = 0, 1, -(length - 510)/(510 - 490) elseif (length < 580) then r, g, b = (length - 510)/(580 - 510), 1, 0 elseif (length < 645) then r, g, b = 1, -(length - 645)/(645 - 580), 0 elseif (length < 780) then r, g, b = 1, 0, 0 else r, g, b = 0, 0, 0 end if (length >= 380 and length < 420) then factor = 0.3 + 0.7*(length - 380)/(420 - 380) elseif (length < 701) then factor = 1 elseif (length < 780) then factor = 0.3 + 0.7*(780 - length)/(780 - 700) else factor = 0 end return r*255, g*255, b*255, factor*255 end local startTime = getTickCount() local function rainbowColorVehicle() for _,v in ipairs(getElementsByType("vehicle")) do if (getElementData(v,"rgb") == "on") then local progress = math.fmod(getTickCount() - startTime, 3000) / 3000 local length = interpolateBetween(400, 0, 0, 700, 0, 0, progress, "Linear") local r, g, b = wavelengthToRGBA(length) setVehicleColor(v, r, g, b, r, g, b, r, g, b, r, g, b) end end end addEventHandler("onClientPreRender", getRootElement(), rainbowColorVehicle) Link to comment
Discord Moderators AlexTMjugador Posted July 21, 2016 Discord Moderators Share Posted July 21, 2016 My code does work, I have just tested it. I wouldn't want to waste the time of both of us with scripts which are wrong, don't you think? The problem with the script is that the code I posted is clientside only, and the command handler you added is designed for the serverside, so it won't obviously work because it assumes and requires different arguments to work. Other than that, the code is working like a charm. Here you have the fixed version of your own code: function rgbToggle(_,value) if not value then outputChatBox("Syntax: /rgb (on/off)",0,255,255) end if (value == "on") then setElementData(getPedOccupiedVehicle(localPlayer),"rgb","on") outputChatBox("Enabled.",0,255,255) elseif (value == "off") then setElementData(getPedOccupiedVehicle(localPlayer),"rgb","off") outputChatBox("Disabled.",0,255,255) else outputChatBox(value.." is not a valid argument!",0,255,255) end end addCommandHandler("rgb",rgbToggle) local function wavelengthToRGBA(length) local r, g, b, factor if (length >= 380 and length < 440) then r, g, b = -(length - 440)/(440 - 380), 0, 1 elseif (length < 489) then r, g, b = 0, (length - 440)/(490 - 440), 1 elseif (length < 510) then r, g, b = 0, 1, -(length - 510)/(510 - 490) elseif (length < 580) then r, g, b = (length - 510)/(580 - 510), 1, 0 elseif (length < 645) then r, g, b = 1, -(length - 645)/(645 - 580), 0 elseif (length < 780) then r, g, b = 1, 0, 0 else r, g, b = 0, 0, 0 end if (length >= 380 and length < 420) then factor = 0.3 + 0.7*(length - 380)/(420 - 380) elseif (length < 701) then factor = 1 elseif (length < 780) then factor = 0.3 + 0.7*(780 - length)/(780 - 700) else factor = 0 end return r*255, g*255, b*255, factor*255 end local startTime = getTickCount() local function rainbowColorVehicle() for _,v in pairs(getElementsByType("vehicle", root, true)) do if isElementOnScreen(v) and (getElementData(v,"rgb") == "on") then local progress = math.fmod(getTickCount() - startTime, 3000) / 3000 local length = interpolateBetween(400, 0, 0, 700, 0, 0, progress, "Linear") local r, g, b = wavelengthToRGBA(length) setVehicleColor(v, r, g, b, r, g, b, r, g, b, r, g, b) end end end addEventHandler("onClientPreRender", getRootElement(), rainbowColorVehicle) I have also optimized the onClientPreRender handler function loop, because looping through every vehicle created is insane and can generate pretty big slowdowns if your server if full of them and that optimization does not modify how the effect looks. Link to comment
Captain Cody Posted July 21, 2016 Share Posted July 21, 2016 You don't have to use onClientPreRender, you could throw it server side with a very low timer. "50ms" which Is 20x smaller then a secound. I'm not quite sure your eyes could spot the difference. Link to comment
shaio Posted July 21, 2016 Author Share Posted July 21, 2016 it looks too fast, colors switch too fast, i want it to be smoother, how do i turn the timing down? Link to comment
Captain Cody Posted July 21, 2016 Share Posted July 21, 2016 turn down how fast the timer goes. Link to comment
EstrategiaGTA Posted July 21, 2016 Share Posted July 21, 2016 Toy around with different times and stay with the one you think it fits the most. Link to comment
shaio Posted July 22, 2016 Author Share Posted July 22, 2016 I tried but i cant get it to go slower, except it like cuts the colors in half, one is different kinds of blue and the rest are like red, yellow, and orange and the blue ends up going slow but the red, yellow, and orange just fly through. Link to comment
Discord Moderators AlexTMjugador Posted July 22, 2016 Discord Moderators Share Posted July 22, 2016 Change the line 51: local progress = math.fmod(getTickCount() - startTime, 3000) / 3000 To: local progress = math.fmod(getTickCount() - startTime, time) / time Being the time variable the time in milliseconds you want the transition from red to violet to last (of course, remember that you can replace time with a number like I did, or else you will have to define the variable somewhere in the code). To achieve the effect you want, I would try 6000 ms first and then change that value until it looks nice. You don't have to use onClientPreRender, you could throw it server side with a very low timer. "50ms" which Is 20x smaller then a secound. I'm not quite sure your eyes could spot the difference. Doing this kind of effects which need frequent updating in the server is definitely so SAMP-ish and unefficient. It will waste bandwidth by syncing the vehicle color each 50 ms, when the clients can already expect that color and apply it by themselves. And in the server you can't get elements by their type which are streamed in so easily, so it will introduce some CPU overhead too. However, if your server has unlimited bandwidth, a hell of CPU and you feel like doing this clientside will make people complain "HEY Y0UR S3RV3R IS SO LAG PLS FIX" only after knowing it is done on their PCs, computing it on the server is the way to go. Link to comment
Captain Cody Posted July 22, 2016 Share Posted July 22, 2016 Something such as that will not kill your CPU and bandwidth, unless you have a thosand timers going at the same time. But yes, it is a bit more unefficient then onClientRender, but I was just thinking of the sync there. Link to comment
shaio Posted July 23, 2016 Author Share Posted July 23, 2016 I tried changing the time but heres what happens, the colors split in half, one half goes slower, the other goes faster.. Link to comment
Discord Moderators AlexTMjugador Posted July 23, 2016 Discord Moderators Share Posted July 23, 2016 I have tried with 6 and 12 seconds and the color transition works as expected: each and every color phase modifies its duration linearly. Can you describe the effect you want more precisely, please? In case you are referring to the abrupt color "jump" between red and violet, it can be fixed by inverting the progress value after each period (that is, the first period goes from 0-1, the second from 1-0, the third back from 0-1, and so on): local startTime = getTickCount() local lastProgress = 0 local alternateOrder = false local function rainbowColorVehicle() local progress = math.fmod(getTickCount() - startTime, 3000) / 3000 if lastProgress > progress then -- Flip interpolation targets after each "restart" alternateOrder = not alternateOrder end -- Save last progress to calculate the above lastProgress = progress -- Take alternateOrder into account to invert the progress progress = alternateOrder and 1 - progress or progress local length = interpolateBetween(400, 0, 0, 650 --[[ Reduced 50 nm here to make the apparent red color be visible less time ]], 0, 0, progress, "Linear") local r, g, b = wavelengthToRGBA(length) for _,v in pairs(getElementsByType("vehicle", root, true)) do if isElementOnScreen(v) and (getElementData(v,"rgb") == "on") then setVehicleColor(v, r, g, b, r, g, b, r, g, b, r, g, b) end end end addEventHandler("onClientPreRender", getRootElement(), rainbowColorVehicle) Link to comment
shaio Posted July 23, 2016 Author Share Posted July 23, 2016 ill prob just record it and show u that way.. Link to comment
shaio Posted July 26, 2016 Author Share Posted July 26, 2016 I have tried with 6 and 12 seconds and the color transition works as expected... Yes that code makes it go as slow as I want it to, but it only does hot colors, not cold colors, like blue.. Link to comment
Discord Moderators AlexTMjugador Posted July 26, 2016 Discord Moderators Share Posted July 26, 2016 This length variable definition should give you the desired result. It sacrifices a bit of prominence of hot colors to give it to blue-ish colors. local length = interpolateBetween(430, 0, 0, 670, 0, 0, progress, "InQuad") Just replace the previous line by this new one. Link to comment
shaio Posted July 27, 2016 Author Share Posted July 27, 2016 but now it only displays hot colors, not the full spectrum. Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now