Take your games to the next level with support for a range of accessibility options. Help deal with subtitles, color blindness, audio controls and more!

In this tutorial, you’ll learn some simple strategies to increase the reach of your game by making it user-friendly to people with common disabilities.

Your audience is a diverse bunch of awesome people. Did you know among casual gamers, 20% have disabilities? And that doesn’t even count other conditions that are not registered disabilities, such as red/green color deficiency and conditions that are not long-term or considered substantial.

If you want to target your game for a “typical gamer,” you need to broaden your perspective!

However, this is a good thing. By creating customizable and flexible gaming options, you not only open the door to many players with disabilities, but you also add ‘quality of life’ improvements that all of your players will thank you for.

In this two-part tutorial, you’ll learn how to make accessibility improvements for:

Sight impairment: Flexible fonts, flexible font sizes and adjustments for color deficiency.

Hearing impairment: Closed captions with directional cues.

Motor disability: Movement sensitivity, customizable keybindings, and a button-mashing alternative.

Cognitive disability: Hints and tips.

Other quality of life improvements: Subtitle speed.

Part 1 of the tutorial will focus on making the game easier to play for people with sight or hearing impairments.

In this tutorial, you’ll focus on small changes that make a big impact. These will open your game to a substantial number of players with disabilities.

Many niche audiences would benefit from more involved game mechanic adjustments and assistive technology devices. Although these adaptations are of great value, this tutorial won’t cover these more advanced topics.

If you want to investigate these more advanced adaptations, check out Advanced Game Accessibility Guidelines.

Getting Started

To start this tutorial, you’ll need Unity version 2019.3 or newer. You can install it from Unity.com or by using Unity Hub.

Note: This tutorial requires you to have at least some basic experience with Unity. You’ll need to know how to work within the Unity editor and have a good foundation in C# scripting. Check out our beginner tutorials if you are new to Unity.

OK, ready to go? Download the starter project using the Download Materials button at the top or the bottom of this tutorial and open Improving Accessibility in Unity Games Part 1 Starter with Unity.

Note that the starter project wasn’t created for you to be able to just plug in accessibility features. The aim was to show how you can retrofit these features to an existing game, even when the developer hadn’t considered them.

The folder structure in the Project window looks like this:

Here’s a description of what each folder inside of Assets\RW contains.

3DModels: The 3D models required for this tutorial.

Animations: The animation controllers and their animations.

Audio: The soundFX for the project and an Audio Mixer.

Fonts: A custom font file.

Materials: The materials for the 3D models and the particle effect.

Prefabs: The many prefabs are further divided into the following folders: Building Blocks: The basic building blocks for the environment. Dungeon Interactables: The interactable elements in the environment. Dungeon Pieces: Larger pieces of dungeon assembled from the basic building blocks. UI Prefabs: Reusable UI elements.

Scenes: The dungeon scene.

Scripts: The scripts required for this tutorial.

Standard Assets: The standard character controller used in this project.

TextMesh Pro: A package that you can download to replace Unity’s standard UIText with something with greater utility.

Textures: The textures for UI elements and the textures and normal maps for some of the 3D Models.



www.soundsnap.com

www.textures.com Note: The textures and sound effects used in this tutorial come from these two awesome sites:

OK, it’s time to have a crack at Puzzley Dungeon!

Trying Out Puzzley Dungeon

Navigate to Assets/RW/Scenes and double-click on DungeonScene, if it’s not already open in the editor. Then click the Play button at the top of the editor.

You’ll probably see a few design decisions that will scream poor accessibility choices… Good! Even big game studios are guilty of every issue you’ll remedy in this tutorial.

One final point before you start this tutorial in earnest: Even if you need to compromise on your design, the difficulty of a puzzle or a gameplay mechanic, it’s worth it.

A player with disabilities will thank you for allowing them to enjoy your game rather than hit a frustratingly impassable wall.

Having said this though, you can make your game creative and flexible enough to be challenging for die-hard gamers and still playable for casual players or people with disabilities. The broader the audience that can enjoy your game, the more successful it will be.

Addressing Visual Impairment

