[SOLVED] Directional Arrows When Over Regions

Started by imagazzell, Sun 24/10/2021 06:59:20

Previous topic - Next topic

imagazzell

Hey guys,

I'm trying to have the cursor switch to one of four directional arrows when over different regions that lead to other rooms.

- I have a sprite for each arrow: left (sprite slot 46), right (47), up (48), and down (49).

- I made an "Arrow" cursor mode out of the Usermode1 cursor, with the default image set to 46 (the "left" arrow sprite).

- I have a global variable set up (in the Global Variables pane) named "region_direction", string type, initial value: left.

In my room script, I have the following function to set the "region_direction" accordingly depending on the specific region. In this instance, for region 1, I want to use the "up" arrow.
Code: ags

function room_Load()
{
  Region* r = Region.GetAtScreenXY(mouse.x, mouse.y);
  if (r == region[1]) {
    region_direction = "up";
  }
}


Finally, in the verb coin script (where all of the other cursor related functions are), in the "repeatedly_execute" function, I have the following code to switch the cursor back and forth from the arrow mode to the standard walkto cursor, with the intention of the arrow graphic changing to the appropriate sprite depending on the "region_direction" variable (in this case, sprite 48 for "up"):
Code: ags

Region* r = Region.GetAtScreenXY(mouse.x, mouse.y);
if (r != region[0]) {
  if (region_direction == "up") {
    mouse.ChangeModeGraphic(eModeArrow, 48);
  }
  mouse.Mode = eModeArrow;
}
else {
  mouse.Mode = eModeWalkto;
}


With this, the cursor switches back and forth as expected, but the arrow sprite does not change, just stays on the initial "left" sprite.


I've been trying different variations of this all day. It seemed to make sense in my head but I just can't get it to work. I've read several older threads of similar scenarios, but nothing's seemed to help me so far. I don't know if I'm just missing one important point here, like how script types work with each other, or if the solution is more complex than I initially thought.

Can someone please tell me what I'm doing wrong, or how else to achieve what I'm trying to?

Thank you!
Music Composing Services: https://youtu.be/BbT3kfhgA4E

Crimson Wizard

#1
Your first code snippet (one with room_Load) does not make much sense, you only test a region under the mouse cursor once at the room load, what if the mouse is not over the region at that time? Then the variable is never set.

If you want to configure additional properties for the regions, then you should not rely on where the mouse is at the room start. Instead make an array of region directions and set it up unconditionally for all regions.
Code: ags

String region_direction[AGS_MAX_REGIONS];

function room_Load()
{
  region_direction[1] = "up"; // for region 1
  region_direction[2] = "left"; // for region 2
  // and so on
}


Then when you found a region under the mouse, use that region's ID number to get its direction:
Code: ags

Region* r = Region.GetAtScreenXY(mouse.x, mouse.y);
if (r != region[0]) {
  String dir = region_direction[r.ID];
  if (dir == "up") ...
  else if (dir == "left") ...
  // and so on
}



Aside from that, you may perhaps simplify this by storing directions using existing enum called "Direction", which has values like "eDirectionDown", "eDirectionLeft" and so on:
Code: ags

Direction region_direction[AGS_MAX_REGIONS];

function room_Load()
{
  region_direction[1] = eDirectionUp; // for region 1
  region_direction[2] = eDirectionLeft; // for region 2
  // and so on
}


But that is a matter of preference.

imagazzell

Thanks for your assistance, CW. Arrays have been beyond my current skill level.

I'm getting an error on the first line:
Code: ags
String region_direction[AGS_MAX_REGIONS];

Error: Attributes of identifier do not match prototype

Any ideas? Something to do with my global variable, perhaps? (It is set as String type with "left" as the initial value.)

Quote from: Crimson Wizard on Sun 24/10/2021 07:22:15
Your first code snippet (one with room_Load) does not make much sense, you only test a region under the mouse cursor once at the room load, what if the mouse is not over the region at that time? Then the variable is never set.
Yeah, that didn't seem right. Initially, I had it under "repeatedly_execute", but through my trial and error it eventually ended up under "room_Load" and just stayed there until I came to ask for help.
Music Composing Services: https://youtu.be/BbT3kfhgA4E

Crimson Wizard

#3
Quote from: imagazzell on Sun 24/10/2021 21:57:27
Arrays have been beyond my current skill level.

Arrays may be thought as multiple variables sticked together. You access them by the name and index (like myarray[5]) instead of just name. Index is 0-based, but you seem to already had experience with that as you have "region[0]" in your code.

