Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: Brian925 on Thu 05/01/2023 09:38:38

Title: Custom Inventory-hover over inventory items to reveal an image
Post by: Brian925 on Thu 05/01/2023 09:38:38
Hello,
I have a custom inventory GUI and I'm trying to figure out if there is a way to hover over an inventory item and have it reveal an image that explains the purpose of the item. It's difficult for me to navigate the inventory item behaviors in the GlobalScript. I assume I have to repeatedly execute a call out to whether the x and y are on the inventory item, but if the inventory changes position, the x and y will change. Is there a way to directly say "if this inventory item is hovered over with the cursor in interact mode, an image (stored in a view, 3 possible loops that each hold a still image) will pop up"? As a heads up,  my inventory GUI is not in it's own room, it is called out from the top bar and hovers over any room the character is currently in.

Buttons have the option to set another image for hovering, but inventory items don't, so curious.

Thanks
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Snarky on Thu 05/01/2023 10:45:15
InventoryItem.GetAtScreenXY() (https://adventuregamestudio.github.io/ags-manual/InventoryItem.html#inventoryitemgetatscreenxy)
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Khris on Thu 05/01/2023 13:22:30
Here's how to detect the two relevant events ("cursor moves on top of item X", "cursor leaves item X"):

// add this above the repeatedly_execute_always function, if it exists
InventoryItem* prevItem;
function handle_inv_images() {
  InventoryItem* currentItem = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
  if (currentItem != prevItem) {
    if (prevItem != null) {
      // mouse was moved away from prevItem
      // cleanup here, possibly only if currentItem == null
    }
    if (currentItem != null) {
      // mouse was moved over currentItem
      // display info GUI, etc.
    }
  }
  prevItem = currentItem;
}

// this function might already exist, otherwise simply add it
function repeatedly_execute_always() {
  handle_inv_images();
}
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Brian925 on Thu 05/01/2023 20:02:01
Thanks, Snarky, Khris, as always your help is appreciated.

Khris, tried your code and it did the job well with a single inventory item. Within the code you posted, is it possible to set that up for unique inventory items, i.e, iTickets shows GUI1, iGlove shows GUI 2, etc? The inventory items are dynamic, so they are not always in the same XY position, they move when inventory comes and goes. My first instinct is to do some sort of if/than with an Active Inventory Command, but i'm not sure how to call it out
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Khris on Thu 05/01/2023 20:22:48
You shouldn't have to use multiple GUIs for this. Say you have a single GUI with a button (btnImage) and a label (lblDescription).

You can now do this:
  btnImage.NormalGraphic = image[currentItem.ID];
  lblDescription.Text = text[currentItem.ID];

This requires two arrays populated by you in game_start, like:
int image[20];
String text[20];

function game_start() {
  image[iKeycard.ID] = 123; // keycard sprite
  text[iKeycard.ID] = "It's the keycard you found in the dining room.";
  // etc.
}

You can also use custom properties for this; add two properties that apply to inventory items only, an integer ("image_slot") and a text one ("description"). Then just enter the info in there for each item. Finally, use these lines instead:

  btnImage.NormalGraphic = currentItem.GetProperty("image_slot");
  lblDescription.Text = currentItem.GetTextProperty("description");
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Brian925 on Fri 06/01/2023 07:46:12
btnImage.NormalGraphic = image[currentItem.ID];
Is the button the only thing I need to customize in this part of the code? I wasn't sure if other things needed replacement or if they were calling out to other parts of the code. Can you explain what the right hand side of this is doing? I know it's saying that my button should show up depending on what the current item is, but I don't know where it's getting the information from.

Is 'images' in line 5 supposed to be 'image'?
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Khris on Fri 06/01/2023 09:11:30
Yeah, fixed.

The idea is to store a sprite slot (integer) for each item. You can do this via custom properties, or via an array. If you use an array, you can use the inv item's ID as array index.

The array code doesn't need anything else, the right side is just a single element of the image array, i.e. the sprite slot.

int image[20]; creates 20 integers, image[0] to image[19].
If the keycard has an ID of 3, line 5 becomes image[3] = 123;
Later, when the player is hovering over the keycard and thus currentItem == iKeycard, this number is now read back and assigned as NormalGraphic to the button.
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Brian925 on Fri 06/01/2023 22:07:39
Thank you for being so thorough.

There is something about this code that isn't clicking with me and I've been fighting with it for a couple days.
Right now I have this:
int image[20];at the top of my global script, not embedded in a function.

then I have this:
{
image[6] = 123; // keycard sprite
}
in my game start function

Finally I have this:
  bWindowTickets.NormalGraphic = image[34]as unembeded in the global script.

I'm realizing that the original code was using a text string as a return for the mouse over, but I took it out because my inventory item hover would create an IMAGE, not text. What I thought I was doing here was mousing over iTickets (which I changed to image 6) and returning bWindowTickets, which is a button in a GUI.

Right now it is currerntly returning Parse Error, unexpected bWindowTickets.

bWindowTickets is a button in a GUI, named properly in the design properties. That's where I'm at.

Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Khris on Fri 06/01/2023 23:09:20
My original code assumed that hovering an item would
a) display a sprite on a GUI button
and
b) display text via a GUI label

a) requires storing a sprite slot for each inv item
b) requires storing a string for each inv item

Hence two arrays, an int one for the sprite slots, and a string one for the texts.

There's three issues with
bWindowTickets.NormalGraphic = image[34]1. no semi-colon at the end of the line
2. a hard-coded 34, which makes no sense, since the code/line is supposed to work for each item dynamically
3. unembedded, which will not work at all; assignments can only happen inside functions

