Change fonts at runtime advanced

Started by , Fri 23/09/2016 15:43:40

Previous topic - Next topic

m0ds

Hi guys, so one way to change speech font and normal font at runtime is Game.SetSpeechFont or Game.SetNormalFont(eFontNormalNew) what not...

This works fine for "general stuff".

But anything in a GUI using eFontNormal for example, will not change. Therefore you have to call it manually somewhere.

For a game with 50 GUI's each with 20 buttons on them, this means a line of code to call each one, bit of a headache...

Label1.Font = eFontNormalNew;
Button1.Font = eFontNormalNew;
Label2.Font = eFontNormalNew;
Button2.Font = eFontNormalNew;
...
Label312.Font = eFontNormalNew;
Button8billion... ;)

Is there any workaround to get AGS to scan all GUI's and button labels (ie look for any remaining uses of eFontNormal and replace them) and make that change? This example is related to Russian translations, or any that require a different font. I'm wondering why eFontNormal in GUI's doesn't get updated when you call a game wide switch to a new font at runtime, but that's a whole other issue. For now I'm interested to know if anyone has a trick, tip, or whether I'm going to have to write and call each label. It's okay for some games that use 5 gui's and a few buttons, but this one has 50 and 8 million labels... so it's a whole other kettle of fish! Thank you!

Crimson Wizard

#1
The general advise for all times: if you want to do same operation to all items of same type, search for the method to iterate over list of those items in a loop.

You can iterate over gui controls array:
Code: ags

function ReplaceFontOnGUI(GUI *g, int old_font, int new_font)
{
  int i = 0;
  while (i < g.ControlCount)
  {
    Button *b = g.Controls[i].AsButton;
    if (b != null)
    {
      if (b.Font == old_font)
        b.Font = new_font;
    }
    Label *l = g.Controls[i].AsLabel;
    if (l != null)
    {
      if (l.Font == old_font)
        l.Font = new_font;
    }
    i++;
  }
}


You can also iterate over array of all guis:
Code: ags

function ReplaceFontOnAllGUIs(int old_font, int new_font)
{
  int i = 0;
  while (i < Game.GUICount)
  {
    ReplaceFontOnGUI(gui[i], old_font, new_font);
    i++;
  }
}


NOTE: the script above is AGS 3.2.1 compatible, if you are using 3.4.0 you could make those loops slightly more beautiful with "for" and "continue" commands.

m0ds

Interesting method, looks solid...thanks CW. I've never really got to grips with the while command in AGS. I will be giving it a try (on 3.3.0) asap. Thank you!

m0ds

Hmm, CW can you give me further tips how to get this working please? I place the function in globalscript, how do I call it? Do I need to use "import function" or something? It doesn't seem to want to be called like other functions in the game, but at the same time, I have little idea what I'm doing ;) thanks!

Snarky

Quote from: Mods on Fri 23/09/2016 17:08:48
I've never really got to grips with the while command

:shocked: 8-0 :shocked: 8-0 :shocked: 8-0 :shocked: 8-0

Are you saying that for fifteen years (or however long you've been an AGSer) you've been coding without loops?

m0ds

#5
Haha, pretty much. Pick up inventory item, use inventory item with thing -- for my own stuff, doesn't usually require anything complex! Only in the last 4, other people's code they've passed onto me, has been more complex than that ;) I did some functions stuff back in January... using functions and loops look like good methods, I've forgotten since then though... I thought it'd just be paste CW's function, change the font names and put ReplaceFontOnGui(); somewhere to call it... obviously not tho...

Jack

While will run its bracketed/child block of code as long as the condition is valid (true). It is checked once before the code block and, if run, it will return to the condition to check if it's still true when it's done with the child block.

So this will keep running the while loop as long as the var is smaller than 5:

Code: ags
int i = 0;
while (i < 5) {
  i++;
}


In other words, it will run the child block 5 times in this case, and i will be 5 after the while block is done. The while and the condition will be checked 6 times, where the last time i is no longer smaller than 5 and it will go on to the next command after the child block without running it. If you leave out the i++ from the child block, it will create an "endless loop" since the value of i never changes and remains less than 5 forever.

m0ds

#7
Haha yeah I get that. It's simple to understand, I just don't find myself writing it ever, so it's a bit like riding a bicycle. It's not hard, you just have to have some experience to use it... I'm trying now to understand how to call and run CW's function.

Crimson Wizard

#8
Well, that really depends on where do you change fonts. If you do that in global script, then just put both functions I posted in Global Script (somewhere above where you are supposed to call them).
Then just call
Code: ags

ReplaceFontOnAllGUIs(eFontNormal, eFontNormalNew);

or something like that.

BTW, I did not really test my script out, so there could be typos and such.

m0ds

#9
Thank you. I get a parse error at expr near g

"    Button *b = g.Controls.AsButton();    "

g seems defined in the function so I don't know what the conflict is...

I can feel it wanting to work... :)

I will try and learn a lesson about functions and loops from this, promise! ;)

Crimson Wizard

Ooops! It is ".AsButton", not "AsButton()". Same with label.

m0ds

That got it, thanks a lot! It works nicely! I see much Russian now.

SMF spam blocked by CleanTalk