Just started, a few questions, mostly about globals

Started by FortressCaulfield, Sun 12/05/2024 17:49:17

Previous topic - Next topic

FortressCaulfield

Hi, I've been using AGS for maybe a week and had some questions:

1. I was surprised to find if I declare a variable in room script that it doesn't reset upon leaving and re-entering the room. I'm aware I could reset it with a region easily enough, but that's not really my question. How do variables declared this way differ from globals? Do I just need to make peace with using globals for every little counter and boolean? The use in this case is player repeatedly looking at a bookshelf and being shown a different book each time in a specific sequence.

2. I wanted to create a generic function for invalid inputs. Like if the player clicks talk on hotspots that are just bits of scenery, rather than creating a talk function for each of them, I thought I could put a generic_invalid_talk() function in global and then have every hotspot or object call that. Compiles fine, but crashes on use. Did I need to declare the function somewhere, or is this approach just a non-starter? Is there another way to come at this I'm not seeing?

3. Is there a way to make think animation automatically loop like talk animation does? I have done a work around with just making the think loop quite long but feels suboptimal.

4. Is there a way to show specific graphics/sprites on the gui, on top of the background graphic? I remember seeing this a lot in old sierra games and would like to have a shot of the character on either the options menu or inventory window which will change through the game.

5. Is there a way to adjust walk speed for specific directions? My character moves up and down too fast. Maybe bc her L/R loop is 8 frames and her Up/Down is only 6? I'm away the char struct has a x and y movement speed values. How often/where would I need to set that to have it be permanent?

Thanks!

Crimson Wizard

#1
Hello.

Quote from: FortressCaulfield on Sun 12/05/2024 17:49:171. I was surprised to find if I declare a variable in room script that it doesn't reset upon leaving and re-entering the room. I'm aware I could reset it with a region easily enough, but that's not really my question. How do variables declared this way differ from globals?

