Dungeon Ho!: Unity – Dev Blog #10

Welcome back, Item Hoarders! Today we’re going to finish looking at the basics of picking up an item, as well as the structure of the Inventory object. Once we know how these classes interact, we can start piecing together the PickUpItems dialog. And that’s where the fun begins.

But first, as promised, here’s the actual code for getting all items on a particular tile in the dungeon.  It’s really, really complicated.

public List getItemsOnTile(int x, int y)
{
   List itemsOnTile = null;

   Vector2Int position;

   foreach (Item item in items)
   {
       position = item.getPosition();

       if (position.x == x && position.y == y)
       {
           if (itemsOnTile == null)
               itemsOnTile = new List();

           itemsOnTile.Add(item);
       }
   }

   return itemsOnTile;
}

Okay, I lied. It’s not. Remember that the dungeon contains a List of all of the Items in it.  All we do is loop through that list and add any item in the correct tile (denoted by its position property) to the list of items on that tile that we’re building, then we return that list.

That’s not all, though; remember that we also want to get any corpses on the tile, because although those aren’t items – merely mobs with the CORPSE flag set – we need to be able to pick them up, too.  So we actually use a slightly different method, getAllEntitiesOnTile();

public List getAllEntitiesOnTile(int x, int y)
{
    List entitiesOnTile = null;

    Vector2Int position;

    foreach (Entity entity in entities)
    {
        position = entity.getPosition();

        if (position.x == x && position.y == y)
        {
            if (entitiesOnTile == null)
                entitiesOnTile = new List();

            entitiesOnTile.Add(entity);
        }
    }

    return entitiesOnTile;
}

As an aside, I also have a few other methods along these lines, including getMobOnTile()getSolidEntityOnTile(), and probably a few others.  You never know when they’ll come in handy!

OK, so now that we can query the tile for its contents (and, in theory, send a PickUpItemCommand for one of them), what actually happens when the command is processed?  Here’s the command itself.

public class PickUpItemCommand : MobCommand
{
    private string successMessage = "{0} picked up the {1}.";
    private string failureMessage = "{0} was unable to pick up the {1}.";

    public PickUpItemCommand(Entity src, Entity targ)  : base(src, targ)
    {
    }

    public override void execute(Dungeon dungeon)
    {
        Mob srcMob = source as Mob;

        string result;

        if (srcMob.pickUpItem(target))
        {
            target.detachFromDungeon(dungeon);

            result = string.Format(successMessage, source.name, target.name);
        }
        else
            result = string.Format(failureMessage, source.name, target.name);

        Debug.Log(string.Format("{0} {1}", ToString(), target.ToString()));

        Messenger.report(result);
    }

    protected override void determineTurnOrder()
    {
        Mob srcMob = source as Mob;

        turnOrder = srcMob.getBaseInitiative() - 5;
    }
}

Ignore determineTurnOrder() for now, as we haven’t discussed combat yet.  (I told you I was much further along than the blog would indicate!)  We’re mainly interested in the execute() method, here – which, if you recall, is called by the Dungeon object every time a turn is advanced.

The first thing the method does is tell the source of the command (that is, the entity that initiated it) to attempt to pick up the target of the command, which is the item itself.  The mob’s pickUpItem() method – which we’ll look at next – returns either true or false depending on whether the mob could actually pick up the item or not.  This, obviously, can fail if the mob is already carrying too much (or for any other reason we decide to implement).  If the method returns true (success), we detach the object from the dungeon (which is a fancy way of saying we remove it from the dungeon’s item and entity lists, since it’s now a part of the mob’s inventory instead), and assign the success string to the variable that the Messenger console is going to output once the command fully resolves.  If the mob’s pickup method returns false instead, we output the command’s failure message.  You can ignore the Debug.Log() statement.  That’s purely for debugging purposes; I currently have every command output all of its data to the Unity console so I can keep an eye on what it’s actually doing when it executes.

So far, so good?  The next step is to look at what happens when the Mob attempts to pick up the item in question.  Let’s move on over to the Mob class and check out the pickUpItem() method.

public bool pickUpItem(Entity item)
{
    if (canPickUpItem(item))
    {
        inventory.getContents().Add(item);

        item.setParent(gameObject);

        item.setOwner(this);

        item.enable(false);

        return true;
    }
    else
        return false;
}

First thing we do is check to see if the mob can actually pick up the item.  If they can, we add the item to the mob’s inventory.  Next, we set the item’s parent to that of the Mob’s gameObject.  Remember that the gameObject property of any Unity script component is the Unity gameObject that the script is attached to.  Changing the item’s parent to the Mob’s gameObject, therefore, moves the item directly under the Mob in the Unity scene tree.  This gives us a quick and dirty way of eyeballing what a mob is carrying within the Unity editor.  We also set the item’s owner (a property unique to our own Entity class) to the Mob.  This allows us to know which Mob owns the item without having to reference the gameObject and then query the Mob component.  It’ll also come in handy when we write our save/load routines, since gameObjects aren’t directly serializable and our own Entity data will be.  (As you can imagine, this was how object references were handled in the original Java code, which didn’t have a convenient scene graph for us to play with.  It’ll come in handy here as well, which is why I’m keeping it.)

Finally, we disable the item so that Unity doesn’t render it.  The enable() method is literally just a wrapper around a call to gameObject.setActive(), which looks cleaner.

Before we move on, here’s the setParent() method, so you can see how the Unity parenting is done.

public void setParent(GameObject obj)
{
    gameObject.transform.parent = obj.transform;
}

Next, let’s look at the mob’s canPickUp() method.  It contains the logic that determines if the mob can actually pick up the item.

public bool canPickUpItem(Entity item)
{
    return inventory.getTotalWeight() + item.getWeight() <= getMaxCarryWeight();
}

All we do here is check to see if the current weight of the mob’s inventory, plus the weight of the item, would exceed the mob’s maximum carry weight.  If it does, we don’t allow the mob to pick up the item (by returning false).  If it doesn’t, we return true instead.  We could easily extend this method with additional logic if we needed to.

Finally, let’s look at a select portion of the Inventory class; specifically, the bits that allow us to have an inventory!  Every mob has an instance of this class.

public class Inventory
{
    private List<Entity> items;

    public Inventory()
    {
        items = new List();
    }

    public float getTotalWeight()
    {
        float totalWeight = 0;

        foreach (Entity entity in items)
        {
            totalWeight += entity.getWeight();
        }

        return totalWeight;
    }

    public List getContents()
    {
        return items;
    }
}

The inventory consists of a List of Entity objects – not Items, because remember, the player can pick up Mob corpses as well, which are derived from Mob, not Item – as well as some handy methods to query the contents of the inventory as well as tally up the weight of everything in it.  As you can imagine, this class will get more complicated once we start equipping items… but for now, this is all we need in order to let the mob carry stuff.

Whew, that was a lot!  Tune in next time when I take a brief detour into the DropItemCommand, showing you how to do this process in reverse, and then we finally start to explore the UI system and how to wrap all of this process into a handy dialog component.

-Steve

Advertisements
Categories: Development, Dungeon Ho!, Unity | Leave a comment

Post navigation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: