Monday 21 March 2016

The Inventory System

Continuing on from my last post, Final A* Implementation and Inventory, I have now made much further progress with the inventory system, with it now being implemented to a functional level.


  • The Unit class now has a functioning inventory list, with Item classes now being pushed into it.
  • I have attempted to add a small level of security to the Item class, by storing its variables as private, and having them accessed externally via get methods.
  • The first entry in the inventory is registered as the active weapon, with combat now being slightly adjusted based on this. Further fine tuning will be required for the combat mechanics
    • This needs to be slightly tweaked, so that certain unit classes can only use a specific type of weapon.
  • A health vial has been implemented. When clicked on in the inventory, it will restore a units health, provided they are injured to begin with.
    • This was one of my key concerns with my project at this point. The current units inventory is represented by 5 buttons on the UI. As the inventory could end up having items added and removed from it, I wanted to make sure that the button corresponding to an item, based on position in the inventory, would always run the desired function.
    • Prior to this, I had only used UI buttons OnClick() inspector mechanics, manually adding the desired function to a button. I had to do research into dynamic button assignment, which lead me to this post on the Unity3D forums.
    • Initially, I had tried the following:

for(int i = 0; i < units[currentUnitIndex].inventory.Count; i++) {
            if(units[currentUnitIndex].inventory[i].itemType == Item.ItemType.Tool) {
                    inv[i].onClick = units[currentUnitIndex].inventory[i]._heal(units[currentUnitIndex]));
            }

        }

    • This lead to no success in the slightest. Upon finding the forum post mentioned above, I tweaked the for loop slightly, leading to this:

for(int i = 0; i < units[currentUnitIndex].inventory.Count; i++) {
            if(units[currentUnitIndex].inventory[i].itemType == Item.ItemType.Tool) {
                    inv[i].onClick.RemoveAllListeners();
                    inv[i].onClick.AddListener(delegate { units[currentUnitIndex].inventory[i]._heal(units[currentUnitIndex]); });
                }
            }
        }
    • While this for loop lead to some results, I kept having errors return, stating that the index was out of range. Starting to panic, I decided to create an Item temporary variable within the loop, storing the Item used in there, and calling on the _heal method from there. At this point I also added an if statement, declaring that the method would only be available if the Item name was "Health Vial", but realised shortly after that it was not required, due to how I set the _heal function up. My for loop ended up as so:
        for(int i = 0; i < units[currentUnitIndex].inventory.Count; i++) {
            if(units[currentUnitIndex].inventory[i].itemType == Item.ItemType.Tool) {
                    Item item = units[currentUnitIndex].inventory[i];
                    inv[i].onClick.RemoveAllListeners();
                    inv[i].onClick.AddListener(delegate { item._heal(units[currentUnitIndex]); });
            }
        }

    • By storing it as a temporary variable, this seemed to remove any issues with the index being out of range, allowing it to work with no visible issue, and no errors.
    • Having contemplated the removed if statement during the writing of this, I have decided to add it back, as I may add items that effect stats temporarily, meaning that Item.ItemType.Tool will not only be used for healing units:
        for(int i = 0; i < units[currentUnitIndex].inventory.Count; i++) {
            if (units[currentUnitIndex].inventory[i].itemType == Item.ItemType.Tool) {
                if (units[currentUnitIndex].inventory[i].Name == "Health Vial") { 
                    Item item = units[currentUnitIndex].inventory[i];
                    inv[i].onClick.RemoveAllListeners();
                    inv[i].onClick.AddListener(delegate { item._heal(units[currentUnitIndex]); });
                }
            }
        }
  • This now means that combat is being dictated much more by weapon choice and type, and a health Item can be applied to units.
  • As a small bug fix, I now have changed code around, so that the path is visible to players, and only shows the path up to the amount of spaces a Unit can move. While I had attempted to implement this earlier, I realised only recently that an if statement within the Tile update was turning them white, meaning the path could never be fully visualised.
My next steps will possibly be my most challenging, as I am aiming for AI implementation, as it has been put off due to other aspects of the project. This will start off with readings during this current week, and hopefully start implementation by next week.

There is one more aspect I would like to attempt to tackle before this too. At this current point, units are being instantiated in based on the worldSize for positioning. Instead, I would like to be able to use the grid[ , ] array to position the units, as this will make for more direct instantiation of units, requiring much less math to place units initially. While this will not be my primary focus, I believe it will aid in AI implementation, in terms of positioning AI units.




Sunday 13 March 2016

Final A* Implementation and Inventory

Following on from my last, Continuing with A*, I met with my lecturer Chris Janes, I have now got my A* pathfinding working much more accurately.

Last time, I was struggling to alter the diagonal movement within the pathfinding. With the advice I was given at my meeting, I have now altered the pathfinding to work along horizontal and vertical connections.

Previously, the pathfinding would look at neighbouring nodes (public List<Node> GetNeighbours in Grid.cs) by creating a 3x3 grid, with the current node in the centre, and checking every position in the grid bar the centre to determine how to move. Now, when neighbours are being added, it simply calls on the nodes positioned above, below, left, and right. I had originally attempted to alter the use of the 3x3 grid, cutting out diagonally placed nodes, but it was pointed out that I could achieve this much quicker by simply calling on the 4 neighbours the node required.

Movement has been tweaked, so there is a slight delay in a unit moving from space to space, giving a sense of visible movement. While I have issues that will be ironed out later, at this point, I now have a successfully working pathfinding system.

Following this, I decided to start looking towards my inventory system. Going along the ideas explained in my previous post, I still believe that it will be most beneficial to get an inventory system implemented, before moving onto AI.

I have created 2 new classes, the Item class, and the Items class:

  • The Item class is a representation of an item itself. It can function as either a Weapon or utility item, currently using the variable stats Damage and Hit Chance, or Heal amount.
  • These items are created within the Items class. Though currently containing only one, the items class will have a method for every item available within the game. The method creates a new Item class, assigning the required stats, then pushes it into the players Inventory List.
At first, I ran across some issues:
  • When I initially tried the method above, I received a warning stating that a MonoBehaviour based script, I could not create it as I was attempting to:


public void IronSword(Unit unit)  {


            Item item = new Item(0, "Iron Sword", 5, 10, 0);

              unit.inventory.Add(item); 
      (This was originally being pushed externally. In the generateUnits method in GameManager, the item was being called to be created through the Items script, being stored as a public Item variable on that script, then trying to move that Item into the Unit's inventory.)
            }
        • Following this, I removed the MonoBehaviour from the Item class. While I was no longer receiving the warning, I was getting Errors stating that, once the item was being pushed into the inventory, that no object existed to be pushed.

        • Not clear on why this error was being received, I instead chose the opposite route; to work with the item as a MonoBehaviour class. To do this, I had to use AddComponent(), to attach the item class as a script to the unit gameObject. Due to how the Item class has been set up (Visible below under Item.cs), I could create a new Item class, but I could not input the values required, instead leaving a blank item class on the unit.

        • As this was getting me nowhere, I went back once again, removing MonoBehaviour again from the Item class. I attempted the method seen above, with unit.inventory.Add(item) being added at this point. The unit in question is currently being set through the generateUnits method in GameManager. As items outside of set up should only be accessible to the current unit at the time, I will be able to call on the current unit as the (Unit unit).

        Overall, while I still have some steps to make to finishing the inventory system, I have found it much easier to implement than expected. My main concern at this point is the sorting and re-ordering of Inventory List. While I may be able to create a work-around, I intend to keep the active weapon in space [0] of the list, rather than requiring further bools in the Item class, or for the player to specifically keep referencing items within the inventory.

        This shall be completed and implemented around the middle of next week, so AI implementation can be ideally before next week is out.