For all Unity developers and developers-to-be, both beginners and professionals!

Post news Report RSS Double Barrelled - Progress Update (Week 11/15)

We are working on NPC interactions and got a few tidbits to share.

Posted by on

Hey Peeps,

Yet another delayed update on our progress is here. Today we will talk about the Chat Bubbles and how we made 'em happen in Unity.

TL;DR;

Before I talk about the really boring stuff let me say a few things about our plans for various kinds of interactions between our hero Blake and whomever it is the player decides to poke with the mouse cursor.
People on Mars are strange, somewhat, so not everyone will want to talk to Blake, those NPCs that don't completely ignore him will behave much like our stunning science officer Dr. Nova Blaze here.

The UI may still change but the general idea will pretty much remain the same. When an NPC is clicked or in some cases approached by the player he or she may say something. At which point a chat bubble will appear over their heads and smoothly follow the speaker should they decide to talk and walk as it were.

Other NPCs may choose to have a more meaningful conversation with the player in which case a dialog UI will appear. Dialogs in DB will be rather simple and will mostly help sell the story to the player. If you have played Diablo III you should have a pretty good idea of what we are talking about here.
Similarly to Diablo the story will be rather linear with very little choice given to the player. This lets us get rid of any dialog branching or other such nonsense making the implementation a lot simpler.
Besides the game is not about dialogs its about kicking and shooting the living crap out of all 'em space aliens.

Last but not least we will have Quests, although in presentation they will not be much different from dialogs there will be a bit more information presented to the player about a possible reward and various completion bonuses.

UNITY DEV STUFF

ALLERGY WARNING : Do not read if you you are allergic to XML!

Now comes the really boring stuff. In the previous update I've talked a bit about the implementation of level randomisation for Double Barrelled. Since this update is all about chat bubbles and conversations I thought I would shed some light on how we put the bubbles thing together.

Managers, files and so on...
In Double Barrelled the game systems are controlled by a number of Managers that at any one point in time can be in a single state aka a Finite State Machine. Each manager is responsible for a certain sub-system like audio, level loading, player input, UI and so on. Conversations, dialogs, quests and whatnot are no different from the other systems of the game so they get their own manager too.


Similarly to the World Chunks manager we load all necessary data for conversations from xmls located in a resources folder. In this case we are only interested in a single resource folder so we set an include filter for that folder.

Levels manager, which is responsible for loading of scenes etc, tells the Conversations manager to load all conversations that match a level name into its cache. This makes loading of conversations a lot faster later on as we no longer have to search the resources for conversation files we need.

HandleEngineHooks.Instance.StartCoroutine(stateLoading.LoadLevelCR(levelName, isDone => 
            {
                // Set state
                SetState(new ManagerLevelsStateIdle());
                                
                // Load conversations for last loaded level
                if(_managerConversations != null)
                {
                    // Conversation files are named to match the level names they should be loaded with.
                    _managerConversations.LoadConversationFile(Application.loadedLevelName);
                }

                if(callback != null)
                { callback(isDone); }
            }));

Speaking of conversation xmls, here is what they look like now


The structure is pretty straight forward, there is a list of Conversations, each Conversation has a list of Lines and each Line has options.
There are bunch of properties on each entity in this xml that we aren't concerned with right now but there a few that are actually important. Text and AudioClipKey properties are pretty self-explanatory but the Options property may seem a bit odd.

You can think of it as a free-for-all dump of whatever parameter or setting you may need when processing this entity in game. In our case the big problem is the bubble size! Why? Well because we are not really interested in writing a UI control that will auto resize based on content.
So we can use the Options bag to store desired size of our bubble. Some of you may think that these options could have been part of the dialog line entity (as an attribute). The reason we didn't want to do it like that is simply because the UI implementation may change, let's say we decided bubbles where a horrible idea, and then you are stuck with a bunch of permanent not to mention useless properties on your Line entity.

UI madness...
So, the player clicks on an NPC at which point the Input manager tells the NPC character script that it's being interacted with. NPC checks its properties to see how it should react.