Movie and TV subtitles generally follow a universal standard. However, no such standard currently exists for games. Here’s a handy list of considerations to keep in mind while designing your subtitles:

Font size should be large and, ideally, customizable.

Font style should be clear and legible.

The text should be clear against the background colors.

For ease of reading, keep the width of the subtitle area modest.

Keep subtitles short, if possible.

Add something that indicates who’s talking.

Now, it’s time to start making your game more friendly to your whole audience.

Substituting the Subtitles

When you watched the opening scenes of Puzzley Dungeon, did the poor subtitles stand out to you? They were small, moved quickly and had a font that was hard to read. Your first step will be to make those subtitles more accessible.

In the Hierarchy, click the SettingsPanel GameObject under Canvas ▸ Settings Menu.

The SettingsMenu GameObject is disabled by default, so it’s grayed out.

Enable it using the checkbox next to the GameObject’s name in the Inspector. You’ll then be able to visualize your changes in the Scene view. Don’t forget to disable it again before entering play mode, though.

Note: The UI fairy has kindly prebuilt a few UI elements so you don’t have to. If you’d like to know a little more about Unity’s awesome UI system, check out this tutorial: Introduction to Unity UI – Part 1

Under SettingsPanel, find and enable the following GameObjects by enabling their checkbox in the Inspector:

FontStyleSettingComponent

FontSizeSettingComponent

Example Text

The Settings Menu should now contain these three new items:

You’ll use these controls to adjust the style and size of the text in-game. The example text will also reflect the changes, so the player can see how the options they choose will look.

Your next step is to get these controls working.

Adjusting the In-Game Text

While many players find that a fancy, medieval-looking font fits well with a dungeon crawler, others may find that kind of font too difficult to read. So you’re going to offer your players the option of two different font styles: a fancy font and a simple font.

To start, open SettingsManager.cs, located in the Project window under Assets/RW/Scripts.

Once your IDE has loaded the script, add the following variables to the top of the class:

//1 public TMP_FontAsset simpleFont; public TMP_FontAsset fancyFont; //2 public TextMeshProUGUI exampleText; //3 public TMP_FontAsset fontStyleSelected; public float fontSizeSelected;

Here’s what these variables do:

These are references to the font files you can switch between. This provides a reference to the example text, so it can reflect the changes the player makes. You retain public references to the players’ settings, so that newly-instantiated UI objects, such as subtitles, can ask the Settings Manager for the font and size to use.

Return to the Unity editor and find and select the SettingsManager GameObject in the Hierarchy. The Settings Manager component in the Inspector should now be populated with your new public fields.

To add the font files, click the Object Picker Button on the right of the field. This will display all the possible TMP_Font Assets in your project to save you from having to search for them. Handy!

Choose LiberationSans SDF for the Simple Font, and UnifrakturMaguntia-Book SDF for the Fancy Font.

Drag the Example Text GameObject from the Hierarchy to the Example Text in the Settings Manager.

Finally, select the fancy UnifrakturMaguntia-Book SDF for the fontStyleSelected and 36 for the fontSizeSelected.

Here is how the Inspector should look now:

You should use default values with these variables so there’s no chance of them having no value if something tries to access them. A font size of 0 is pretty hard to read even with REALLY good eyesight!

Setting Up Your New UI Elements

The next step is to create the methods that your new UI elements will use. Back in the SettingsManager.cs script, add the following code to the empty SetFontType method. You may need to expand the Adjust Settings region.

//1 switch (dropdownValue) { case 0: exampleText.font = fancyFont; fontStyleSelected = fancyFont; break; case 1: exampleText.font = simpleFont; fontStyleSelected = simpleFont; break; default: exampleText.font = fancyFont; break; }

The drop-down component contains a list of possible options. When the user selects one, it sends an int value to denote which one. Here, you use a switch statement to react to each case appropriately. It applies either the fancy font or the simple font to the example text, and retains a reference to the player’s selection in the public variable, fontStyleSelected .

Next, add the following code to the empty SetSize method:

//1 exampleText.fontSize = sliderValue; fontSizeSelected = sliderValue; SaveSettings("FontSize", sliderValue); //**See Note below**