Quote from: imagazzell on Sun 24/10/2021 21:57:27
I'm getting an error on the first line:
Code: ags
String region_direction[AGS_MAX_REGIONS];

Error: Attributes of identifier do not match prototype

Any ideas? Something to do with my global variable, perhaps? (It is set as String type with "left" as the initial value.)

Ah, I forgot to mention that indeed you need to delete your global variable in this case, as in my example you are creating one yourself by hand in script. Unfortunately, the "Global Variables" panel in the editor does not allow to create arrays (idk why).

But depending on which room or rooms you are planning to use this variable (or array) might be declared elsewhere, like in GlobalScript, to let use it everywhere. I don't know your game's specifics. If you want to use same method in multiple rooms, then it's best to declare this in global script, and have the arrow-changing code in global script too (or do you have already? I might have missed this).

There is an article in the manual that explains how to share variables between scripts: https://adventuregamestudio.github.io/ags-manual/ImportingFunctionsAndVariables.html
When you use "Global Variables" panel editor does the same for you, "secretly".

To achieve this, you need to have this in the GlobalScript.asc:
Code: ags

String region_direction[AGS_MAX_REGIONS];
export region_direction;

and this in the GlobalScript.ash:
Code: ags

import String region_direction[AGS_MAX_REGIONS];

imagazzell

Thanks again, CW.

After deleting the global variable, I read the full manual article and thought I was following the instructions correctly, but apparently not, as I'm getting this pop-up error when the game tries to load:
Loading game failed with error: Script link failed. Runtime error: unresolved import 'region_direction'.

So in the GlobalScript header, I declared:
Code: ags
String region_direction[AGS_MAX_REGIONS];


In the room script, after the "room_Load" function that sets the region direction, I exported the variable:
Code: ags
export region_direction;


And in my verb coin script (where the other cursor functions are), I imported it:
Code: ags
import String region_direction[AGS_MAX_REGIONS];


Anything obvious jump out to you as wrong there? Maybe the order in which scripts are read?


Quote from: Crimson Wizard on Sun 24/10/2021 22:09:27
... but you seem to already had experience with that as you have "region[0]" in your code.
To be fair, that part of the function was a direct copy-paste from the manual section about region functions, although I understood it on a basic level.
Music Composing Services: https://youtu.be/BbT3kfhgA4E

Crimson Wizard

#5
Quote from: imagazzell on Sun 24/10/2021 22:54:59
So in the GlobalScript header, I declared:
Code: ags
String region_direction[AGS_MAX_REGIONS];


In the room script, after the "room_Load" function that sets the region direction, I exported the variable:
Code: ags
export region_direction;

No, this is wrong, you need to put both of these lines in GlobalScript.asc, as mentioned in the example in my previous post.

You declare variables only inside the script bodies, not headers, and export them from the same script where you declared them at.

On contrary, you declare the import in the script header, this is where every other script would see it. Alternatively you may put import declaration in each script where you are using this variable (I think this is what you did with the verbcoint script).

Also, if you're using this variable in the verb-coin script, then likely you need to declare the variable right there instead of globalscript. Because in AGS you can only use variables in the same script or scripts located below in the list, and globalscript is by default the last in that list.

imagazzell

Eureka! Your last bit of clarification helped me crack it.

In the verb coin script body (not header), I've got the declaration and export:
Code: ags
String region_direction[AGS_MAX_REGIONS];
export region_direction;

(Placement of the export command doesn't appear to need to be at the end of the script after any functions that use the variable...?)

And I put the import command in the global script header so that I don't need to include it in every room script:
Code: ags
import String region_direction[AGS_MAX_REGIONS];


After that, all I needed to do was tell the cursor change function which sprite to use with each directional string text and define the appropriate direction for each region in the "room_Load" function, and voila, works like a charm. I'll cross my fingers that it continues to work in subsequent rooms, but the logic of the scripts implies that it should be fine.

Thanks a bunch, CW! Please let me know if there's any way I may reward you for your time and attention.
Music Composing Services: https://youtu.be/BbT3kfhgA4E

Crimson Wizard

#7
Quote from: imagazzell on Sun 24/10/2021 23:42:52
(Placement of the export command doesn't appear to need to be at the end of the script after any functions that use the variable...?)

Right, export command may be anywhere below the declaration, because export itself is not for this script, it's for other scripts.

In a nutshell, "import" tells your script(s) that this variable exists somewhere else; and when the game is run, it tries to link each "import" with the "export". "Script link failed" error means that there was an import but no matching export found.

SMF spam blocked by CleanTalk