In our case Nova's Conversation Type is set to Chat so as soon as she is asked by the Input manager to interact with the player Nova's character script sets Conversations manager into a Chat. The Chat state requires a target game object. In this case it will be set to Nova's game object. Now that we have a target we know where to show the bubble and we can also filter out any subsequent chat attempts with the same character while the previous chat bubble is still visible.

On a side note Conversation manager can be only in one state which suits us just fine since we can interact with only one target.

At this point we have everything we need to show the chat bubble and play the audio clip of the voice over.
We have the entity we are interacting with, we know what kind of interaction it should be so all we need now is to get the text and the path to that audio clip.

Chat state makes a call to the Conversations manager and loads a random line for a conversation that is keyed to Nova (as you can see from the xml). The 'oneliners' conversation is a bit different from others since In a dialog or something along those lines we would not load random lines. Instead they would be retrieved according to the Order attribute.

At any rate, having selected a line from the conversation we have the audio clip path which is fed to the Audio manager and we have the text of the one-liner to be shown in the bubble. We also know what width and height the dialog bubble should be.

Now comes the fun part...we show the bubble.

Them bubbles...
Showing the bubble is quite simple really. All we have to do is instantiate a prefab of the bubble from the resources folder and put it in the right position above the NPC's head. To do that we need a dummy prefab to align the bubble with, you can see one floating above Nova's head there


This object is part of Nova's parent game object so it always follows (and rotates with) Nova's character in game. The follow part is great the rotate part not so much.
In order to help us find the dummy object aka Dialog Bubble Anchor we use the Anchors script on our NPC character as you can see in the next image.


The anchors script is a very neat way or organising all the attachment points for your characters. We can mount weapons, gear and so on with relative ease. All we need to do is just access the right property of the Anchors script and we got our mounting point with the rotations and positions all ready and the best part the anchor objects are parented under bones so they get animated with the character.

Now the bubble!


Fascinating ain't it :)

As you can see the bubble graphics are anchored to the bottom of the canvas. This makes resizing work only sideways and up which is exactly what we want. By the way the tail of the bubble is not part of the main image since that is a sliced sprite. So we couldn't stretch it (resize) if it was part of the main graphic.
The text area is anchored to grow with the background so we always have as much text space as we can get in a given bubble size.

And that's all there is to know about the thing, like I said pretty boring stuff. At this point we got everything in place and we have shown the bubble to the player. It's created right above the characters head at the anchor point.

As you can see below the script has a Background property which takes in the graphic for the background sprite. This makes it possible for us to resize the bubble using those options from line entity we talked about a above. Text property takes...surprisingly...the text graphic of the bubble so that we could assign the line text to it.


Now we need it to follow the character if it moves and we want some fancy fade ins and outs for the graphics just to make the whole thing a bit more awesome.

The follow thing is fairly simple stuff. The bubble script has a target property and that is fed to the Smooth Follow script which applies simple easing along the horizontal and vertical axes.

The fading in and out of the whole bubble is achieved by iterating through all of the items in Graphics property and applying a color alpha lerp to them.

private void FadeGraphics(float fadeDuration, float targetAlpha)
	{
		if(Graphics == null || Graphics.Length == 0)
		{ return; }

#if DEBUG
		Debug.LogFormat("DialogBubble.FadeGraphics > Fading to {0} alpha over {1} seconds.", targetAlpha, fadeDuration);
#endif

		foreach(var graphic in Graphics)
		{			
			if(graphic == null)
			{continue;}

			graphic.CrossFadeAlpha(targetAlpha, fadeDuration, false);
		}
	}

And there you have it a dialog bubble gently fades in, plays the audio and fades out. Was a pain in the ass to get the whole thing to work nicely with the rest of the game systems but it turned out quite well in the end :)

In the next update we will show the dialogs in action and talk a bit more about the implementation of a more structured conversation.

PS: I hope there is at least one soul out there that will find this part of the news post interesting :D

We will be back with more soon. Stay tuned.

- Alex

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: