Colour Cycling of day and night

Started by xenogia, Fri 08/05/2009 03:08:33

Previous topic - Next topic

xenogia

I have looked on the forum for a thread about colour cycling day and night.  A good example of this is the Quest for Glory series.  Is this possible using 32-bit mode in AGS.  I know you can put in global integers to determine that it is day or night and use two seperate images.  But I would look a whole colour cycling animation to go with it.

Any ideas?

GarageGothic

You can't do color cycling in 32-bit short of running a pre-made animation. What you can do however, is draw the night background on top of the day background at variable transparency using DrawingSurface functions. It's best not to use it every game loop as that will slow down the game on low-end CPUs, but calling it every second or two decreasing the transparency by one percent every time should give you a nice day-to-night effect.

xenogia

So you would put something like the following in repeatedly execute using a while statement.  I've grabbed the example code from the AGS documentation. How would you call it every second or two?

Code: ags

DrawingSurface *mainBackground = Room.GetDrawingSurfaceForBackground(0);
DrawingSurface *nightBackground = Room.GetDrawingSurfaceForBackground(1);
mainBackground.DrawSurface(nightBackground, 50);
mainBackground.Release();
nightBackground.Release();

GarageGothic

#3
Something like this should do the trick (not tested tested, but has problems with high loop counts):

Code: ags
DrawingSurface* backgroundbackup;
int fadeloops;
int fadetimer = -1;
int currentfadetrans;
int fadetoframe;

function FadeToBackground(int frame, int loops) {//loops is the number of frames the fade should take, so higher means slower fade speed
  if (frame == GetBackgroundFrame()) return;
  SetBackgroundFrame(GetBackgroundFrame()); //to make sure the background isn't animating
  DrawingSurface* currentbackground = Room.GetDrawingSurfaceForBackground();
  backgroundbackup = currentbackground.CreateCopy();
  currentbackground.Release();
  fadetoframe = frame;
  fadetimer = loops;
  fadeloops = loops;
  currentfadetrans = 100;
  }

function on_key_press (eKeyCode keycode)  {
  if (keycode == eKeyF) {
    if (fadetimer == -1) FadeToBackground(1-GetBackgroundFrame(), 80);
    }
  }

function repeatedly_execute() {
  if (fadetimer > -1) {
    int fadetrans = 100*fadetimer/fadeloops;
    if (fadetrans != currentfadetrans) {
       DrawingSurface* currentbackground = Room.GetDrawingSurfaceForBackground();
       if (fadetrans <= 0) {
         currentbackground.DrawSurface(backgroundbackup);
         currentbackground.Release();
         backgroundbackup.Release();
         SetBackgroundFrame(fadetoframe);
         fadetimer = -1;
         }
       else {
         DrawingSurface* endbackground = Room.GetDrawingSurfaceForBackground(fadetoframe);
         currentbackground.DrawSurface(backgroundbackup);
         currentbackground.DrawSurface(endbackground, fadetrans);
         currentbackground.Release();
         endbackground.Release();
         fadetimer--;
         currentfadetrans = fadetrans;
         }
       }
     else fadetimer--;
     }
  }
  


Edit: OK, code fixed and tested to work. I added a shortcut key ('F') just to test out the function, the on_key_press section can of course be removed if you're calling the function from script.

xenogia

Would I have to put all that code in each room, or is it a globalscript affair?

GarageGothic

No you can put it in the globalscript, then import the FadeToBackground function in the global header (or put the whole thing in a module if you prefer), then call FadeToBackground from the room.

I'm in the middle of testing the code, so I may make a few corrections during the next couple of minutes.

xenogia

#6
Thank you so much, amazing work.. I look forward to your updates.

NOTE:
You might as well make a module of it and add it to the modules list on the forum :)

Trying to apply it but I am get undefined token when I try to call the function.

GarageGothic

#7
Try the code I just posted, it should work. The debug key ('F' to fade) assumes that your day/night backgrounds are frames 0 and 1.