The slider component sends a float of the value selected. As you did with the font style, you set the font size of the example text and save a reference in fontSizeSelected .

Note: Persisting the data from the Settings Menu is important not only for accessibility reasons, but also to avoid annoying all your players. Saving and loading throughout the tutorial would add a considerable amount of repetitive code. Therefore, you’ll see an example of Loading Saved Settings in Part 2 of this tutorial series when the Settings Menu is complete. Until then, expect each control to have a line of code to save the newly-adjusted setting.

The UI components are already wired up to the methods you just completed. Once again, have a look at the tutorial here if that process is unfamiliar to you.

Back in Unity, it’s time to test things out. Don’t forget to disable the SettingsMenu GameObject again, then click the Play button to check that everything works well so far.

Work that slider! Toggle that font! Looking good?

Your next task is to implement the changes across the game when you exit the Settings Menu.

Adding Your Font Changes to the Game’s Menus

You have two types of UI that you need to tackle: The couple of game menus that persist in the scene, albeit hidden, and the subtitles that the game generates on the fly.

You’ll start with the menus.

Add and instantiate the following lists to the top of the SettingsManager script.

public List<GameObject> gameUIPanels = new List<GameObject>(); private List<TextMeshProUGUI> gameUITextComponents = new List<TextMeshProUGUI>(); private List<Button> gameUIButtonComponents = new List<Button>();

The public gameUIPanels list will allow you to simply drag all the panels you want to affect into the list in the Inspector.

At the start of the game, the text and buttons will be extracted from the gameUIPanels and added to their own lists. This means the Settings Manager won’t have to find them every time something changes.

Add the following code to Start in the SettingsManager to populate the two private variables, gameUITextComponents and gameUIButtonComponents :

foreach (GameObject panel in gameUIPanels) { TextMeshProUGUI[] tempArray = panel.GetComponentsInChildren<TextMeshProUGUI>(); foreach (TextMeshProUGUI item in tempArray) { gameUITextComponents.Add(item); } Button[] tempButtonArray = panel.GetComponentsInChildren<Button>(); foreach (Button button in tempButtonArray) { gameUIButtonComponents.Add(button); } }

Here, you iterate through the list of GameObjects looking for any TextMeshPro components in the object or any of its children. If the code finds any, it adds them to the gameUITextComponents list. Similarly, Button components are added to the gameUIButtonComponents list.

Once the player has completed the adjustments to the font and clicked the Exit button in the Settings Menu, you want to pass those changes to all the elements you’ve collected.

Add the following code to the start of SettingsDidExitOrLoad .

//1 foreach (TextMeshProUGUI textComponent in gameUITextComponents) { textComponent.font = fontStyleSelected; textComponent.fontSize = fontSizeSelected; } //2 foreach (Button button in gameUIButtonComponents) { button.image.rectTransform.sizeDelta = new Vector2((fontSizeSelected / 32) * 200, (fontSizeSelected / 32) * 50); }

Here, you iterate through the gameUITextComponent list and set the fonts to the size and style the user selected. Then you expand or reduce the size of the buttons in the gameUIButtonComponents to match the font size the user selected.

Return to Unity and add the UI elements you want to include in the gameUIPanels list.

In the Hierarchy, make sure you’ve toggled the disclosure triangle so that the child GameObjects are visible in Canvas. Select the Settings Manager and drag the following four GameObjects from the Canvas into the Game UI Panels List:

InventoryMenuSettingsButton

StartMenu

EndMenu

DoneButton (found in the Settings Menu)

Before you click Play to see if all your hard work has paid off, go ahead and take care of the subtitles, too. All you need is a little script.

Changing the Font Styles in the Subtitles

In the Project view, navigate to Assets/RW/Prefabs/UIPrefabs/SubtitlePrefab.

The subtitle prefab is very basic. It’s simply a text element with a Destroy Timer script to remove it after a set time. The game manager instantiates one when it needs one, populates the text and slaps it in a panel with a vertical layout group.

