Dungeon Ho!

Dungeon Ho!: Unity – Dev Blog #14

Welcome back a second time, dungeon generators!

Today (again), we’re going to look at the DungeonGenerator class of objects, which are Unity ScriptableObjects and really, really useful.

What is a ScriptableObject?  I’m still not entirely sure.  But near as I can tell, they’re Unity components that basically hold data, and can have scripts attached to them, but are not actually GameObjects and don’t exist in the game world.  Therefore, I decided to use them to generate my dungeons.  Did I need to do this?  Couldn’t I just create a bunch of, say, static C# classes derived from a DungeonGenerator class?

Well, yes; I could have.  One thing that makes ScriptableObjects neat though is that they’re exposed to the Unity editor, and you can store data directly in them.  As you’ll see, this comes in pretty handy.

But first, the basics.

Here’s my original abstract DungeonGenerator class:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

[CreateAssetMenu(fileName = "DungeonGenerator", menuName = "Dungeon Generator", order = 0)]
public class DungeonGenerator: ScriptableObject
{
    public void generateDungeon(Dungeon dungeon, int level, bool questLevel, int w, int h)
    {
        Debug.Log(string.Format("DungeonGenerator.generateDungeon({0} - {1});", dungeon.getEnvironment().name, level));

        generateDungeonMap(dungeon.getDungeonMap(), w, h);

        populateDungeon(dungeon, level, questLevel);
    }

    public virtual void generateDungeonMap(DungeonMap dungeonMap, int w, int h)
    {
    }

    public virtual void populateDungeon(Dungeon dungeon, int level, bool questLevel)
    {
    }
}

The CreateAsset tag creates options in the Unity Editor’s Assets menu to create a new asset of this type.  It’s kinda useless for the DungeonGenerator object, because, much like a pet platypus, it doesn’t do much.  It’s the subclasses that we really want to use it for.  So why do I have it here?  Truthfully, I don’t know.  Probably just so I can copy-paste it and change the parameters, because I’m an old man and my memory is failing.

Anyhoo, you’ll notice that there are three methods; generateDungeon(). generateDungeonMap(), and populateDungeon().  The Dungeon class, which contains a public variable of type DungeonGenerator, calls the generateDungeon() method to initialize its map variable, which is of course the DungeonMap object we’ve looked at previously (and which, as you notice here, is passed in to the generation method proper).

So, all we have to do in order to create a new DungeonGenerator is to subclass this class (…why isn’t it abstract, then?  It can be, but it’s not 100% necessary I guess), then override the two virtual methods.  We’ll look at that in a second.

Why is this useful?  Well, during development you definitely want the ability to generate different kinds of dungeons.  Currently, I have the DefaultDungeonGenerator, which creates the actual, legit dungeons that are used by the game, a TestDungeonGenerator, which creates a simple, 10×10 map every time (that I mainly use to test basic stuff without being harassed by other Mobs), and a MonsterMashDungeonGenerator, which generates a 10×10 map like the TestDungeonGenerator… but fills it with a passed-in monster type so that I can… test that kind of monster.  There’s a lot of reasons you may want to simply dump an army of kobolds into your map and see what happens, the very least of which is to see if their randomly-generated attributes and gear break under stress.  So it’s very useful to do this.  But, I digress.

So the first thing you need to do is create a member variable in your Dungeon class of type (wait for it) DungeonGenerator.  Then, once you’ve created DungeonGenerator assets in your Unity project, if you want to change the type of DungeonGenerator being used in the game, simply drag the new asset into this field and off you go.  Here’s a screenshot of the assets themselves, after they’ve been created with the Assets->Create command.

DHo ss 1

…and here’s the Dungeon object with the generator asset assigned via the script’s public variable.

DHo ss 2

(We may look at that startRevealed boolean another time; for now just note that it’s another debugging tool that alters the visibility of the map, which lets me not have to explore the entire thing to get a bird’s eye view of the proceedings.  Handy!)

Now, as I said, the TestDungeonGenerator simply generates a basic “box” with entrances and exits, so we’re not going to do much with that one.  We’ll close out this post by taking a quick look at the MonsterMashDungeonGenerator’s ability to take data.

Here’s the code of the MMDG;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "MonsterMashDungeonGenerator", menuName = "(Monster Mash) Dungeon Generator", order = 0)]
public class MonsterMashDungeonGenerator : TestDungeonGenerator
{
    public string monsterType;

    public override void populateDungeon(Dungeon dungeon, int level, bool questLevel)
    {
        Monster monster;

        for (int r = 5; r < 10; r += 2)
        {
            for (int c = 3; c <= 7; c += 2)
            {
                monster = ObjectSpawner.spawnMonster(monsterType, 1, false, false);

                monster.setPosition(c, r);

                monster.attachToDungeon(dungeon);
            }
        }      
    }
}

Note the public monsterType variable.  Once you’ve created a MonsterMashDungeonGenerator asset in your Unity Editor, this field will appear in the Inspector window when you click on it.  Each type of Monster in DHo!:U has a “tag” variable defined that denotes its monster type.  eg a Kobold’s tag is “kobold”.  If you pass that type tag into the ObjectSpawner, it spawns a monster of that type.  How?  Magic.  But seriously, we’ll look at the ObjectSpawner in more depth in a future blog, because it’s both very complex and very simple.  I’m quite happy with it.

Anyway, once you assign the MMDG asset with a monster type set to the Dungeon as indicated above, a box map filled with that kind of monster will be generated in the game, and there you go.  And the map itself?  Well, note that MMDG is a child class of TestDungeonGenerator, and I did not override the parent generateDungeon() method.  This means that it will simply generate the same map that a TestDungeon does.

Being able to swap out DungeonGenerators is so useful it simply can’t be repeated enough.  Hopefully you find this little trick relevant for your projects, either now or in the future.  Tune in next time when I go over the algorithm used to create the mazes used in the game.

-Steve

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

Dungeon Ho!: Unity – Dev Blog #13

Welcome back, dungeon generators!  Once again I’ve been too busy actually developing to stop and create new blog entries… but I have good news.  That being, that Dungeon Ho!: Unity is about to enter what I call the “core systems playtesting” stage.  This is where I make a standalone build of the game, hand it off to some willing friends, and watch them utterly break everything I’ve labored to build over the last, uh… amount of time that I don’t really want to ponder.

That’s actually a good question, though; how long has DHo!:U been in development?  Well, the astute among you will notice that I began this dev blog roughly two years ago.  Unfortunately, I haven’t been working on the game straight through all of this time; I’ve been adding bits and pieces to the core engine when time has permitted, documenting the features as I added them in this blog.  (And you can see a rough timeline of how that’s gone by looking at the post dates.)

The good news is, since this great nation of ours decided it was a crime to set foot in your front yard I’ve had plenty of time to focus on building the game, and development progress has far outstripped the rate at which I’ve been blogging, since as you can imagine given the choice between implementing features or testing the game and blogging about implementing features, I’d rather be pushing forward and doing the former.

So, today we’re going to take a detour from looking at the inventory management UI and dig into the first of the next two topics I want to cover, which people will find a lot more interesting than how to hook up a Unity event; dungeon generation.  Dungeon Ho! uses a fairly straightforward but really cool random dungeon generator that does way more than simply connect squares together like a lot of Roguelikes, but it doesn’t go crazy and use far-out generation procedures involving noise or natural terrain or anything of that nature, balancing atop the line between “simple” and “complex” while still managing to look really cool.

Before I go into that though, I want to touch in more depth on the topic of DungeonGenerators.  I alluded to this back when I first began developing the dungeon generation code, but didn’t really say much about it in any great detail.  In recent days it’s been an absolutely invaluable tool for both development and testing, though, so I want to do a bit of a deep-dive and show you just what I’m on about.  So, bop on over to the next blog entry after this one and we’ll take a look.

-Steve

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

A moment of reflection

Hello everyone,

Dungeon Ho!: Unity has been in development for long enough that I’ve got a solid prototype working, and since one of the primary focuses (foci?) of the project has been refactoring and redesigning, I thought I’d take a moment to talk about the two biggest time-savers I’ve managed to implement in the rewrite.

Using the platform’s native UI framework

This is a huge one.  HUGE.  I’ll say it louder for the people in the back; IT’S HUGE.

When I first wrote Dungeon Ho! for the Android platform, I didn’t know anything about layouts or its native input controls.  All I could do was blit to a SurfaceView, and given that my background was in J2ME development, which is both Java-based and requires you to do that, I knew that would be enough.  I was used to rolling my own UI components; I knew how to make buttons click and dropdowns… drop down.  I could scoll my own text, even; and I could be assured that it’d all work as I expected and I wouldn’t see some last-minute framerate drop because you can’t overlay, say, a FrameLayout over your SurfaceView because reasons.

That was the idea, anyway; go with what you know to keep development time short.  And I think in the long run it was a good idea, because DHo! still took close to two years to finish.  Imagine how long it’d have taken if I had to learn Android’s UI stuff on top of it.

Now, I’ve gone the other way.  I learned Unity’s UI/canvas system before I started working on the port and all of the UI controls are done “the Unity way”, and it’s saving me a shit-ton of work.  All of that event handling code, the animation code, the mouse-clickthrough code, the math and resizing code, all of it is already done for me.  Adding a new screen is as easy as drag-and-dropping a new canvas and tossing some buttons on it.  I did the entire start-game flow (…with placeholder art, natch) in little under an hour.  That would have taken me a day or two, the old way.

So in short, know your tools.  You have no idea how much it helps, no matter how good you are in other ways.

Data, data, everywhere

Roguelikes are procedurally-generated, and DHo! probably moreso than most, these days.  Everything is created in code, from the maps to the monsters’ stats to the items; there’s no entry in a list that says “Potion of healing: heals 25hp”.  The code does it all; generates a base potion, randomly figures out what effects it has when drunk, and then names it accordingly.  This makes for a very, very varied playthrough experience.

It also makes for a fucking huge, complex codebase.

I’ve already touched on this when I wrote about the monster definitions; yes, you can follow the same process to copy-paste code templates and rename variables to create a new Monster, but why would you?  Just define a JSON file with the monster’s parameters (eg. “Kobolds range from 50 to 100 pounds”) and let a generic routine parse that data and figure it out.  It’s so much simpler to add an entry to a generic Item file that says “Daggers can be made of wood or metal” than to have to remember which chunks of code to copy and modify to say “if this item is a dagger, make it out of wood or metal”.

Why didn’t I do this the first time?  I think for some reason I assumed that if I defined data files I’d not have the flexibility I had in procedural generation.  Also, and this goes back to knowing your tools, I didn’t know how to handle text files, especially JSON, in Android… and didn’t think it was worth researching.  I will never do that again.

Well, there you have it; the two biggest lessons I’ve learned in porting this project so far.  The new codebase is much cleaner and more flexible than the old, and I’ll be very careful to make sure I don’t sacrifice this going forward.  I will also never not take the time to do proper research on a feature and cut corners in my personal projects again.  After all, I’m not on a deadline.

Tune in next time when we return to coding, with the promised dungeon generation classes.

-Steve

Categories: Development, Dungeon Ho! | Leave a comment

Dungeon Ho!: Unity – Art Blog #2

Good news, everyone!  I’ve completed the initial revamp of the random dungeon generation algorithm, complete with more detailed tilesets.  Here’s a screenshot of it in action;

DHU ss1

The next dev blog will detour from the usual wibbling on about inventory pickups and delve into the process I used here.  Stay tuned.

-Steve

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

Dungeon Ho!: Unity – Livestream update

o hai.  Do you… like to watch?

I’ve started livestreaming the development of Dungeon Ho!: Unity on Twitch.  In theory, I am live from 11am to 4pm weekdays, Pacific Standard Time.  In reality, I’m not very good at keeping that schedule and tend to roll in anywhere from 11-12:30.  If the coding process interests you to the extent that you would love to watch it unfold in realtime, come visit my channel at https://www.twitch.tv/sandalfootproductions/ – and be sure to Follow me so you can get notified of such things relevant to your interests.

-Steve

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

Dungeon Ho!: Unity – Art Blog #1

‘sup.  We’re breaking from our usual content format to give you a sneak peek at the game’s graphics overhaul, which is currently in progress.  The first step is to expand the game’s tileset to allow for a more richly detailed map.  You can see the bulk of the work being done here in the new Tomb/Dungeon environment tiles.

Tombs Tileset

-Steve

Categories: Artwork, Development, Dungeon Ho! | Leave a comment

Dungeon Ho!: Unity – Dev Blog #12