The global variables are different from room variables in that they may be accessed anywhere, in every room and script (well, almost, but I'll skip nuances for now).
Room variables may be accessed only in the respective room script.


Quote from: FortressCaulfield on Sun 12/05/2024 17:49:17The use in this case is player repeatedly looking at a bookshelf and being shown a different book each time in a specific sequence.

I'm a bit confused by this question, you are saying that you like to have a different reaction each time, then why do you want to have a variable reset? Or do you want this sequence to reset each time upon re-entering a room?

Resetting something is mostly a question of design.

If you like the whole room state to be reset each time, then you can make the room "non-state-saving". In AGS currently this is done by choosing a room number above 300 (301 and on). This will simply erase room from memory each time you leave it.

If you like to reset room state completely but only on certain occasions, then there's ResetRoom function.

Finally, if you like to reset only certain things, like variables or object positions, but not other things, then there's a "Enter Room before Fade-in" event (aka "room load"), where you may write room initialization code.


Quote from: FortressCaulfield on Sun 12/05/2024 17:49:172. I wanted to create a generic function for invalid inputs. Like if the player clicks talk on hotspots that are just bits of scenery, rather than creating a talk function for each of them.

AGS already has such function, it's called "unhandled_event":
https://adventuregamestudio.github.io/ags-manual/Globalfunctions_Event.html#unhandled_event
This function is called automatically any time an action is used on object or hotspot, which does not have a script function attached to corresponding event.

Of course, if you don't like this function for any reason, you may write your own, but then it's a matter of finding the optimal way for calling it. Commonly this is called from on_mouse_click(), after testing an object or hotspot under the cursor using IsInteractionAvailable().
https://adventuregamestudio.github.io/ags-manual/Globalfunctions_General.html#isinteractionavailable
This is a very brief explanation, the actual code may be more complicated than this.

Quote from: FortressCaulfield on Sun 12/05/2024 17:49:17I thought I could put a generic_invalid_talk() function in global and then have every hotspot or object call that. Compiles fine, but crashes on use. Did I need to declare the function somewhere, or is this approach just a non-starter? Is there another way to come at this I'm not seeing?

I would not recommend calling this function from every object, because that is tedious and bug-prone; and instead suggest to use one of the two methods described above.

But to answer your question directly, calling a global function from the room script should normally work, if done correctly.
In order to tell what is wrong, I would need to know how and where did you declare this function, how and where did you call it, and what was the error message when it crashed.


Quote from: FortressCaulfield on Sun 12/05/2024 17:49:174. Is there a way to show specific graphics/sprites on the gui, on top of the background graphic? I remember seeing this a lot in old sierra games and would like to have a shot of the character on either the options menu or inventory window which will change through the game.

You may do this using non-clickable buttons (a button which has Clickable property set to false) with a NormalGraphic set and empty Text.

Quote from: FortressCaulfield on Sun 12/05/2024 17:49:175. Is there a way to adjust walk speed for specific directions? My character moves up and down too fast. Maybe bc her L/R loop is 8 frames and her Up/Down is only 6? I'm away the char struct has a x and y movement speed values.

In Character properties disable "UniformMovementSpeed" and set different values to "MovementSpeedX" and "MovementSpeedY".

In AGS Editor there's a quirk that some properties are hidden if another property render them useless. TBH this is not the first time such behavior gives user a wrong impression that certain option does not exist. Maybe this should be changed to displaying all properties always.

Khris

Regarding question #1, you can use the "enters screen before fadein" event / room_Load function for this; no need for a region.

Also, if you change a room's number to 300 or above, it doesn't save its state when you leave it.

FortressCaulfield

Thanks for the reply.

For the first item, it was more a stylistic question as to whether it's normal to have a whole pile of bools and ints in global for trackers and stuff. My char has to learn 3 things before she can ask a char about the plot. Since those things are all in different room the only way to track them was global bools. I couldn't find any other way to do it.

Thanks, I'll try to track down that function.

>You may do this using non-clickable buttons (a button which has Clickable property set to false) with a NormalGraphic set and empty Text.

I had thought of that, but couldn't figure out how to check score to potentially alter the graphic each time the gui was called.

Thanks for the other answers, very helpful!

Snarky

Quote from: FortressCaulfield on Mon 13/05/2024 01:17:32For the first item, it was more a stylistic question as to whether it's normal to have a whole pile of bools and ints in global for trackers and stuff. My char has to learn 3 things before she can ask a char about the plot. Since those things are all in different room the only way to track them was global bools. I couldn't find any other way to do it.

Yes, in that case you do need global variables. But note that there are two kinds of global variables in AGS: you have the ones in the global variable pane, but you can also make a variable global by exporting it from a script (the global script or a module script, not a room script) and putting an import statement in the script header.

These are essentially equivalent (under the hood, the global variables pane is converted into a script with export/import statements), but using script variables gives you a bit more flexibility, since you can group related variables in arrays and structs. So, for example, some devs use a "GameState" script/struct where all the variables that keep track of game progress are stored.

Quote from: FortressCaulfield on Mon 13/05/2024 01:17:32I had thought of that, but couldn't figure out how to check score to potentially alter the graphic each time the gui was called.

Normally the way to do this is to create a function that updates the information and shows the GUI, and always call that function whenever you want it displayed. Or if you need to update the GUI while it is displaying, not just when you bring it up, you can have just an update function, and call that in repeatedly_execute(), for example.

Khris

Quote from: FortressCaulfield on Mon 13/05/2024 01:17:32For the first item, it was more a stylistic question as to whether it's normal to have a whole pile of bools and ints in global for trackers and stuff.

As opposed to what though? Are you talking about organizing them like Snarky mentioned?
If so, there is another way you could use (although I personally wouldn't): characters and other entities can have custom properties of various types. So for organizational purposes you could create some of these and use something like
Code: ags
  player.SetProperty("tasks_achieved", player.GetProperty("tasks_achieved") + 1);

This has no advantage though, and is a lot less smooth than
Code: ags
  tasks_achieved++;

heltenjon

#6
Quote from: FortressCaulfield on Mon 13/05/2024 01:17:32For the first item, it was more a stylistic question as to whether it's normal to have a whole pile of bools and ints in global for trackers and stuff. My char has to learn 3 things before she can ask a char about the plot. Since those things are all in different room the only way to track them was global bools. I couldn't find any other way to do it.
There are other ways to do it. The other responders here are very experienced coders and their advice are aiming at good coding; advice that will work every time.

However, just looking at what you write about your game, you could solve this specific case simply by adding a point to the score (which is built in and works right away without declaring the variable): https://adventuregamestudio.github.io/ags-manual/Globalfunctions_General.html#givescore If you aren't using score for something else, you can simply check if the score is 3 (or more, if you want to use this further) before she can talk to the NPC.

Another way will be to give your character inventory items (gems, diploma of insult sword fighting, a medal or whatever) when they achieve the task you have set, and use an if command to check whether the player have the required items before allowing progress. Note that this is essentially the same as using bools - the player either has the item in her inventory or not.

These ways will also work, but are prone to errors, especially if you make a longer game: Can the player get 3 points by repeating an action? Or by doing another task than the one you intended? What happens if the score reaches 4? Is the player going to keep the useless items in her inventory, cluttering it up? Do you want to code descriptions and messages if the player tries to use them later on? Is the conversation with the NPC a once-in-the-game event, or do you need to keep it open for the player to replay the dialog? What you gain from not having to declare the variables may easily be lost to messing up something like this.

Another obvious reason to follow the experienced coders suggestions, will be that if you develop a systematic approach, it will be easier for you to go back and understand your old code after some time has passed, which may be needed for updates or bug fixes.

eri0o

I think at first simple global variables are the way to go, just figure some naming scheme that works for you and a bunch of booleans will probably work fine.

I have made-up a small objectives system too

https://github.com/ericoporto/i_rented_a_boat/blob/main/I_rented_a_boat/Objectives.ash

https://github.com/ericoporto/i_rented_a_boat/blob/main/I_rented_a_boat/Objectives.asc

And I guess there are several other ways to go - as heltenjon mentions, depending on what sort of progress you are tracking the inventory items/score may work too.

Some games I saw use multiple enum types to track different things that can progress at the same time - and some people have come up with complex state machines to track the game story although I don't know if those actually got used.

SMF spam blocked by CleanTalk