Double-click on the SubtitlePrefab to open it. In the Inspector, click Add Component and type SubtitleManager. Press Return and then Create and Add. You now have a nice, new script to manage your subtitles!

Move the new script into Assets/RW/Scripts (you’ll find it by default created under Assets). Then double-click on it to edit it and add the following at the top of the script:

using TMPro;

This lets you access TextMeshPro in the namespace.

Next, add these two private variables at the top of the class:

private SettingsManager settingsManager; private TextMeshProUGUI myTMPComponent;

These reference the Settings Manager to extract the player’s font preferences and the TextMeshProUGUI text component so you can apply adjustments.

Add the following code to Start to make these adjustments.

//1 settingsManager = GameObject.FindGameObjectWithTag("SettingsManager").GetComponent<SettingsManager>(); myTMPComponent = gameObject.GetComponent<TextMeshProUGUI>(); //2 myTMPComponent.font = settingsManager.fontStyleSelected; myTMPComponent.fontSize = settingsManager.fontSizeSelected;

Wires up the variables you created in the previous step to their respective objects. Takes the font style and size from the Settings Manager and applies them to the subtitle.

Save the script and return to Unity to test it out. Press the Play button. Don’t forget to change the font to Simple in the Settings menu of the running game before you click Start Game.

For all those who were wondering what a “Gold Teh” was, there will be a few “ohhh” and “ahhh” moments now that you can read some of the subtitles. :]

Adding an Outline to the Subtitles

For this game, the subtitle color works well against the deep dark dungeon environment. However, making your subtitles stand out is so simple, it doesn’t make sense not to do it.

To get started, double-click on the SubtitlePrefab in Assets/RW/Prefabs/UIPrefabs to open it in the Hierarchy and Inspector.

Scroll down to the Material component and expand it using the disclosure triangle. Click on Underlay to expand it.

If you ticked Underlay and tweaked the settings, you’d create a nice outline around your text.

However, this would also affect all instances of this font throughout the game, as they share the same default material.

Setting Up a Separate Material for the Subtitles

To fix this, right-click at the top of the Material component and select Create Material Preset.

The Project view should jump to the new duplicate material named UnifrakturMaguntia-Book SDF. Select it in the Project view and append “Outline” to its name to distinguish it from its twin.

In the Inspector, check Underlay and adjust the following settings:

Color: Set the alpha to 255 to make the black opaque.

Offset X: Set to 0.

Offset Y: Set to 0.

Dilate: Set this value to 1.

Awesome! That will make your fancy styled text in-game stand out against all backgrounds.

Standardizing Your Outlines

The simple font already has a few Material Presets. Navigate to Assets/RW/TextMesh Pro/Resources/Fonts & Materials. Here, you’ll find an Outline Material already, LiberationSans SDF – Outline.

However, this material uses an Outline as opposed to an Underlay to create the outline. For clarity and consistency, your next step is to adjust the material to use an Underlay instead.

Uncheck Outline and check Underlay instead. Apply the same settings as with the fancy font.

Implementing the Outlines

To override the default material, you’ll need to set the material preset when you instantiate the subtitle. To do that, add the following two variables to the SubtitleManager:

public Material outlineSimpleFontMaterial; public Material outlineFancyFontMaterial;

These variables will hold your new outline materials. Next, add the following code to the end of Start :

switch (settingsManager.fontStyleSelected.name) { case "LiberationSans SDF": myTMPComponent.fontMaterial = outlineSimpleFontMaterial; break; case "UnifrakturMaguntia - Book SDF": myTMPComponent.fontMaterial = outlineFancyFontMaterial; break; default: myTMPComponent.fontMaterial = outlineFancyFontMaterial; break; }

This switch statement sets the outline font material for the font that the user selected.

Now, return to Unity to populate the public variables.

Note: Remember, you can click on the little circle connectors to pull up a list of available materials in your project.

Make sure you save the prefab.

Click the Play button and marvel at the clarity of the subtitles, regardless of background shenanigans!

Congratulations! You have improved the game tremendously already for people with vision impairment.

Adaptations for Color Vision Impairment

Color blindness is a fairly common condition. Red-green is the most common form, affecting approximately 8% of males and 0.5% of females. This is a problem for players since many games use color a great deal. For example, colors might help users find the solution to puzzles or to indicate status or progress in the UI.

Note: You can experience how a person with color blindness sees things, even if you don’t have the condition yourself. For example, Colour Blind Awareness is a site where you can visualize images as someone with colorblindness does. Additionally, it offers links to sites that will allow you to upload your own images to visualize, which is useful for testing your game’s color palettes.

Making a Color-Based Puzzle More Accessible

Puzzley Dungeon has a color-based puzzle, where the player needs to place different color gems on their respective pedestals.

There are many ways you could adjust this puzzle to assist individuals with color blindness. For example, the shapes of the gems could be different or you could emblazon archaic symbols on the gems and pedestals to indicate correct pairings.

For this tutorial, you’re going to show a change in the gems’ material emission to indicate the correct placement. After all, if you don’t have powerful glowing gems in your dungeon crawler, you are doing something wrong! :]

Open the InteractablePart script found in Assets/RW/Scripts. This class handles puzzles with more than one component, such as the gem puzzle, where a few things need to happen correctly before the user can successfully finish the puzzle.

You call OnTriggerEnter when part of a puzzle needs to react to a change. Within this method, you differentiate between puzzles where the order of events is important, such as playing musical notes or pushing buttons in the correct order, versus puzzles where order is not important, like with your gem game, where the player can place the gems in any order.

Correct placement of a gem will bring you into this nested conditional:

if (!isSequenceImportant) { myMasterInteractable.playerGuess[partNumber] = 1; myMasterInteractable.Interaction(); }

Putting Your Requirements to Work

Each puzzle has a requirement. For example, the WoodenDoorwayKeyhole requires a GoldKey to open it. In this next step, you’ll use the Gem requirement to ensure that the material change only affects your completed gem puzzle.

Under myMasterInteractable.Interaction(); , in the same curly braces, add the following code:

if (requirement.Contains("Gem")) { Material gemMaterial = other.gameObject.GetComponentInChildren<Renderer>().material; StartCoroutine(LerpEmission(0.0f, 1.0f, gemMaterial)); }

You’ll get an error because you haven’t created the method you’re trying to access… yet. Your next step will be to fix that. Add the new method below, in the same script:

private IEnumerator LerpEmission(float startValue, float targetValue, Material gemMaterial) { float progress = 0; while (progress <= 1) { float emission = Mathf.Lerp(startValue, targetValue, progress); gemMaterial.SetColor("_EmissionColor", gemMaterial.color * emission); gemMaterial.EnableKeyword("_EMISSION"); progress += Time.deltaTime; yield return null; } }

This method uses a Mathf function called Lerp . It gradually adjusts a value from one to another over time. Here, you'll use it to adjust the emission color of the gem, but you can use it in many other useful ways! Keep it in mind.

Back in Unity, press the Play button and test out your new, super-powerful gems.

Yeah! This is starting to feel more like a proper dungeon crawler. As you can now see, putting the correct gem down on the correct pedestal, results in the color emission brightness significantly increasing.

Addressing Hearing Impairments

When you design your games to assist players with hearing impairments, you're also making quality-of-life changes that all your players will thank you for. More players than you think will take advantage of these improvements.

Ubisoft has stated that 60% of Assassins Creed players play with the subtitles turned on. Additionally, think of the many times you've played your mobile games without volume because of others around you. Fortnight added a directional cue to sounds for mobile users for this reason. These changes level the playing field for all players, since sound is such an important aspect of the multiplayer survival game.

In this section, you'll implement the following:

Closed captions.

Directional cues for all sounds.

Separate FX/music volume controls.

Game design thoughts for sound-based puzzles.

Adding Closed Captions

Now that you have readable subtitles, you also want to make sounds easier to detect, even for people with hearing disabilities. You'll do that by adding closed captions.

First, enable a new toggle on your settings screen. Select AudioDescriptionToggleComponent in the Settings panel in the Hierarchy, under Canvas ▸ SettingsMenu. At the top of the Inspector, enable the toggle with the checkbox.

Your Settings panel should look like this:

OK, now head back into the SettingsManager script to complete the method the toggle hooks into.

First, add an instance variable at the top of the class to hold the state of the toggle:

private bool audioDescriptionEnabled = false;

This variable doesn't need to be public because the Settings Manager itself will handle sending the subtitles.

Next, find the empty ToggleAudioDescription method and add the following code:

audioDescriptionEnabled = isDescriptionEnabled; SaveSettings("DescriptionEnabled", isDescriptionEnabled.ToString());

The setting from the toggle is simply passed to the variable in the Settings Manager for all to access!

Now save the script and pat yourself on the back, you did great. :]

Adding Scripts to Noisy GameObjects

Next up, you're going to create a new script that you'll add to all GameObjects that have an audio source. The script will watch the state of its own audio source and if played, will send a subtitle of your choice to the Game Manager.

Note: You can easily implement the changes that you are making to this starter project in any other projects you create. You can even go back and make these changes retroactively. Just search for Audio Sources in the Hierarchy, drop this script on them, and they'll instantly start reporting their activity.

Navigate to Assets/RW/Scripts. At the top left of the Project view, click Create ► C# Script to create a new script. Name this script AudioDescription and double-click on it to begin editing. Finally, add the following variables to the top of the class:

private SettingsManager settingsManager; private AudioSource myAudioSource; public string myDescription; public bool descriptionSent = false;

The names of these variables should be self-explanatory. Here's what they do, in order:

settingsManager: Holds a reference to the Settings Manager so that it can request a subtitle. myAudioSource: Holds a reference to the Audio Source attached to the GameObject so you can check if it's playing. myDescription: Enables you to add a string to a report, such as: "Sound of torch crackling." descriptionSent: Ensures a subtitle is only sent once during the playback of the sound, and not for every frame.

Now add the following code to the Start to instantiate your private variables:

settingsManager = GameObject.FindGameObjectWithTag("SettingsManager").GetComponent<SettingsManager>(); myAudioSource = gameObject.GetComponent<AudioSource>();

Next, add the following code to Update . This is where the magic happens!

if (myAudioSource.isPlaying && descriptionSent == false) { settingsManager.HandleAudioDescription(myDescription); descriptionSent = true; StartCoroutine(ResetReportingDescription(myAudioSource.clip.length)); }

Here, Update checks to see if the Audio Source is playing, and whether a description for the audio has already been sent. This only happens for the first frame, when the audio starts playing.

Then, three more things happen:

A description of the audio is sent to the method called HandleAudioDescription in the Settings Manager. descriptionSent is set to true . Finally, you initiate a coroutine to reset descriptionSent once the audio ends by passing in the length of the audio clip.

The eagle-eyed among you may have noticed neither of these methods exists yet. It's time to fix that!

Add the following new method to the AudioDescription script:

private IEnumerator ResetReportingDescription(float clipLength) { yield return new WaitForSeconds(clipLength + 0.1f); descriptionSent = false; }

This first line does exactly what its name indicates. WaitForSeconds pauses execution of the method for the time you specify: The length of the clip plus a precautionary extra fraction of a second. Once that time has elapsed, the descriptionSent is set to false so that the subtitle will send again the next time the audio plays.

Next, head into the SettingsManager.cs script and add the following new method:

public void HandleAudioDescription(string subtitle) { if (!audioDescriptionEnabled) { return; } else { gameManager.PublishSubtitle(subtitle); } }

Save all changes to your scripts.

Attaching the Descriptions to the Audio Sources

Return to Unity and type AudioSource into the search bar at the top of Hierarchy.

This should reveal several GameObjects in the scene with AudioSource components attached. Adding the AudioDescription will be simple for most of these objects, but you need to be a little careful to ensure you don't get unwanted duplicates and that you pass changes to prefabs and prefab variants correctly.

Hold down Control, or Command on Mac, and select the following: BlueGem, ColumnTorch (just one of them), GateDoorway1, GoldKey, PressurePlate (E) and StartDoorway.

In the Inspector, click Add Component, type AudioDescription and click Add.