The statement should go in line 12 of my original reply, and it should use currentItem
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Brian925 on Sun 08/01/2023 08:48:04
Thanks. After some research I was kind of able to mimic what you did with the int and String arrays in a blank game.

I'm curious though, (and I've attached an image) how I could apply this to inventory images that return an image value that is always in the same spot even though the inventory positions will change once they are used?

Since the inventory is already stored, do I need to create an array for that, or are the arrays specifically for the return values?

In theory, (forgive me, still learning) could I do something like this?

int image[20];
at the top of the global script to create the array for the window images

function game_start() {
  image[iTickets.ID] = bWindowTickets; // keycard sprite
  image[iBlender.ID] = bWindowBlender;
  image[iGlove.ID] = bWindowGlove;
// trying to connect array GUI buttons to their inventory counterparts
}
to set the descriptions

and then populate that information into this?:


InventoryItem* prevItem;
function handle_inv_images() {
  InventoryItem* currentItem = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
  if (currentItem != prevItem) {
    if (prevItem != null) {
      // Mouse OFF the current item
      // cleanup here, possibly only if currentItem == null
    bDefaultWindow.Visible=true;
   
    }
    if (currentItem != null) {
      // mouse OVER currernt item
      // display info GUI, etc.
      bDefaultWindow.Visible=false;
//populate the windows here?
    }
  }
  prevItem = currentItem;
}

I appreciate the patience, trying to study up on my own as much as possible
(https://cdn-useast1.kapwing.com/video_image-OosaGTMzbI.jpeg)

Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Khris on Sun 08/01/2023 10:25:08
It sounds like you want a button for each item. This is possible but not necessary, all you need is the sprite slot for each item, then put the associated image on a single, static button.

Let's say you've created the description image for iTickets and imported it into AGS. It ends up being sprite #73.
To show the correct image when the player is hovering over iTickets, you want to display sprite 73.
The easiest way to display an image in a GUI is to add a button to the GUI, make it "dead" (i.e. not react to clicks / hovering) and set the sprite as the button's .NormalGraphic.

Let's assume the button is called "btnItemDesc".
What we now want is code that essentially does btnItemDesc.NormalGraphic = 73; if the currentItem is iTickets.
That code is also supposed to use a different image / sprite slot number, when currentItem is iBlender, and so on.

The long way to do this is:
  if (currentItem == iTickets) btnItemDesc.NormalGraphic = 73;
  else if (currentItem == iBlender) btnItemDesc.NormalGraphic = 74;
  // ... lots more of the same duplicate mess here

This is incredibly ineffective obviously, given that we can use a single line instead. This requires to somehow get from currentItem == iTickets to 73, but also from currentItem == iBlender to 74, same for the rest of the items. The ideal system is always one that requires as few changes to existing code as possible when you add or change something elsewhere, ideally zero changes.

There are multiple ways to do this. Using a table where AGS can look up the number is one way, this is implemented using an array of integers.

Another way is to use specific numbers for the sprites and basic addition (this is a new solution I somehow didn't mention yet). After importing a sprite, you can change its slot number by right-clicking it. You can now pick any unused slot. Assuming iTickets is the first inv item and thus its ID is 1, you can change the slot number of the description sprite to for instance 101. Or 501. Doesn't really matter, as long as the difference between an item's ID and the associated sprite slot is always the same. (I'll use 100 for the example code below)

Now in the code we can do this:
    if (prevItem != null) {
      // Mouse OFF the PREVIOUS item
      // cleanup here, possibly only if currentItem == null
      btnItemDesc.Visible = false; // we actually want to hide the button here
    }
    if (currentItem != null) {
      // mouse OVER CURRENT item
      // display info GUI, etc.
      btnItemDesc.NormalGraphic = currentItem.ID + 100; // we no longer need an array
      btnItemDesc.Visible = true; // show button
    }

(To clarify the meaning of "current" and "previous" item, this is in the context of a single frame, i.e. 1/40th of a second by default; "currentItem" is the item under the mouse in the current frame, "previousItem" is the item under the mouse 1/40 seconds ago)
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Snarky on Sun 08/01/2023 10:30:19
(Got sniped by Khris, but posting anyway in case having it put a different way helps you grasp it more easily.)

Why do you think you need multiple separate buttons? If you're only displaying one image/button at any one time, you should just have one button, and change its graphic to the image you want to display whenever that changes. And that's pretty much what the original code by Khris does.

Analogies can sometimes be more confusing than helpful, but to me your question sounds like, having understood how to link a TV program to a particular TV channel, you now want to figure out how to link each TV channel to a separate TV, because you think that every time you want to watch a particular show you will need to disconnect the current TV, then look up which TV is tuned to the station you want, and plug that one in. And maybe that would be possible, but actually the right way is to just look up what channel the program you want to watch is on, and switch your one TV to that station.

I don't mean to imply that your question is stupid in any way. Just that I think you've got the mental model of what you need to do a bit wrong.
Title: Re: Custom Inventory-hover over inventory items to reveal an image
Post by: Brian925 on Sun 08/01/2023 19:19:17
Thanks guys,

Snarky, I originally thought the most effective way to return the images was in a GUI button from Khris' original explanation that returned a string. I see now that it adds steps where it doesn't belong for returning images instead of text.

I agree about the wrong mental model. As a self taught coder, I have a lot of blind spots. In the past, I could survive with a bunch of if/than statements, but this time around, I'm trying to really understand putting arrays together and consolidating my code. When I'm given example code, I'm not always sure what I should replace with my content, which parts are returning previous code and which parts are calling premade functions I'm not aware of. Just need more hours.

Khris, that one worked perfect. Kind of a cool concept to label the sprite number at a recognizable interval to save some coding time. Thanks so much for both of your help.