I may turn this into a module, but to be honest the reason I don't release more modules is that I can't be arsed to write the documentation. For the code to be fully functional I also need to add an event for eEventLeaveRoom so that the backup copy of the background doesn't remain in memory plus some function to make fades work across rooms (sun starts setting in one room, you walk to another room while the background is still fading, and in the new room the fade continues). Start and stop timer commands could also be useful.

Edit: Argh, I keep getting a "cannot draw surface unto itself" error with slower fades and I have no idea why. I'll look into it again tomorrow.

xenogia

Thanks for the help GarageGothic, now I am just trying to get the characters to change light level.

I am guessing I would have to add a while routine using for example region[1].Lightlevel = a or something to that description with that function.

GarageGothic

Yeah, you could use the fadetrans variable as a modifier, and in the "if (fadetrans != currentfadetrans) {" section of the code set

Code: ags
region[1].LightLevel = maxlightlevel-(fadetrans*(maxlightlevel-minlightlevel))/100);


It's a shame that regions don't support custom properties, otherwise it would be very quick to set all this up in the editor by adding max/min light level properties. It would be somewhat easier if you use SetAmbientTint to adjust light levels for the entire room, but perhaps you need more detailed control for different screen areas.

xenogia

Your right about the SetAmbientTint, so would I use the same equation with SetAmbientTint.  Sorry for all the questions but I am learning a lot from your code.  I also noticed that the code you posted just before makes them brighter, how would you reverse that to make them darker.

GarageGothic

#11
If you can settle with using AmbientTint, you could do it like this:

In the editor, create two custom properties (Number type) called MaxAmbientLight and MinAmbientLight, set them to only apply to rooms

Then in the "if (fadetrans != currentfadetrans) {" section of the repeatedly_execute, put these lines:

Code: ags

int minlightlevel = GetRoomProperty("MinAmbientLight");
int maxlightlevel = GetRoomProperty("MaxAmbientLight");
int tint = 40; //as an experiment, I try making the light more bluish as it gets darker
if (fadetoframe == 1) SetAmbientTint(0,0, 255, ((100-fadetrans)*tint)/100, minlightlevel+(fadetrans*(maxlightlevel-minlightlevel))/100);
else SetAmbientTint(0,0, 255, (fadetrans*tint)/100, maxlightlevel-(fadetrans*(maxlightlevel-minlightlevel))/100);


Let me know if it works. Would't surprise me if there are a couple of parenthesis missing.

Edit: I forgot the saturation values in the SetAmbientTint, fixed that. AND, changed the tint value from applying to the blue color to the saturation value itself - still may need some experimenting to make it look good, and probably another color that pure blue.

xenogia

#12
I got an error message after putting in the code and putting those two custom properties in the room
compiles okay..
but when trying to run it I get the following error msg:

Unable to create local script: Runtime error: unresolved import "maxlightlevel"

EDIT: My bad, was something I forgot to remove previously

GarageGothic

Which line gives you the error? Have you made sure that "MaxAmbientLight" is in fact the name of the custom property you created?

Edit: Ah, ok, does it work then?

xenogia


Trent R

Woo-hoo! Nice thread. I've thought about this problem before(for my own QFG-like game), but haven't decided on how to do it.  Very cool Garage!

~Trent
To give back to the AGS community, I can get you free, full versions of commercial software. Recently, Paint Shop Pro X, and eXPert PDF Pro 6. Please PM me for details.


Current Project: The Wanderer
On Hold: Hero of the Rune

GarageGothic

#16
Glad to hear it, Xenogia! If someone could take a look at my code and try to find what causes the "cannot draw surface unto itself" error at higher loop counts, I'd be very grateful.

Trent, I hope you'll find the code useful, at least for inspiration. When I have the time I may iron out the bugs and turn it into a module.

Edit: I'm an idiot. It turned out there was nothing wrong with the script but that my background was actually animating (albeit very slowly), so the currentframe changed midway through the function. You should remember to "SetBackgroundFrame(0);" (or whatever you want it to be) in the player_enters_room script whenever you use multiple background frames but don't want them to animate. However, I've now included a failsafe so the script at least won't crash the game in case you forgot.

SMF spam blocked by CleanTalk