Forum rules - please read before posting.

Regarding a notebook effect

Hello community,
Hope you are all doing well.
I would like to share with you what we have and see what we can do to achieve a certain effect.
First: in our game, one inventory is a notebook, with text. Each small sentence is a clue (like "a key" or "a missing photo".

Our inventory is Unity UI based, with buttons and inside the button, the text (which is a placeholder since the inventory "items" or "clues" are AC based).

1) When combining clues together they both have to be struckthrough "and" remain strikenthrough if we open the notebook again. How can I "call" that AC text (the main inventory name of each element) and add the strikethrough using TMPro, for example? It's a script but I want to call the string from AC since we are using many languages and don't know how to link the slot text with that effect.

2) Our interface is drag and drop but in here we want to use a "click-check" interface for that particular menu (when I click on the clue, I have it selected and on the second click on any other clue, run an action list, or else, deselect). Is there a way to achieve that? The idea would be clicking on any text, and remain highlighted for example, and act as a "selected" item. Then the next one would be either correct, or wrong and remove the highlight.

Hope it's clear and not so hard...

Unity 2020.3.27f1 | AC v1.74.5

Thank you :smile:

Comments

  • 1) A strikethrough in TMPro can be added by surrounding text with an tag.

    To use this on an inventory item's label, you'd have to create a duplicate TextMeshProUGUI and use it as a hidden "dummy" label that's linked to the InventoryBox element, and then have your actual label (that's visible) use that for its value, i.e.:

    if (shouldBeStruckThrough)
    {
        GetComponent <TextMeshProUGUI>().text = "<s>" + dummyText.text + "</s>";
    }
    else
    {
        GetComponent <TextMeshProUGUI>().text = dummyText.text;
    }
    

    To work out whether an item can be struck through or not, and have that information be stored upon closing the menu or saving a game, you can probably rely on Inventory properties.

    Inventory properties are typically variables that you can attach to each instance of an inventory item, but a little-known feature of AC is that they can also be modified - at runtime - for individual item instances. These modifications are stored in save-game data.

    For example, this code will set a bool property ("IsUsed") of an inventory item ("Clue01") held by the Player to True:

    KickStarter.runtimeInventory.PlayerInvCollection.GetFirstInstance ("Clue01").GetProperty ("IsUsed").BooleanValue = true;
    

    For each dummy/visible TMPro pairing, you can get its associated item instance by referencing its Canvas, the "dummy" TextMeshProUGUI object linked to the InventoryBox element, and the slot number it represents:

    MenuInventoryBox inventoryBox = (MenuInventoryBox) KickStarter.playerMenus.GetMenuWithCanvas (myCanvas).GetElementWithGameObject (dummyGameObject);
    InvInstance slotInstance = inventoryBox.GetItem (itemSlot);
    

    And then, reading that item's property in the same way:

    if (slotInstance.GetProperty ("IsUsed").BooleanValue)
    {
        GetComponent <TextMeshProUGUI>().text = "<s>" + dummyText.text + "</s>";
    }
    else
    {
        GetComponent <TextMeshProUGUI>().text = dummyText.text;
    }
    

    Our interface is drag and drop but in here we want to use a "click-check" interface for that particular menu

    If you want to disable drag-and-drop, you can do so with:

    AC.KickStarter.settingsManager.inventoryDragDrop
    

    Any Manager field can be modified through script - you can get an API reference by right-clicking the field's label. Just be aware that changes made to assets survive exiting Play mode - so you'll need to set them to default values manually through script when the game begins as well.

  • Hello,
    Thank you very much for the feedback.

    1) The inventory not Drag/Drop now works flawlessly. Just a little question here: how can I disable combining them again? Just the combination, not the inspection.

    2) Regarding the strikethrough we came up with a different idea. We won't rely on that natively from TMPro, rather, on a "scratch" (which is an object which should appear on top of the inventory button or slot). Each button will have a scratch just like Discworl Noir.
    You previously said we could rely on the inventory properties but I don't understand how I can use it to show that particular object visible if turned on or flagged. The inventory property is a bool called "CluesFlagged" which means, it's been used. When I combine two items, they both should be flagged. On the AL, I go to Inventory, then Property to variable and that's it. Lost :(
    The idea would be to flag that particular clue forever and enable a certain object on top.

    Thank you very much for the feedback. The game is coming along better and better thanks to all this.

  • how can I disable combining them again? Just the combination, not the inspection.

    On a per-item basis? You can use the Inventory: Change interaction to disable Combine interactions.

    I go to Inventory, then Property to variable and that's it.

    As multiple instances of a given item can exist, setting Inventory Property values at runtime is handled through scripting - as my example above.

    Though, I would suggest first testing out the "scratch" behaviour by setting the "CluesFlagged" property's default value to True for some Inventory items. This too will rely on scripting - here's a sample code you can attach to each Button linked to the InventoryBox element:

    using UnityEngine;
    using UnityEngine.UI;
    using AC;
    
    public class ScratchImage : MonoBehaviour
    {
    
        public Canvas myCanvas;
        public Image scratchImage;
        public int slotIndex;
        private MenuInventoryBox inventoryBox;
    
        private void Update ()
        {
            if (inventoryBox == null)
            {
                Menu menu = KickStarter.playerMenus.GetMenuWithCanvas (myCanvas);
                if (menu)
                {
                    inventoryBox = (MenuInventoryBox) menu.GetElementWithGameObject (gameObject);
                }
            }
    
            if (inventoryBox)
            {
                InvInstance slotInstance = inventoryBox.GetItem (slotIndex);
                scratchImage.enabled = InvInstance.IsValid (slotInstance) && slotInstance.GetProperty ("CluesFlagged").BooleanValue;
            }
        }
    }
    
  • Hello Chris,
    After fixing some other issues, I came back here with the updates.
    As for the scractch, this is still a go but I can't make the script work as it's giving me an error here: InvInstance slotInstance = inventoryBox.GetItem (slotIndex);

    Cannot implicitly convert type 'int' to 'AC.InvInstance'

    Maybe it's because I've updated to 1.75.2 since my last post.


    Instead of relying on this script (which I would like to make it work to test it out), I started playing with the Unity Buttons. I found that if you press the mouse button quickly (such as after an unheld interaction), the Event System can collide with AC, showing that the button is pressed but there's no item selected. It seems Unity is faster at detecting clicks, hence, the problem.

    Second problem: if you click outside the button, it "unpresses" while you are still holding the item (remember, we are not having a drag and drop for this inventory).

    I tried for hours to look for a solution, such as getting the Slot Index of the inventory, or the button from which the "item" came from, so I can make that slot "uninteractable" or locked at the desired setup. But I couldn't retrieve which button was the last button clicked. The button properties of that particular button (the one from the item I'm holding came from) are the ones I need to retrive so I can edit the text color and other stuff.


    To summarize the first part, the idea would be to: "on enter, change the color of the button (that works flawlessly)". "On click, only IF AC item detected that an item was held, change the color, and remain there until I close the menu or select a second itrm". The scratch can come afterwards as I can't make a simple thing such as this work flawlessly.

    Thank you very much for everything.

  • As for the scractch, this is still a go but I can't make the script work as it's giving me an error here: InvInstance slotInstance = inventoryBox.GetItem (slotIndex);

    Use this instead:

    InvInstance slotInstance = inventoryBox.GetInstance (slotIndex);
    

    For the other issues: can you provide clear steps on how to recreate them starting with AC's default interface?

  • Thanks for the working code. It works but in strange ways. Let me tell you exactly what I did and post some pictures (sorry for the long thread but I'm sure many people will come here eventually looking for the same approach).

    Unity based UI, 4 buttons (prototyping this, but eventually will have 7 or 8).
    Each button has below a child which is the "scratch" just like you told me.
    Each "clue" has a property called "Clues Flagged". By default this should be false as I haven't used them yet. If I set one to True, it will automatically load the Scratch. If I set manually one to true in any script, it will load the scratch. The idea is to do it by InvID rather than creating one method for every single inventory I have.

    The "Slot" int is set to 0,1,2,3 per slot. Slot 1 = 0, Slot 2 = 1, etc. I manually wrote it in the inspector in Unity. I think it was inteded to do so, right?
    The script is attached to each Button and assigned each scratch image to each button.

    Problem 1: I can't make it move to "True" when the combination works. I tried to edit it in the Action List but I can't. The code doesn't "set" the bool to True, hence that's why it doesn't activate. If I create one method for every single inventory item, then I can do it, but imagine creating a method for 60-70 items...


    Going to the second part/problem and explaining it thoroughly: It is somehow similar to the above part but this time it should mark or stay "selected" if I clicked on a button. The way I did it is by using the Unity button color tint properties (highlight, pressed, selected etc.).
    The problem here is that if I click on a button, and then click outside (other than a button), it revertes the color to normal (but AC knows I'm still holding the item).

    So I said: ok, I'm not going to mess around with the Event System, let's go with a circle or a gameobject that marks the object around it (it's still a notebook so it's a valid approach). Then went back to this post

    https://adventurecreator.org/forum/discussion/12140/inventory-box-highlight-after-clicking-on-the-object#latest

    and used this approach, but now that I have a bit more of knowledge, I found that it never "deselects" (the circle stays on forever). Even if the combination doesn't work or I unselected the item, it should revert the circle (disable it). It never, ever disables it.

    I'm super close to achieving these two effects and only using AC scripting rather than messing around with Unity buttons or the Event System, or difficult scripts in which I need to check whether the AC is holding the item or not, etc.

    Not sure if the images will be of any help, but never mind, here they are:
    https://imgur.com/a/tA7jC3g


    What I meant yesterday with the Unity Buttons and the AC is that, if you combine two objects, a dialogue will probably occur. If you are impatient, you will probably start clicking again on the buttons even when the player is speaking, either to make it shut or just to try other combinations. I found that hammering the click on the buttons (when the dialogue is on and then moves to gameplay), it could lead to Unity detecting the click but AC not, so the button will be pressed and AC will not "hold" the item. You could recreate it by using two or three buttons, AC Unity/Prefab inventory type, and an unhandled interaction. Make a combination (any), let it play, and hammer on the buttons. You will notice sometimes the click will enter the Event System but AC will not hold the item. In the pictures of the post I did yesterday I posted one pic in which it's blue but the cursor doesn't hold the clue. Picture two: clue not selected, but button "On".

    If I can help you with anything let me know. I think it's better to stick with AC approaches to avoid bugs like this. Just let AC tell you when you have something and then change buttons or whatever (yesterday and today's work was based on that).
    Thank you very much :)

  • Problem 1: I can't make it move to "True" when the combination works

    Naturally, you'll want to use a script that automates it. The main thing to know is how/when a combination is considered "correct".

    The OnInventoryCombine_Alt event is run whenever two items are combined. If you wanted this to result in both items having their properties set, you can update them here:

    private void OnEnable () { EventManager.OnInventoryCombine_Alt += OnInventoryCombine; }
    private void OnDisable () { EventManager.OnInventoryCombine_Alt -= OnInventoryCombine; }
    
    private void OnInventoryCombine (InvInstance invInstanceA, InvInstance invInstanceB)
    {
        invInstanceA.GetProperty ("Clues Flagged").BooleanValue = true;
        invInstanceB.GetProperty ("Clues Flagged").BooleanValue = true;
    }
    

    I found that it never "deselects" (the circle stays on forever). Even if the combination doesn't work or I unselected the item, it should revert the circle (disable it). It never, ever disables it.

    The script I posted for you in the other thread dealt specifically with showing the "circle" image upon clicking an item - in a general sense. As mentioned, it would need to be expanded upon to similarly disable it at the time you intend.

    If its visibility is instead based on the item's selection, you can either hook into the OnInventorySelect/OnInventoryDeselect events, or brute-force it by simply comparing the associated item with the SelectedInstance variable:

    using UnityEngine;
    using UnityEngine.UI;
    using AC;
    
    public class CircleImage : MonoBehaviour
    {
    
        public Canvas myCanvas;
        public Image circleImage;
        public int slotIndex;
        private MenuInventoryBox inventoryBox;
    
        private void Update ()
        {
            if (inventoryBox == null)
            {
                Menu menu = KickStarter.playerMenus.GetMenuWithCanvas (myCanvas);
                if (menu)
                {
                    inventoryBox = (MenuInventoryBox) menu.GetElementWithGameObject (gameObject);
                }
            }
    
            if (inventoryBox)
            {
                InvInstance slotInstance = inventoryBox.GetItem (slotIndex);
                if (InvInstance.IsValid (slotInstance) && slotInstance == KickStarter.runtimeInventory.SelectedInstance)
                {
                    circleImage.enabled = true;
                }
                else
                {
                    circleImage.enabled = false;
                }
            }
        }
    }
    

    Just let AC tell you when you have something and then change buttons or whatever

    AC has its own input module, but doesn't replace the core EventSystem behaviour - and relies on it rather than its own click handling when dealing with Unity UI.

    What you could try is forcing the EventSystem itself to de-select any Button it has selected upon exiting an AC cutscene:

    private void OnEnable () { AC.EventManager.OnExitGameState += ExitGameState; }
    private void OnDisable () { AC.EventManager.OnExitGameState -= ExitGameState; }
    
    private void ExitGameState (AC.GameState _gameState)
    {
        if (_gameState == AC.GameState.Cutscene)
        {
            UnityEngine.EventSystems.EventSystem.current.SetSelectedGameObject (null);
        }
    }
    
  • Hello Chris, thank you very much for everything.

    One comment:
    On the Scratch side I can't make it work. This is what I did: created that script (the one with InvInstance invInstanceA, InvInstance invInstanceB) and added it to a gameobject. When the correct combination works, send message to that object and execute that method. It gives me an error (Failed to call function OnInventoryCombine_Alt of class NotebookController Calling function OnInventoryCombine_Alt with no parameters but the function requires 2.).

    The reason behind it is because I want that the correct combination triggers the "true" values but I can't make it work. Not sure if this is the correct way to do it.


    As for the circle, it super works! I did a little tweak here so the highlight is also a different image. It looks really nice. Here's the code for anyone who wants to achieve same effect (just the last part, which is where I added a new image2. Of course, add a variable on the top and call it image2.
    Thank you very much

        if (inventoryBox)
        {
            InvInstance slotInstance = inventoryBox.GetInstance(slotIndex);
            InvItem theItem = AC.KickStarter.runtimeInventory.hoverItem;
            if (InvInstance.IsValid(slotInstance) && slotInstance == KickStarter.runtimeInventory.SelectedInstance)
            {
                image.enabled = true;
            }
            else
            {
                image.enabled = false;
            }
    
            if (InvInstance.IsValid(slotInstance) && slotInstance == KickStarter.runtimeInventory.HoverInstance && theItem != null)
            {
                image2.enabled = true;
            }
            else
            {
                image2.enabled = false;
            }
        }
    
  • It gives me an error (Failed to call function OnInventoryCombine_Alt of class NotebookController Calling function OnInventoryCombine_Alt with no parameters but the function requires 2.).

    Don't call the event function manually - it will run automatically when two items are combined together. You can insert additional checks inside the function if you need to add further conditions.

  • Thank you very much. As you said, It was impossible for me to figure out a way to do the check inside the function. What I did instead to handle the scractch was creating several methods and triggering them manually when the combination works. Not the best approach but I'm a newbie on coding and need to rely on this for the meantime.

    On the other hand I tried to achieve the circle and reset it after the player says his line (by running a Coroutine and then setting it to false). The bad part is that the only circle it selects is the first item I click on. Been reading the documentation the whole day to figure out why it only circles the word and I think it's because it's up to the rule of "I'm holding something, so apply it just there, but not the destination item".

    Question: Is there a way to also apply it to the second item I click? The reset functions works great, the hover works great but visually is a bit weird to just show one marked item.

    Other than that, thanks and sorry for the long thread.

  • The code above will show a circle over the item currently selected. If you want to make it more complex, you'll need to adapt the code - but it really depends on the specifics of when exactly you want such graphics to show.

  • Thank you very much for everything Chris. Hope this thread can help some other adventurers. I made it work using Unity and your scripts. So far, it works!

    As a desired feature, it would be great to change bool variables through AC. Not sure how difficult it could be to develop but it will be great to do so.
    Thanks again.

  • edited April 2022

    I'd need some context - change in what way? Are you referring to AC variables, or Animator parameters?

  • Hello.

    Im referring to changing the inventory bool variables through Action lists. We are changing the ‘is used’ or ‘is scratched’ inventory bool variables.

    Thanks
  • Item parameters aren't so easy to set through Actions, since you're dealing with different instances of the original item - unlike variables which only have a single instance.

    It is possible to create custom Actions, however - see this tutorial for details.

  • Thank you Chris. Always helpful and great tutor for our team, beginners.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.