Forum rules - please read before posting.

Equipment window

24

Comments

  • Yes, you'll need to ensure that the Containers are present at all times, so that they can be accessed whenever the menu is opened regardless of scene.

    Create a new GameObject and parent both Container to it so that they're both individual children. Then, make sure both Containers have a Remember Container component with Retain in prefab? checked.

    To the parent object, attach the script from this on the AC wiki, which will cause it to survive scene changes. Then make the whole thing a prefab.

    To spawn this prefab as soon as your game begins, create a new ActionList asset file and use the Object: Add or remove Action to add it to the scene. Then assign this ActionList into the ActionList on start game field in the Settings Manager, which will cause it to run when the game begins, regardless of which scene you're starting from.

  • edited September 2021

    I did as you said but got this error:
    Error while saving Prefab: 'Assets/Prefabs/ContainersEquip.prefab'. You are trying to save a Prefab that contains the script 'DontDestroy', which does not derive from MonoBehaviour. This is not allowed.
    Please change the script to derive from MonoBehaviour or remove it from the GameObject 'ContainersEquip'.

    I'm sure I copied the script verbatim.

    I then tried following the instructions on the wiki instead, that is, saving the script as an asset and trying to add the component "Dont Destroy Me" to the parent object, but no such component turns up.

    I wonder what I'm doing wrong.

    PS:
    I might as well go ahead and get a nudge in the right direction regarding the rest of this endevour:

    Down the line I will want to check the contents of the container, e.g. with OnContainerAdd and Container: Check, and update the variables that keep track of the player character's "stats".

    This too is something I want to run across all the scenes.

  • I'm sure I copied the script verbatim.

    My fault, sorry. The wiki mentions naming the script DontDestroy, but it instead needs to be named DontDestroyMe, matching the class name inside the code.

    I've updated the wiki page with the correction.

    Down the line I will want to check the contents of the container, e.g. with OnContainerAdd and Container: Check, and update the variables that keep track of the player character's "stats".

    If you're dealing with stats, you'll want to rely on the OnContainerAdd event rather than an Action, so that you can update the player's stats based on that item's properties.

    Items can be assigned properties in the Inventory Manager. These are similar to AC Variables, only each item has it's own value for each property.

    You can then read these property values from the InvInstance (inventory item instance) parameter in the OnContainerAdd event.

    For example, this script will read an integer property named "StrengthBoost" for any item placed in the Container the script is attached to, and update a Global Variable of the same name:

    using AC;
    using UnityEngine;
    
    public class StatUpdateExample : MonoBehaviour
    {
    
        private void OnEnable () { EventManager.OnContainerAdd += OnContainerAdd; }
        private void OnDisable () { EventManager.OnContainerAdd -= OnContainerAdd; }
    
        private void OnContainerAdd (Container container, InvInstance containerItem)
        {
            if (container == gameObject.GetComponent<Container>())
            {
                int statValue = containerItem.GetProperty ("StrengthBoost").IntegerValue;
                GlobalVariables.GetVariable ("StrengthBoost").IntegerValue = statValue;
            }
        }
    
    }
    
  • It says I can't add the script to the container because it "does not contain a class derived from UnityEngine.MonoBehaviour"...

  • The script's filename needs to match the class name - in this case, StatUpdateExample.

  • Ok, the script is now accepted, but does nothing to update the global variable.
    I've made sure the variable's name is correct, and has a starting value.
    I've created the inventory properties and assigned the inventory item's value in said property.
    I have a label that shows the variable's value. Nothing happens when I "equip" the item (click on the inventory item so that it transfers to the container).

    [img]https://i.imgur.com/thFMfQD.png[/img]
    [img]https://i.imgur.com/58DXWJt.png[/img]
    [img]https://i.imgur.com/GKBtnjG.png[/img]

    Also, the value shouldn't really be replaced by the "boost"; it has a starting value that should be added to, but that's just a matter of operators. I just want to make sure I can affect the variables properly first.

  • Nothing happens when I "equip" the item (click on the inventory item so that it transfers to the container).

    How are you using this click to handle the transfer? Through the item's Use ActionList? Please share a screenshot showing for example item.

    Are these variables and properties all Integers?

    Paste in the following at the top of the script's OnContainerAdd function:

    Debug.Log ("Added item " + containerItem.InvItem.label + " to container " + container + ", Matches component? " + (container == gameObject.GetComponent<Container>()), container);
    

    Check the Console at this moment - it should report the item being added. What shows?

  • There's no bug report based on that, so I guess the script isn't triggered at all.

    Yes, they are handed via the use actionlist, which looks like this (for the inventory item 'cap'):
    [img]https://i.imgur.com/qqAb5kS.png[/img]

    It looks like it's working, in so far as that the items swap correctly between the inventory box and the container.

  • Are you spawning the "ContainersEquip" prefab at runtime, or are you still testing in a single test scene for now? If spawned, at what point?

    Is the script present on the "headContainer" GameObject that's in the scene at runtime?

  • edited September 2021

    Rats, this one was my mistake. I had accidentally attached the script to the parent "container"object instead of the actual container.
    It works as intended now! (Will just figure out how to work out the proper value, but I'll try myself first.)
    Thanks :)

  • edited September 2021

    Ok, I've played around with the above script, and there's some problems still. I kind of understand the logic behind it, but I'm not skilled enough when it comes to scripting...

    The first thing is obviously that the global variable should have the bonus added to it, not replaced by it.

    Secondly, it should have the bonus taken away when emptied. If I click on the item in the container - and it gets transfered to the inventory again - the bonus is still there. However, when an item is replaced by a new one, it works fine.

    Thirdly, if I expand the above script to cover all four bonus types, every new item's bonus will overwrite the bonuses given by other items in other containers.

    https://imgur.com/U9dhVcP

    My attempt uses the initial value of each global variable, since I haven't worked out how to simply add/subtract the bonus.

    This script will work as long as I only try one piece of equipment at a time, but if I've already put something in her hand, that bonus is ignored once I put something on her head.

    I should mention that I've added the script to each of the four containers.

    Looking forward to some help here :)

  • The script is just an example - it's not intended to be the final script.

    The exact nature of the script depends on how you want stats to behave. Does each container control it's own stat, or can you compound a stat by adding items into multiple containers?

  • edited September 2021

    yes, equipable items have up to four properties, and the four containers (head, right hand, left hand, foot) can hold items with various combinations of boosts.

    PS:
    I realise this isn't really AC-specific, so if you feel that you don't have time to teach me general scripting that's ok!

  • edited September 2021

    It isn't strictly AC-related, no. But something like this should do it. One script, with each stat given its own entry in the Inspector:

    using UnityEngine;
    using System.Collections.Generic;
    using AC;
    
    public class StatUpdateExample : MonoBehaviour
    {
    
        [SerializeField] private List<Container> containers = new List<Container>();
        [SerializeField] private Stat[] stats;
    
        private void OnEnable ()
        {
            EventManager.OnContainerAdd += OnContainerAdd;
            EventManager.OnContainerRemove += OnContainerRemove;
            UpdateStats ();
        }
    
        private void OnDisable ()
        {
            EventManager.OnContainerAdd -= OnContainerAdd;
            EventManager.OnContainerRemove -= OnContainerRemove;
        }
    
        private void OnContainerAdd (Container container, InvInstance containerItem)
        {
            if (containers.Contains (container))
            {
                UpdateStats ();
            }
        }
    
        private void OnContainerRemove (Container container, InvInstance containerItem)
        {
            if (containers.Contains (container))
            {
                UpdateStats ();
            }
        }
    
        private void UpdateStats ()
        {
            foreach (Stat stat in stats)
            {
                UpdateStats (stat);
            }
        }
    
        private void UpdateStats (Stat stat)
        {
            int totalValue = GlobalVariables.GetVariable (stat.baseVariableName).IntegerValue;
    
            foreach (Container container in containers)
            {
                if (container.InvCollection.InvItems.Count == 0 || container.InvCollection.InvItems[0] == null)
                {
                    continue;
                }
    
                if (InvInstance.IsValid (container.InvCollection.GetInstanceAtIndex (0)))
                {
                    int statValue = container.InvCollection.GetInstanceAtIndex (0).GetProperty (stat.propertyName).IntegerValue;
                    totalValue += statValue;
                }
            }
    
            GlobalVariables.GetVariable (stat.propertyName).IntegerValue = totalValue;
        }
    
    
        [System.Serializable]
        private class Stat
        {
    
            public string propertyName;
            public string baseVariableName;
    
        }
    
    }
    

    For each stat, you'll need a matching property and global Integer variable (e.g. "Strength" as well as a global Integer variable that acts as the stat's base value (e.g. "StrengthBase").

    If you replace the current scripts with this, and fill in the fields, it should work.

  • edited September 2021

    Using your script gives me this warning:
    Inconsistent accessibility: field type 'StatUpdateExample.Stat[]' is less accessible than field 'StatUpdateExample.stats'

  • Corrected above - try again.

  • edited September 2021

    Ok, the script compiles now, and the fields show up in the inspector.
    I've created a new set of variables, with base values, and made sure to write all the variables in the fields.

    However, trying out the script gives me this:

    NullReferenceException: Object reference not set to an instance of an object
    StatUpdateExample.UpdateStats (StatUpdateExample+Stat stat) (at Assets/Scripts/StatUpdateExample.cs:57)

    Additionally, practically all functionality is gone in the equipment window. Also, if I don't give the first global integers a value (the non-"base" ones), the stats show as 0. My idea was that I should only fill in initial values to the "base" variables.

  • However, trying out the script gives me this:

    Updated again. We're getting there!

    My idea was that I should only fill in initial values to the "base" variables.

    That should be the right workflow. See how the script works now and we'll go from there.

  • hm, just to be sure - does it matter where I put the script?

    Because I still get a similar warning:
    NullReferenceException: Object reference not set to an instance of an object
    StatUpdateExample.UpdateStats (StatUpdateExample+Stat stat) (at Assets/Scripts/StatUpdateExample.cs:60)

    And like before, I can't use the equipment properly (can't navigate or choose new items) once the warning kicks in, and like before the stats still show 0, even though I've made sure to give the "base" variables values.

    I'm worried that I have missed something fundamental here :(

  • The script itself won't interfere with the UI's behaviour, but if Unity gives an error then it will cause issues.

    If your script's line 60 refers to this:

    int statValue = container.InvCollection.GetInstanceAtIndex (0).GetProperty (stat.propertyName).IntegerValue;
    

    then the issue is likely that the assigned item does not have the property it's looking for.

    For each stat you define in the "Stats" array in the Inspector, you'll need to supply a property name. Each item will have to have these properties assigned.

    I can't give more specific advice without seeing how you've set this up. Share screens of the script component's Inspector, as well as the inventory items / variables involved.

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.