Forum rules - please read before posting.

Best way to update Inventory Item Main Graphic?

2»

Comments

  • Thanks a lot again. The screenshot seems to work as I get the "Took screenshot succesfully!" message in the console.
    However, when I display the inventory of photos, the screenshots don't appear.
    I have two "photos" that I carry from start with assigned textures. These show. When I take the screenshots and hover over the position in the Inventory box, the newly taken shots show with their names, e.g. Photo 3 etc., so it seems new items are added, but there is no texture to them.
    Would these show up in the Inventory Manager?

    Another thing. When I click on an Inventory item (photo) in the Inventory Box, I open a new menu "Photos" that is to display a lager image of the chosen inventory item. This is done through a simple Action: Menu-Change state-Turn on Menu-Photos and Menu-Select Item-e.g. Photo 1.

    For the newly added photos I get the error: Cannot change cursor to display the selected Inventory item because the item 'Photo 3' has no associated graphic.

    Also, is there any way to keep an inventory item selected until I select another one only when this menu is open (and keeping the Drag and Drop interface for gameplay)?
    I'm developing this for iOS.

    https://imgur.com/a/AB0l0Cz

  • To clarify, in the "Photos" menu I will put a "Delete this photo" button, and I assume this will be "Delete selected", which is why I assume I need to have the item seleced if when not clicked on.

  • it seems new items are added, but there is no texture to them. Would these show up in the Inventory Manager?

    I believe I've recreated the issue. In your script, replace:

    newItemInstance.Tex = screenshot;
    playerInvCollection.Add (newItemInstance);
    

    with:

    InvInstance addedInstance = playerInvCollection.Add (newItemInstance);
    addedInstance.Tex = screenshot;
    

    For the newly added photos I get the error: Cannot change cursor to display the selected Inventory item because the item 'Photo 3' has no associated graphic.

    Thanks for the details. This is an error with AC and shouldn't display in this situation. I'll correct it, but it won't impact on the game itself when it shows.

    I assume this will be "Delete selected", which is why I assume I need to have the item seleced if when not clicked on.

    Not necessarily. The Inventory: Add or remove Action's Remove method has a Remove last-selected? option, and you can also keep track of the last-clicked/selected item through scripting.

  • YES !!!! The screenshot is added as one of the thumbnails in the inventory boxes. Perfect. You're the man!
    I'll work on this using different methods but can you point me in the right direction of what I should look at when displaying the clicked thumbnail (in the inventory box) to display this my Photos menu? Right now it displays as long as I keep the mouse button pressed, but disappears when I release the button.

  • An InventoryBox element of the type "Display Last Selected" will show the item last selected, even if it is no longer.

  • Works perfect! I can't thank you enough! Your customer service is beyond excellent. And AC as well!

  • Hi,

    Sorry to revive a very old post. In the above I was helped to create in-game screenshots that are added as inventory textures. I read the posts in the beginning of this thread of how to make these textures survive save/load of games, but I cannot get it to work. Basically I'd like to save the game with the taken screenshots as textures and then update the saved images when the player adds/deletes "photos". Can you please give me a pointer of how to do this?

    Also, when saving I get the below error:
    [d3d11] attempting to ReadPixels outside of RenderTexture bounds! Reading (0, 10, 978, 560) from (977, 571)
    I assume it has to do when taking the save screenshots.

    // Magnus

  • For the saving/loading, I'd say you're best off relying on a String property, available for Items in your "photo" category, and storing the image data there. This is because item property data is automatically recorded in save-game files.

    After loading, you can then extract that data and re-apply it to the item.

    I'll need a bit of a refresher on what steps / code you've added so far, but the next step would be to create the Property available ready for items to make use of.

    Also, when saving I get the below error:

    What is the error message in full, and - if it's coming from a custom script - what is the script?

  • edited February 6

    Hi,

    Thanks for getting back so soon. I'm not sure what you mean with storing image data as a string...
    Without really knowing what I'm doing, this is what I have:
    1. A screenshot is taken at runtime and added as a texture to runtime inventory/category"Photos" This is the coroutine you helped me with last time:
    '''
    private System.Collections.IEnumerator CreateTextureCo()
    {
    yield return new WaitForEndOfFrame();

            Texture2D screenshot = GetScreenshotTexture();
            Debug.Log("Took screenshot succesfully.");
    
    
            int categoryID = 1; // Set this to the photo category's ID number
            InvCollection playerInvCollection = KickStarter.runtimeInventory.PlayerInvCollection;
            foreach (InvItem item in KickStarter.inventoryManager.items)
            {
                if (playerInvCollection.Contains(item.id) || item.binID != categoryID) continue;
                InvInstance newItemInstance = new InvInstance(item);
                InvInstance addedInstance = playerInvCollection.Add(newItemInstance);
                addedInstance.Tex = screenshot;
                PlayerMenus.ResetInventoryBoxes();
                break;
            }
    
        }
    

    '''

    1. The photos category occupies Inventory slots 8-37, 30 slots
    2. I've put a string property on them named Pic1, Pic2 etc. (alhtough I don't think this is what you meant.
    3. I've added a script prefab in the scene that I call with "Send Message" in an Action List
    4. The action list is run through the default AC Save Menu when clicking in the Save list
    5. The Send Message functions are:
      '''
      using System.Collections;
      using System.Collections.Generic;
      using System.IO;
      using UnityEngine;
      using AC;
      using System.Collections.ObjectModel;

    namespace AC
    {

    public class SavePictures : MonoBehaviour
    {
                public void SavePicTextures()
        {
            for (int i = 8; i < 39; i++)
            {
                InvInstance item = KickStarter.runtimeInventory.GetInstance(i);
                // InvVar picProp = item.GetProperty(3);
                // string picPropString = picProp.GetValue();
                string picName = "Pic" + (i - 7);
                Texture photo = item.Tex;
                Texture2D photo2D = (photo as Texture2D);
                byte[] bytes = photo2D.EncodeToJPG();
                File.WriteAllBytes(Application.persistentDataPath + "/" + picName + ".jpg", bytes);
            }
        }   
    
        public void LoadPictures()
        {
            for (int i = 8; i< 39; i++)
            {
                string tempPicName = "Pic" + (i - 7);
                byte[] bytes = File.ReadAllBytes(Application.persistentDataPath + "/" + tempPicName + "jpg");
                Texture2D photo = new Texture2D(1024, 578);
                photo.LoadImage(bytes);
                KickStarter.inventoryManager.GetItem(i).tex = photo;
            }
        }
    }
    

    }
    '''
    7. Next step would be to reference each of the saved images to a Save Slot, but I haven't got there yet.
    8. The error I get now is
    NullReferenceException: Object reference not set to an instance of an object
    AC.SavePictures.SavePicTextures () (at Assets/Scripts/SavePictures.cs:23)
    ( Texture photo = item.Tex;)

    The error message is just what I wrote above. Nothing else. It happens only sometimes when I save and I assume it has to do with the Save screenshots when I have the camera in certain angles as the saved image comes out as just gray. I will try to narrow it down more.

  • If line 23 is Texture photo = item.Tex;, then it's to do with the item not being in the Player's inventory. You're running a for loop through each item ID, but not checking if that item is present tat the time.

    With the use of properties, however, this should be avoidable. The idea of the property is to store the encoded data (which you're currently generating in this function) instead to the item's String property - so that it's saved automatically within the save-file, no need for additional files.

    To do this, return to your CreateTexturesCo function and insert the following just above the call to ResetInventoryBoxes:

    byte[] bytes = screenshot.EncodeToJPG ();
    string dataString = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
    addedInstance.GetProperty ("Photo").TextValue = dataString;
    

    (Replacing "Photo" with the name of your String property).

    This string property needs to be reserved for your screenshot data - remove the default values of "Pic1" etc.

    The next step would be to then extract this data back to the item's icon after loading - but test progress first.

  • Thanks a lot for this. I haven't completely got my head around InvItem and InvInstance, and as the property of the photo inventory item doesn't show up in in the inspector, I wasn't sure if it is saved, so I changed one line as below to change it in the inspector/inventoryManager:

    foreach (InvItem item in KickStarter.inventoryManager.items)
    {
        if (playerInvCollection.Contains(item.id) || item.binID != categoryID) continue;
        InvInstance newItemInstance = new InvInstance(item);
        InvInstance addedInstance = playerInvCollection.Add(newItemInstance);
        addedInstance.Tex = screenshot;
        byte[] bytes = screenshot.EncodeToJPG();
        string dataString = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
        item.GetProperty("PhotoID").TextValue = dataString;
        // addedInstance.GetProperty("PhotoID").TextValue = dataString;
        PlayerMenus.ResetInventoryBoxes();
        break;
    

    When deleting photos (removing the item from inventory), I also null the property in inventoryManager.
    This works fine and the string appears in the inspector, however, when I save and then load, the property in the inspector it empty, so I don't know where to take this data from when loading the save. Should it appear in the inspector/AC Game Editor?
    Or are InvInstance properties also saved and I should stick with that?

    Q1: Are there any performance/memory implications to using UTF8 vs. using Convert.FromBase64String(string)?
    Q2: Is there anywhere to put an Action list to be run "Always on load", instead of adding it to each scene?

  • I think I actually got it to work with InvInstance!
    I kept your code to update the Property of the InvInstance, although I changed it to string dataString = Convert.ToBase64String(bytes), as I got errors on UTF8.
    I also found the place to put the "ActionList after loading", where I use the below code:

            public void GetPhotos()
            {
                InvCollection playerInvCollection = KickStarter.runtimeInventory.PlayerInvCollection;
                for(int i = 8; i < 39; i++)
                {             
                    if (playerInvCollection.Contains(i))
                    {
                        InvInstance itemIns = KickStarter.runtimeInventory.GetInstance(i);
                        string picString = itemIns.GetProperty(3).GetValue();
                        byte[] bytes = Convert.FromBase64String(picString);
                        Texture2D tex = new Texture2D(1024, 578);
                        tex.LoadImage(bytes);
                        itemIns.Tex = tex;
                        PlayerMenus.ResetInventoryBoxes();
                    }
                }
            }
    

    All the photos are stored in InventoryManager with ID 8 to 37.

    Still, are there any performance/memory implications to using UTF8 vs. using Convert.FromBase64String(string)?

    Is there anywhere to see in the inspector etc., what the InvInstance look like, as it's a bit scary that e.g. the Property is being changed without seeing what it looks like.

    Good for now and thanks so much for pointing me in the right direction!!

  • I haven't completely got my head around InvItem and InvInstance

    Essentially: InvItem is the original asset, and InvInstance is the runtime instance of it. The latter should always be the one you modify at runtime - a page describing the general concept can be found here.

    Is there anywhere to put an Action list to be run "Always on load"

    You may have already found it, but the Events Editor has a Scene: Change: After event with a Due to loading save-file? option.

    Are there any performance/memory implications to using UTF8 vs. using Convert.FromBase64String(string)?

    I couldn't say - I wasn't picking one over the other, it was more an example of the general concept. If switching to Base64 works better, go with it.

    Is there anywhere to see in the inspector etc., what the InvInstance look like

    You could add a Debug.Log in there to print out the saved data, but to check this properly, look in the Save-game File Manager, at the top of the Settings Manager. Select the save-file you want to check, and it'll be in the Player Data's Items section.

  • Thanks again. Need to make better use of the Events Editor for sure!

    It's probably a Unity Editor error, but when looking at the Save-game File Manager I can only scroll down to "Save game X: Data" and Global Variables. Then the down scrolling stops and I get the error:

    GUI Error: You are pushing more GUIClips than you are popping. Make sure they are balanced.
    UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
    

    and lots of different:

    NullReferenceException: Object reference not set to an instance of an object
    AC.GVar.IsGlobalVariable () (at Assets/AdventureCreator/Scripts/Variables/GVar.cs:599)
    AC.SaveSystem.UnloadVariablesData (System.String data, System.Boolean updateExistingVars, System.Collections.Generic.List`1[T] existingVars, System.Boolean fromOptions) (at Assets/AdventureCreator/Scripts/Save system/SaveSystem.cs:2071)
    AC.MainData.ShowGUI () (at Assets/AdventureCreator/Scripts/Save system/SaveData.cs:174)
    AC.SaveData.ShowGUI () (at Assets/AdventureCreator/Scripts/Save system/SaveData.cs:42)
    AC.SaveFileManager.SaveFileGUI () (at Assets/AdventureCreator/Scripts/Managers/SaveFileManager.cs:360)
    AC.SaveFileManager.OnGUI () (at Assets/AdventureCreator/Scripts/Managers/SaveFileManager.cs:52)
    UnityEditor.HostView.InvokeOnGUI (UnityEngine.Rect onGUIPosition) (at <5f40cdb07bd44d76a23dad985a4ec283>:0)
    

    ... keeps going.

    I'm using Unity 2021.3.8f1 and AC 1.79.3

  • Thanks for the bug report.

    To fix, open up AC's GVar script and replace its IsGlobalVariable function (around line 597) with:

    public bool IsGlobalVariable ()
    {
        if (KickStarter.runtimeVariables)
        {
            foreach (GVar gVar in KickStarter.runtimeVariables.globalVars)
            {
                if (gVar == this)
                {
                    return true;
                }
            }
        }
        foreach (GVar gVar in KickStarter.variablesManager.vars)
        {
            if (gVar == this)
            {
                return true;
            }
        }
        return false;
    }
    

    Does that resolve it?

  • Yes, that works fine! Thanks again!

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.