Welcome back, Item Picker-Uppers!  Today we’re finally going to look at the PickUpItemsDialog and how to leverage all of the things we’ve done so far in order to get items from the map into the player’s inventory, and back again.  But first, we need to know how to trigger this sort of thing from a keypress.

Do you remember the DungeonMaster class?  That’s the one that handles player keypresses.  I’ve done a lot of things to this class since we’ve seen it last, but the thing we’re most interested in is the collectInput() method:

// Primary keyboard driver - Queries Input object and puts commands in queue.
    public void collectInput()
    { 
        UIScreen topmostScreen;

        if (uiManager == null)
            uiManager = dungeon.getGame().getUIManager();

        topmostScreen = uiManager.getTopmostUiComponent();

        // Hotkeys
        if (Input.GetKeyDown(KeyCode.P))
            addCommand(new PassCommand(dungeon.getPlayer()));

        // Hotkeys for particular screens ////////////////////////////////////////
        if (topmostScreen != null)
        {
            // We don't want the user to be able to operate stuff "under"
            // any currently-displaying UI components.  IE, they shouldn't
            // be able to move with the character screen up.
            topmostScreen.handleHotkey();

            if (Input.GetKeyDown(KeyCode.Escape))
                topmostScreen.hide();

            return;
        }

        // Screen activation /////////////////////////////////////////////////////
        if (Input.GetKeyDown(KeyCode.I))
            uiManager.showUI(UIManager.INVENTORY_SCREEN);

        if (Input.GetKeyDown(KeyCode.C))
            uiManager.showUI(UIManager.CHARACTER_SHEET);

        if (Input.GetKeyDown(KeyCode.G))
            uiManager.showUI(UIManager.PICK_UP_ITEMS);

        if (Input.GetKeyDown(KeyCode.Q))
            uiManager.showUI(UIManager.QUEST_LOG);

        // Directionals //////////////////////////////////////////////////////////
        if (Input.GetKeyDown(KeyCode.LeftArrow))
            addCommand(new MoveCommand(dungeon.getPlayer(), MoveCommand.WEST));

        if (Input.GetKeyDown(KeyCode.RightArrow))
            addCommand(new MoveCommand(dungeon.getPlayer(), MoveCommand.EAST));

        if (Input.GetKeyDown(KeyCode.UpArrow))
            addCommand(new MoveCommand(dungeon.getPlayer(), MoveCommand.NORTH));

        if (Input.GetKeyDown(KeyCode.DownArrow))
            addCommand(new MoveCommand(dungeon.getPlayer(), MoveCommand.SOUTH));

        // TODO: Read abstract game actions
        // TODO: Read mouse/clicks
    }

Fun stuff!  The first part of the method assigns a reference to the pre-existing UIManager so that we have something to work with, assuming we haven’t already done so, and the next bit determines the topmost UI Canvas so that we can feed it keypresses.  Basically, if there’s a screen already active, it should get all the keys and then exit the method.  If there isn’t a UI Canvas visible, then we can assume a keypress will be one of the player commands… such as picking up an item (…see what I did there?).

As you can see, we’ll trigger the PickUpItemsDialog with the ‘G’ key on the keyboard – and eventually the mouse, when we get that far.  But that’s a post for another time.

If you recall from last time, we can simply call the showUI() method of the UIManager to activate the relevant canvas.  In this case, it’s the UIManager.PICK_UP_ITEMS canvas.

Speaking of which, let’s take a look at it;

DHU 31

I’ll leave it as an exercise to you, the reader, to recreate this dialog in the Unity editor.  It’s basically just three buttons and a ScrollView.  Each element of the ScrollView is a Prefab denoting an entry in the list, which is currently just a Text label.  We’ll look at slot prefabs in more detail once we take a deep dive into the inventory screen.

public class PickUpItemsDialog : UIScreen
{
     public GameObject dungeon;
     public GameObject contents;
     public GameObject slotPrefab;
}

At its base, the PickUpItemsDialog is a UIScreen, the abstract class we looked at last time.  It has public slots for the dungeon, its own contents (the GameObject representing the ScrollView’s content object), and its object Prefab, which – as previously explained – is simply a Label.  The beauty of using a Prefab here is that we can design a new slot object, perhaps with icons or something, and swap it out with no extra effort on our end apart from maybe having to change a line or two of code to not reference the Label if we decided to delete it.  Simply drag and drop the relevant game objects into these slots in the Editor and away we go.

