Unblocking fade in and out name overlay function

Started by Kinoko, Fri 16/09/2005 05:41:23

Previous topic - Next topic

Kinoko

Okay, this may not be important at all but this code took me a long time to get right so I thought I'd post it just in case anyone wanted to do what I did.

Basically, in my RPG, when you walk into a town, I wanted the town name to fade in and then fade out. I also wanted a little flowery border to animate into existance before the word has faded in and then animate again out of existance after the words have faded out. On top of all this, I needed it all to be non-blocking.

I initially used to script given in the manual under the fade topic, but it relied on a Wait command which was obviously blocking. After a few days, I managed to come up with this which, although it may be hideously intindy scripting, works beautifully.

Code: ags

function FadeName (string areaname, int disptime) {
  displaytime = disptime;
  SetGlobalInt(26, 0);
  CentreGUI(36);
  CentreGUI(37);
  gTownname.Y-=50;
  gTownnameborder.Y-=50;
  SetLabelText(36, 1, areaname);
  gTownname.Transparency = 100;
  SetButtonPic(37, 0, 1, 0);
  GUIOn(37);
  GUIOn(36);
  AnimateButton(37, 0, 35, 2, 2, 0);
  SetTimer(8, 30);
}

//in repeatedly_execute_always:
/////////////////// NAME FADE ////////////////////////
if (IsTimerExpired(8)) { //START
  trans = gTownname.Transparency;
  SetTimer(10, 1);
}

if ((IsTimerExpired(10)) || (IsTimerExpired(9))) {
  if ((trans==0) && (GetGlobalInt(26)==0)) { //WORD COMPLETELY VISIBLE
    SetTimer(9, displaytime);
    SetGlobalInt(26, 2);
  }
  else if ((trans==100) && (GetGlobalInt(26)==1)) GUIOff(37); //FINISH - ALL OFF
  else if ((trans==100) && (GetGlobalInt(26)==2)) { //WORD COMPLETELY INVISIBLE
    GUIOff(36);
    SetGlobalInt(26, 1);
    AnimateButton(37, 0, 35, 3, 2, 0);
    SetTimer(8, 30);
  }
  else { //FADING IN OR OUT
    if (GetGlobalInt(26)==0) trans--;
    else if (GetGlobalInt(26)==2) trans++;
    gTownname.Transparency = trans;
    SetTimer(10, 1);
  }
}


So in the room script, I would have, for example: FadeName ("BORONIA", 200);

There's a bit of new and a bit of old script in this because I currently use a hybrid of them both (I'm always trying to use more and more of the new). Obviously, you would need to customise this for your own timing and word position etc. The other advantage to this code is that you can control the speed of the fade.

If this is useful for anyone, well, I'll be pretty happy. It's working wonderfully for me.

If noone thinks this is useful then please delete the topic!

Kweepa

Sounds cool, and the code looks pretty neat.
Except for the indiscriminate use of anonymous global ints. :=
Still waiting for Purity of the Surf II

Kinoko

Well, I'm sure there's a much neater way of doing it but that's how it ended up for me. It's probably a little messy because it was changed bit by bit as I came up with new ideas, not just written from scratch.

simulacra


strazer

Yes, a script module would be nice (but then avoid Timers or GlobalInts please). You could even provide the required GUIs for importing.

But if you at least update the code to AGS v2.7 "strict" and make adjusting the GlobalInt and Timer numbers easier for users (#defines or enums), I can move this to the Tech Archive.

Kinoko

If I knew what a module was, maybe I could... module. But I don't, unfortunately... is it something easy that wouldn't require much more complicated scripting than what I have there? Because that's pretty much as good as it gets with me. I could try to update the code for 2.7 though.

strazer

Instead of putting the code into global or room script, just create a new script module and put the functions and code in there. A script module consists of the main module script and the module header, just like the global script.
Think of script modules as many little global scripts you can add and remove at your leisure without having to copy and paste stuff all around your main global script.

Kinoko


strazer

Menu "Script" -> "Module manager..." -> "New..."
Then press the "Edit script" / "Edit header" button and enter your code.

SSH

Some hints on making this a module:

Modules can have their own repeatedly_execute_always functions, so just make up one in the module with that code in it.

Use meaningful names for variables rather than anonymous globalints. As they are all internal to the module, you don't need to worry about export/import for them

Timers can be replicated by decrementing a global integer in a repeatedly_execute(_always). This means that the normal timers are free for anyone to use elsewhere and you don't need to keep track of them orwarn people in your documentation.

so something like:

Code: ags

enum fade_state_t {eStateFadeAllOff, eStateFadeIn, eStateFadeWait, eStateFadeOut };
fade_state_t fade_state=eStateFadeAllOff;
int fade_anim_timer=-1;
int fade_delay_timer=-1;
int trans;

function FadeName (const string areaname, int disptime) {
  displaytime = disptime;
  fade_state=eStateFadeIn;
  gTownname.Centre();
  gTownnameborder.Centre();
  gTownname.Y-=50;
  gTownnameborder.Y-=50;
  SetLabelText(gTownname.ID, 1, areaname); // ideally a nice GUI object name here
  gTownname.Transparency = 100;
  SetButtonPic(gTownnameborder.ID, 0, 1, 0); // ideally a nice GUI object name here
  gTownnameborder.Visible=1;
  gTownname.Visible=1;
  AnimateButton(gTownnameborder.ID, 0, 35, 2, 2, 0);// ideally a nice GUI object name here
  fade_anim_timer=30;
  trans=100;
}
export FadeName;

repeatedly_execute_always () {
  /////////////////// NAME FADE ////////////////////////
  if ((trans==0) && (fade_state==eStateFadeIn)) { //WORD COMPLETELY VISIBLE
      fade_delay_timer = displaytime;
      fade_state=eStateFadeWait;
  }
  else if ((fade_delay_timer == 0) && (fade_state==eStateFadeWait)) { // Begin fadeout
    fade_state=eStateFadeOut;
  }
  else if ((trans==100) && (fade_state==eStateFadeOut)) { //WORD COMPLETELY INVISIBLE
      gTownname.Visible=0;
      AnimateButton(37, 0, 35, 3, 2, 0);// ideally a nice GUI object name here
      fade_anim_timer = 30;
  }
  else if ((fade_anim_timer==0) && (fade_state==eStateFadeOut)) {
      gTownnameborder.Visible=0;
      fade_state=eStateFadeAllOff;
  } 
  else { //FADING IN OR OUT
      if ((fade_state==eStateFadeIn) && (fade_anim_timer<=0)) trans--;
      else if (fade_state==eStateFadeOut) trans++;
      gTownname.Transparency = trans;
  }

  // Update timers
  if (fade_anim_timer >= 0) fade_anim_timer--;
  if (fade_delay_timer >= 0) fade_delay_timer--;
}


and module header:
Code: ags

import function FadeName(const string areaname, int disptime);



12

strazer


Kinoko

It's a bit late because at first I didn't have the net, then... I forgot, but here's the mod:

http://kinoko.futariba.com/misc/FadeNameMod.scm

Big thanks to SSH and Strazer for the help! It's probably got huge problems so please let me know of anything wrong.

Rui 'Trovatore' Pires

Reach for the moon. Even if you miss, you'll land among the stars.

Kneel. Now.

Never throw chicken at a Leprechaun.

strazer

Quote from: Kinoko on Fri 07/10/2005 13:02:33It's probably got huge problems so please let me know of anything wrong.

If you had enabled permission to edit/view script and header, we could tell for sure. :)
But since it failed compiling, I was able to take a look at the module anyway:

1.) This module requires AGS v2.71. This should be documented.

2.) You use fixed GUI names like "gTownname" and "gTownnameborder".
You should either:
- Make the GUI names parameters of the FadeName function
Code: ags

function FadeName (const string areaname, int disptime, GUI *thenamegui, GUI *thebordergui) {

- Add static functions for the user to set them beforehand
Code: ags

// module header
struct FadeName {
  import static function Fade (const string areaname, int disptime);
  import static function SetNameGUI(GUI *thenamegui);
  import static function SetBorderGUI(GUI *thebordergui);
};

or something
- Document what the user has to set up first
- Include exported GUI files the user can import

3.) You use view 35 to animate the button. What if the user doesn't have it?
Make it a parameter of the function or use the view's script name (FADENAME for example) and instruct the user to create it first.

4.) In case the user has to set up the GUIs himself, don't count on the button being control no. 0. Better give the GUI controls names.

5.) You should use new-style scripting exclusively, for example:
SetLabelText -> TheLabelName.SetText
SetButtonPic -> TheButtonName.Graphic
AnimateButton -> TheButtonName.Animate

6.) The module doesn't contain a version string for dependent modules to check for:
Code: ags

// module header

#define FadeName_VERSION 100


7.) As I said, you don't need the
  export FadeName;
line as functions don't need to be exported.

8.) Nitpicky, but why is the module named "FadeNameMod"? We all know it's a module, why not just call it "FadeName"?

Kinoko

(sorry for the late reply)

Okay, I decided to get back to this issue and clean the mod up, which I've done somewhat. Thanks for all your help, strazer!

I still have very little idea of what I'm doing with mods but here's v1.1: http://kinoko.futariba.com/misc/FadeName.scm

The biggest problem is that I still don't know exactly what I should physically change all the "gTownName" instances to. I don't have any experience with structs or anything so I don't know what code is right. I've left the mod editable this time so you can easily see the script.

I haven't written a readme yet but I changed the view number to FNVIEW and the object number to FNBORDER so it will be documented to create a view/object with those names. I also added the int animdelay so the user can change the animation delay time themselves. The view loop will just be 0, so I'll document that too.

strazer

Wow, did you actually manage to compile that? :o ;)
Next time, try saving your game first before exporting the module. :P

Now, looking back at my comments above, I think they don't really apply in this case.
I didn't really look at what your function actually does. Since it's such specialized code, with the animation and such, I think making a full-fledged module out of it isn't very practical. The Credits module is probably enough for most people.

Quote from: Kinoko on Sat 12/11/2005 06:55:04The biggest problem is that I still don't know exactly what I should physically change all the "gTownName" instances to.

I think it isn't necessary to make the GUIs parameters after all...

Anyway, for the rewritten module below, you need to set up:

- A GUI named "FADENAME" (gFadename) with a single label on it
- A GUI named "FADENAMEBORDER" (gFadenameborder) with a single button on it
- A view named "FADENAMEVIEW" containing the animation for the fadein in loop 0 and the animation for the fadeout in loop 1

Import the module, then you can do
Code: ags

  // script for interaction: Player enters room (after fadein)
  FadeName("Village");


Download FadeName v1.11 (Requires AGS v2.71)

(Btw, I've re-structured the code in repeatedly_execute_always to make it easier to read, but may have changed the behaviour in the process. Be sure to compare it to your version.)

Kinoko


SMF spam blocked by CleanTalk