You only add the AudioDescription component to one ColumnTorch; otherwise, you'll get a duplicate subtitle if both report the audio. You don't add a description to Inventory, because you already receive a subtitle when you pick up an item, so an audio cue is unnecessary.

Each of these items needs to have an appropriate message to send. In the Inspector, populate the MyDescription in the Audio Description components with an appropriate subtitle. Here's a list you can use if you aren't feeling particularly creative:

BlueGem: Gem clinks.

ColumnTorch: Fire crackling.

GateDoorway1: The ancient mechanism grinds and clanks.

GoldKey: Metal clanks.

PressurePlate (E): The musical note E.

StartDoorway: The ancient mechanism grinds and clanks.

Next, you'll need to make sure the changes pass to the prefabs and prefab variants.

With the exception of the ColumnTorch, select each of these items in the Hierarchy. At the top of the InspectorOverrides drop-down and select Apply All.

There's one final change to make: While all the gems clink the same, the pressure plates need to report different sounds. Individually select PressurePlates A, B, F and G, and change the notes in the subtitle to their respective letter.

Done! Great work!

Back in Unity, click Play, make sure you enable Audio Description in the Settings menu and play through the level. Try kicking some gems, dropping some keys and so on.

Adding Directional Closed Captions

Closed captions in movies and TV generally report on the sounds and music in the scene only. In a game, however, the direction of the sounds can be very important. Knowing there's a moaning zombie, or a moaning zombie RIGHT BEHIND YOU, makes a big difference in whether you live or die!

Your next task is to add some additional code to report the direction and distance of the sounds in the subtitle, as well.

Adding Subtitles to Sounds

Head back into the AudioDescription script and add one tiny change. Within Update ´, change the following line:

settingsManager.HandleAudioDescription(myDescription);

To this line:

settingsManager.HandleAudioDescription(myDescription, gameObject);

When an object somewhere in the scene plays its audio, it will now send a subtitle to the SettingsManager and a reference to the GameObject itself.

Return to SettingsManager so that you can adjust HandleAudioDescription to take advantage of this.

First, add the new GameObject argument to the method:

public void HandleAudioDescription(string subtitle, GameObject origin)

Determining Where the Sound Is

Secondly, what use is a reference to the source of the audio if SettingsManager does not know where the player is? To fix this problem, add this new variable at the top of the class:

private GameObject player;

And wire it up in Start by adding this line of code:

player = GameObject.FindGameObjectWithTag("Player");

To calculate the distance and the direction from the player that a sound comes from, you need to do some calculations. This diagram shows you the theory behind the calculations:

To put that theory into practice, go to the HandleAudioDescription method and replace this line:

gameManager.PublishSubtitle(subtitle);

With this monster:

//1 var heading = origin.transform.position - player.transform.position; //2 var distance = heading.magnitude; if (distance <= 5.0) { subtitle = subtitle + " (close "; } else if (distance >= 15) { subtitle = subtitle + " (far "; } else if (distance >= 20) { return; } else { subtitle = subtitle + " ("; } //3 Quaternion rotation = Quaternion.LookRotation(heading, Vector3.up); Vector3 angles = rotation.eulerAngles; //4 // Adjust for the rotation of the player var direction = player.transform.eulerAngles.y - angles.y; if (direction >= -45 && direction <= 45) { subtitle = subtitle + "infront of you)"; } else if (direction > 135 || direction < -135) { subtitle = subtitle + "behind you)"; } else if (direction < -45 && direction >= -135) { subtitle = subtitle + "to your right)"; } else if (direction > 45 && direction <= 135) { subtitle = subtitle + "to your left)"; } gameManager.PublishSubtitle(subtitle);

Here's what this code does:

By subtracting the position of the origin of the sound from the player's position, you get a vector representation of the heading. The magnitude, or length, of this vector will give you the distance of sound from the player. Use the distance value to determine whether the sound is close to or far from the player and add that info to the subtitle. LookRotation converts that heading vector into a rotation from the player to the source of the sound. You then convert this value into an angle. Angle is a bearing in 3D space from the player's location, so you also need to take the player's rotation into account. You subtract the player's from the angle to give you a direction that you can use to describe the location of the sound. You then add this information to the subtitle.

Wow, that was super simple!

Press Play in Unity and do some noisy stuff to see the results of your hard work!

This is a simple implementation of directional audio cues. But with the math you worked out above, you can create all sorts of interesting on-screen notifications.

For example, have a look at Fortnight. A simple compass-like ring intuitively uses icons and color to show what sounds your character hears, where they come from and how close they are.

Volume Controls

Another important consideration for players with hearing difficulties is control over the volume. Giving players control of both music and FX volume can help separate important audio cues, effects or speech from background music.

There's no music in your simple game, but the principle will be the same. You'll attach one of the AudioSources to its own channel to independently adjust its volume. You'll use the torch for this example, as it could use a volume boost. You could also adjust the terrifying and loud door/gate opening sound if you prefer.

First, in the Project view, click on the AudioMixer in Assets/RW/Audio. Open the Audio Mixer window by selecting Window ► Audio ► Audio Mixer from the toolbar.

You'll need to add a new mixer group and expose a parameter to allow you to access its volume by script. Here's how you'll do it:

Select the AudioMixer under Mixers. Then select the Master Group in the Groups list on the left. Click the Plus button to add a child group to the list. Rename it Torch. Creating the child group should select it, which exposes some settings in the Inspector. In the Attenuation section, right-click on Volume and select Expose 'Volume (of Torch)' to script. The exposed parameters should appear in a drop-down on the top-right of the Audio Mixer window. Click on the drop-down to find your new exposed parameter, which is intuitively named MyExposedParam. Click on it to rename it to something even more intuitive, such as TorchVolume.

As you've done previously, navigate to the SettingsPanel in the Hierarchy under Canvas ► SettingsMenu ► SettingsPanel to activate a new control.

Find and select TorchVolumeSettingComponent and enable it in the Inspector.

Now, open the SettingsManager.cs script and add the following code to the empty SetTorchLevel method.

mixer.SetFloat("TorchVolume", Mathf.Log10(sliderValue) * 20); SaveSettings("TorchVolume", sliderValue);

The volume in the mixer is logarithmic, not linear. Therefore, Mathf.Log10 will ensure a smooth increase or decrease of the volume when the player adjusts the slider.

The final step is to tell the torch to use the new mixer you created. Find the two ColumnTorch objects in the Hierarchy. The search bar will help with this.

Next, select both objects and find the AudioSource in the Inspector. One of the parameters, Output, routes the sound through the selected audio mixer ground. Click the selection circle and select Torch in the presented list.

Click Play in Unity to enter play mode. You should now be able to adjust the volume of the FX independently to the sound of the torch's crackling fire... ahh!

Audio Puzzle Considerations

In this tutorial, you created closed captions and added further detail to indicate the direction and distance of the sound. Additionally, you tinkered with Unity's Audio Mixer to see how you can bring more important sounds to the foreground.

The final puzzle in Puzzley Dungeon relies on hearing the notes of the tiles. This is an example of a puzzle that would be a considerable problem for someone with hearing impairment. You solved this issue using the closed captions, but there are several alternative design changes that you could have used to remedy this.

For example, you could change the notations carved on the wall into numbers. Alternatively, you could have your player match symbols on the gems with symbols on the tiles.

There's more than one way to design for disability. Find the one that doesn't feel out of place or break the immersion of the game. Sometimes, you may just need to get creative.

Where to Go From Here?

Congratulations on completing Part 1 of this two-part tutorial!

You can download the completed Part 1 project using the Download Materials button at the top or bottom of this tutorial.

In this part, you worked through improvements concerning sight and hearing impairment. You took the game's subtitles to the next level with adjustable sizes, fonts, and closed captions. You also addressed complications regarding color and sound in the puzzles and boosted your audio with independent control of different sound FX.

In Part 2 of this series, you'll learn about further improvements for players with motor- and cognitive disabilities. You'll learn about adjusting keybindings, control sensitivity and keyboard navigation. You'll also implement a clue system and other quality-of-life changes.

If you have any questions or comments, please leave them below. See you in Part 2!