Next up is the overridden method, prepare():

public override void prepare()
{
     Vector2Int playerPos;

     base.prepare();

     playerPos = player.getPosition();

     populateList(dungeon.GetComponent<Dungeon>().getAllEntitiesOnTile(playerPos.x, playerPos.y));
}

We’ll need the player’s position, so we grab it after we call the base prepare() method (so that we have a player to grab it from, among other things).  Then we populate the list of items based on the objects we get from the dungeon object.  (Since the dungeon is a GameObject, we get a reference to its Dungeon component first, since that’s where all of the data is.)

private void populateList(List<Entity> entsOnTile)
{
     clearcontents();

     if (entsOnTile != null)
     {
          foreach (Entity entity in entsOnTile)
          {
               if (entity != player)
                    createEntitySlot(entity).transform.SetParent(contents.transform);
          }
     }
}

private void clearcontents()
{
     foreach (Transform text in contents.transform)
     {
          GameObject.Destroy(text.gameObject);
     }
}

populateList() populates the contents object with slot prefabs based on the items passed into the method.  First it removes all of the existing items from the list, then creates a new Slot prefab for each item and attaches it by parenting it to the contents object.  The slot prefab is created in the createEntitySlot() method, which spawns a new instance of the Slot prefab and sets its text to the name property of the passed-in item.

private GameObject createEntitySlot(Entity item)
{
     GameObject slot = Instantiate(slotPrefab);

     PickupSlot slotComponent = slot.GetComponent<PickupSlot>();

     slot.name = slot.name.Replace("(Clone)", "");

     slotComponent.pickupDialog = this;

     slotComponent.setItem(item);

     slot.GetComponentInChildren<Text>().text = item.name;

     return slot;
}

Each SlotComponent (…which we’ll look at next) contains a reference to the dialog, as well as the Item object it’s attached to.  We need both of these objects so that it can manipulate the dialog and tell the PickUpCommand which item it should run on when the user clicks the relevant button.

Speaking of the PickupSlot Prefab object, it has the following script attached;

public class PickupSlot : MonoBehaviour
{
     private Color unselectedColor = Color.black;
     private Color selectedColor = Color.green;

     private Entity item;

     private bool selected;

     public PickUpItemsDialog pickupDialog;

     public void setItem(Entity i)
     {
          item = i;
     }

     public Entity getItem()
     {
          return item;
     }

     public void toggleSelected()
     {
          selected = !selected;

          if (selected)
               gameObject.GetComponentInChildren<Text>().color = selectedColor;
          else
               gameObject.GetComponentInChildren<Text>().color = unselectedColor;
     }

     public bool isSelected()
     {
          return selected;
     }
}

The most interesting method is the toggleSelected() method, which changes the color of the Prefab based on whether or not it’s selected.  When the user clicks on an item in the Pickup dialog, we want to highlight it/de-highlight it so that it’s included (or not) in the items that are to be picked up.  Therefore, each slot has a boolean that determines if it’s been selected or not.

So, how does all of that work?  Well, it requires an Event Trigger.  We define one and then attach it to the PickupSlot prefab, like so;

public class PickUpItemEventTriggerHandler : EventTrigger
{
     public override void OnPointerClick(PointerEventData data)
     {
          PickupSlot slot = gameObject.GetComponent<PickupSlot>();

          slot.pickupDialog.onItemSelected(slot);
     }
}

The OnPointerClick() method is automagically called when the Prefab is clicked, passing in the Event data of the PointerEvent that was generated by said click.  The event was generated by the gameObject the script is attached to, so we simply grab the PickupSlot script component of that gameObject, then call its attached pickupDialog’s onItemSelected() method, passing in that slot component.  We do this because the dialog may have to do some bookkeeping relevant to itself when the slot is selected, and we don’t want to tangle that code up in here.  Keeps everything neat.

The onItemSelected() method looks like this;

public void onItemSelected(PickupSlot slot)
{
     slot.toggleSelected();
}

And finally, we use the Unity Editor to call either pickUpSelectedItems() or pickUpAllItems() on the PickUpItemsDialog when the relevant button has been clicked.  pickUpAllItems() simply loops through all of the slots attached to the ScrollView and generates a PickUpItemCommand for each one, so we won’t bother to look at it.  We’ll look at pickUpSelectedItems() instead.

public void pickUpSelectedItems()
{
     DungeonMaster dm = dungeon.GetComponent<Dungeon>().getDungeonMaster();

     PickupSlot slot;

     foreach (Transform child in contents.transform)
     {
          slot = child.gameObject.GetComponent<PickupSlot>();

          if (slot.isSelected())
               dm.addCommand(new PickUpItemCommand(player, slot.getItem()));
     }

     hide();
}

As you can see, the foreach loop checks all of the contents’ object’s children to see if their PickupSlot component is selected.  If it is, a new PickUpItemCommand – which we saw way back when we looked at Command objects – is generated with the player as the source and the Item entity linked to the slot as the target.  The DungeonMaster object then processes all of these commands.

Could we have simply added the selected items to a separate list and then looped through that list and picked up all the items?  Sure, we could have.  Whether or not that’s a better solution is left as an exercise to the reader.  Finally, though, we call hide() on the pickupDialog, which hides it from view until we’re ready to pick up more items.

There’s one final note, here; I’ve implemented a maximum length on the player’s command queue, so if there are more items in the tile than slots in the queue, the player will only be able to pick up as many as there are free slots.  So for example, if the queue’s maximum length is 10 and there’s 20 objects in the tile, the player will only be able to pick up 10 items with one click, no matter how many they select in the dialog.

Well, that certainly was a big one! (obligatory “That’s what she said” joke here.) Hope it was worth the wait!  We’ll be using a similar model for other UI dialogs, especially the Inventory screen.  Tune in next time when we do just that, which will give us the ability to drop items back into the dungeon.

– Steve

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

Dungeon Ho!: Unity – Dev Blog #11

Welcome back, my long-lost readers!  It’s been way too long.  You’re looking well.  I wish I could say I’ve been hard at work on the ‘Ho!, but that would be a lie.  You know how it is.  Things happen.

Anyway… I’m here now, and that’s all that matters.  When last we met, I promised y’all that we would take a look at the UIManager and its various related classes, which is a convenience that I whipped up in order to manage all of the various menu screens and dialogs needed to make the game work.

But first, let’s talk design.  The UIManager class is basically a collection of methods that tracks, keeps reference to, and handles various functionality – such as hiding and showing – screens and dialogs from within the game.  These various UI components are, as you may well know, Unity Canvas objects with a script attached, appropriately named UIScreen.

Before we carry on with that, I noticed something that’s been happening ever since I started using text blocks to format my code examples.  Specifically, that the left and right angle brackets (< and >) in my code are getting “swallowed” by the HTML parser, and I can’t be assed to go in and correct every single instance of it.  If it affects anything important, like if-then logic, I’ll deal with it.  Otherwise, the bulk of the cases are List object declarations; so if you see something like List myList, assume I’m really trying to say List<Class> myList and roll with it.  You’re smart, you should be able to figure out what the relevant class is supposed to be.  Got it?  Good.  Let’s continue.

In Dungeon Ho! parlance, a UIScreen is basically a Unity Canvas with some additional functionality attached via a script, like so;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIScreen : MonoBehaviour {

    protected Player player;

    // Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}

    // Override this method to prepare the screen for viewing.
    public virtual void prepare()
    {
        if (player == null)
            player = GameObject.Find("Dungeon").GetComponent().getPlayer();
    }

    public void show()
    {
        // Yes, this doesn't make sense - but if the prepare(); method
        // alters the contents of the UI, its positions/dimensions/etc. 
        // won't get re-calculated if it's not active.
        gameObject.SetActive(true);

        prepare();
    }

    public void hide()
    {
        gameObject.SetActive(false);
    }

    public void toggle()
    {
        if (gameObject.activeSelf)
            hide();
        else
            show();
    }

    public bool isShowing()
    {
        return gameObject.activeSelf;
    }

    public virtual bool handleHotkey()
    {
        return false;
    }
}

The most interesting bits of the code are in the prepare() method.  This method is called before the UIScreen is about to be shown, and is where each subclass initializes its UI components with the relevant data, as we’ll see in a future post.  It also makes sure that there’s a reference to the game’s Player object, by explicitly caching a reference to one if it can find it.  (ProTip:  If it can’t find it, you broke the game somehow.  There will always be a player object for it to find.)

Why do we do this, rather than simply go into the Unity UI and drag our Player into the relevant slot?  Because it’s one line of code that does the same thing for every UI component and I can’t be bothered to do it the other way.  Maybe if I had a UI guy wiring up these dialogs for me, I’d care.  Rule #1 of solo projects, it’s okay to cut corners and not always follow “best practice” – which is usually only “best” because engineers love to follow the herd.  Mini-rant over.

Also note that the show() method puts what we just described into practice, by calling the prepare() method after setting the gameObject (IE, the UI component this script is attached to) active.  Why don’t we call prepare() first?  Because one of the first “features” I discovered when (logically) implementing it that way is that Canvases don’t update their UI components when they’re not active, so trying to set the data of, say, a ScrollContainer in the Canvas will simply fail.  (Hey, that’s in the code comments – whaddaya know.  Rule #2 of solo programming, always document this stuff when you find it… especially when you’re old and your memory is going, like I am – and mine is.)

OK, enough about UIScreen.  We’ll see how to actually make one in a future blog post.  Let’s look at UIManager next.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager
{
    public const int INVENTORY_SCREEN   = 0;
    public const int CHARACTER_SHEET    = 1;
    public const int PICK_UP_ITEMS      = 2;
    public const int QUEST_LOG          = 3;

    private List uiComponents;

    public UIManager(GameObject ui)
    {
        uiComponents = new List();

        foreach (Transform canvas in ui.transform)
        {
            uiComponents.Add(canvas.gameObject.GetComponent());
        }

        Debug.Log("UIManager found " + uiComponents.Count + " UI components.");
    }

    public void showUI(int id)
    {
        uiComponents[id].show();
    }

    public void hideAll()
    {
        foreach (UIScreen screen in uiComponents)
        {
            screen.hide();
        }
    }

    public void hideUI(int id)
    {
        uiComponents[id].hide();
    }

    public void toggleUI(int id)
    {
        uiComponents[id].toggle();
    }

    public bool isShowing(int id)
    {
        return uiComponents[id].isShowing();
    }

    public UIScreen getUiComponent(int id)
    {
        return uiComponents[id];
    }

    public UIScreen getTopmostUiComponent()
    {
        UIScreen top = null;

        foreach (UIScreen screen in uiComponents)
        {
            if (screen.isShowing())
                top = screen;
        }

        return top;
    }
}

First thing you’ll notice is a bit of laziness; I loop through the passed-in GameObject (…which is the top-level scene node that I have parented all of my UI canvases to) and grab references to them, putting them into a local List, which is indexed by constants.  (I could also have made those constants Strings and used a Dictionary.  Either-or.)

Now, whenever I want to reference a particular UI component, I just use its index constant.  Like so;

uiManager.hide(UIManager.QUEST_LOG);

…and speaking of, the main Game object instantiates an instance of UIManager in its own Unity-supplied start() method;

uiManager = new UIManager(GameObject.Find("UI").gameObject);

Note that I pass in the GameObject named “UI”, as previously described.

Pretty straightforward, eh?  Tune in next time when we look at the Inventory Screen, how it’s derived from UIScreen, and how it’s wired up to the Player’s inventory.  Once that’s out of the way, we’ll intercept some mouse clicks and be able to pick up and drop items… finally!

– Steve

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

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

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

Dungeon Ho!: Unity – Dev Blog #9

Welcome back, flag flippers! Rather than leave you all hanging, I decided to follow up yesterday’s dev blog with a short detour into the wonderful world of boolean operators. This is how the Entity flags are stored, so it’s a pretty useful topic for the aspiring Roguelike programmer. I first learned how to do this by browsing the Quake II source code nearly twenty(!) years ago, but obviously the technique goes back way farther than that.

As I’m sure you already know, numbers are stored in variables as binary values, which means that they’re converted from base 10 (1, 2, 3, 4, etc…) to base 2 – so, ultimately, they’re represented as strings of 0’s and 1’s.  Boolean operations let us act on these variables at the bit level (IE, on the 0’s and 1’s themselves).  We can use this trick to store a bunch of values in one single integer (or double, if you need more) that we’d normally need a stack of boolean variables to represent.

The trick is, each bit’s position in the integer is equivalent to the number 2 raised to a particular exponential value.  For example, 20 is 1. 23 is 8.  When you convert those resulting numbers to their binary representations… they just so happen to place a single 1 into the integer at the exact position of the exponent (starting with zero, of course; computers are funny that way).

For example, as I just said, 20 is 1.  1 in binary is, obviously, 1 – which means that if we were to represent the other 31 bits in the integer (assuming a 32-bit integer) with zeroes, we’d have:

00000000000000000000000000000001

23 is 8.  8 in binary is 1000.  So, once again, padding that out with zeroes we have;

00000000000000000000000000001000

Get the picture?  If we look at each ‘1’ in our integer as a separate flag, we can store 32 different flags in a single number!

…and that’s what we do.  Here’s the EntityFlags.cs file.

public class EntityFlags
{
    public static int EQUIPPABLE                 = (int)Mathf.Pow(2, 0);
    public static int CURSED                     = (int)Mathf.Pow(2, 1);
    public static int CORPSE                     = (int)Mathf.Pow(2, 2);
    public static int UNDEAD                     = (int)Mathf.Pow(2, 3);
    public static int NO_DROP                    = (int)Mathf.Pow(2, 4);
    public static int EQUIPPED                   = (int)Mathf.Pow(2, 5);
    public static int TWO_HANDED                 = (int)Mathf.Pow(2, 6);
    public static int CONSUMABLE                 = (int)Mathf.Pow(2, 7);
    public static int REQUIRES_AMMO_ARROWS       = (int)Mathf.Pow(2, 8);
    public static int REQUIRES_AMMO_BOLTS        = (int)Mathf.Pow(2, 9);
    public static int STACKABLE                  = (int)Mathf.Pow(2, 10);
}

Note that I could have done the math myself and simply defined the values as their actual base 10 equivalents (eg. set the value of CURSED to 2), but why bother?  That’s why we have computers.  They don’t make mistakes.

So, how do we set the flags?  Well, remember your boolean functions.  If you OR a 0 with a 1, you get 1.  So if we take a flag variable (such as the flags member of our Entity class) and simply OR it with one of the flag constants, if the flag bit isn’t already flipped, it will be.  For example;

Say our entity.flags variable is currently set to some binary value;

00110001110000000000000000011000

…and we want to set the CORPSE flag (22, or 4 – which is 100 in binary).  If we OR the two variables together (the relevant bits have been bolded)…

00110001110000000000000000011000 - (original number)

00000000000000000000000000000100 - (flag value)

00110001110000000000000000011100 - (result)

See what happened?  The 0’s in the flag’s value didn’t affect the already-set 1’s in the original variable because 0 OR’d with 1 is already 1.  And since the original value had 0 in the relevant position, ORing it with the 1 from the flag flipped the bit to 1.

Sorry to belabor that point but sometimes it takes a while for people to wrap their heads around it.  I know it sure did for me back in the day.

Anyway, now that we can do that, unsetting a flag is just as easy.  We just use an “exclusive OR” instead of the “inclusive OR” that we used to set it.  The exclusive OR only outputs 1 if both bits are different, so if we OR the flag with the variable and that bit is already set, then both elements of the OR are 1, so the resulting bit gets flipped back to 0.

And finally, we can see if a flag is set by ANDing the flag with the variable, since AND only produces a 1 if both bits are the same.  So ANDing the flag will produce a 1 in the flag’s bit position if the flag is set (since both the flag and the bit already at the flag’s position are both 1) and 0’s everywhere else because the 0’s in the flag ANDed with the existing bits in the variable will “clear” all of the other bits; 0 AND 0 are still 0, while 0 AND 1 are also 0.  That means that if the flag had been set, the result of the AND will be a non-zero value (since we’re left with the single flipped bit) and a 0 if it hadn’t (since all the bits have been ANDed to 0).

Clear as mud?  Fortunately, the code to handle these three operations is dead simple to implement. Here are the relevant functions from the Entity class. Naturally, the variable that stores the set flags is called flags.

public void setFlag(int flag)
{
    flags |= flag;
}

public void clearFlag(int flag)
{
    flags ^= flag;
}

public bool hasFlagSet(int flag)
{
    return ((flags & flag) != 0);
}

 

That’s all for today.  Tune in next time for a quick dive into the dungeon’s entity-querying methods and a brief intro to the UI system, which will be necessary to understand the dialog we’re going to build in order to (finally!) pick up items.

-Steve

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

Blog at WordPress.com.