Improving Accessibility in Unity Games – Part 2
In Part 2 of Improving Accessibility in Unity games, you’ll add support for motor and cognitive disabilities and add some options to help guide players. By Mark Placzek.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Improving Accessibility in Unity Games – Part 2
50 mins
- Addressing Motor Disability in Unity Games
- Being Sensitive to Sensitivity
- Enabling the Sensitivity Adjustments
- Adding Rebindable Keys
- Setting Up Your UI Controls
- Testing Your New Settings Window
- Rebinding Your Inventory Controls
- Adding the Rebind Logic
- Finishing Up
- Applying the Rebinding
- Keyboard Navigation
- Fixing Navigation in Other Panels
- Coding the Selection for Each Menu
- Beating Button Mashing
- Preparing CrosshairRay for a Mouse Hold
- Addressing Cognitive Disabilities
- Adding Clues
- Setting Up Your Trigger
- More Fun With Subtitles
- Adding Colors to the Subtitles
- Highlighting Interactables
- Animating Your Interactive Hints
- Switching Between the Regular and Animated Cursor
- Adjusting Your Subtitle Duration
- Making a Slider to Adjust the Subtitle Duration
- Saving the Settings
- Creating a Save Method
- Saving Your Player Settings
- Where to Go From Here?
Beating Button Mashing
Oftentimes, games require that their players mash buttons repetitively to achieve a goal or to overpower an enemy. However, many find this tiresome or difficult to maintain, and some people with motor difficulties find it impossible.
Puzzley Dungeon uses this mechanic for its rusted gate lever. To make it more accessible, you’re going to build an alternative: a sustained hold of the button.
In the previous section, you enabled ButtonHoldToggleComponent in the SettingsPanel. Now you’ll use this as a toggle to enable the alternative setting.
Open the SettingsManager.cs script and complete the ToggleHoldButton
method, which connects to the toggle.
crosshairRay.isHoldButtonEnabled = isHoldEnabled;
SaveSettings("HoldEnabled", isHoldEnabled.ToString());
What’s crosshairRay
?
Imagine that there’s an invisible line from your player into the 3D world in front of it, called a Raycast. This lets you determine if you are facing something and whether you are close enough to interact with it.
If you are, you can execute appropriate methods to do stuff with the object. The crosshair on the screen is a visual representation of where this ray points.
Preparing CrosshairRay for a Mouse Hold
The crosshairRay
sits between a mouse click and a possible interaction. Unity treats a mouse click and a hold differently, so crosshairRay
needs to know to look out for a hold, if that’s the method the player will use.
Add the following variable to the top of SettingsManager.cs.
public CrosshairRay crosshairRay;
Now, head back into Unity. In the Hierarchy, find and click on the MainCamera child in RigidBodyFPSController.
In the Inspector, find the Crosshair Ray component and open it for editing in your IDE. Then add the following variable to the top of the class:
public bool isHoldButtonEnabled;
Update
is highly commented, have a read through to better understand the flow of logic, but the gist of it is that it is used to determine what kind of interactable objects are being clicked on in-game, if any. If an interactable object is clicked on, then the interaction is executed in code.
With the hold, you have a new scenario to work into the method. Under the comment labeled 2
, change the following line from this:
else if (Input.GetButtonDown("Fire1") && isInteractableHit)
To this:
else if (!isHoldButtonEnabled && Input.GetButtonDown("Fire1") && isInteractableHit)
This ensures that if the player hasn’t enabled the button hold, the game works as it did before.
Under this else if
statement, add the following new else if
statements to add a new, third scenario:
// 3 If the player has enabled the button hold and the character is in range of a "strength" interactable,
// rather than use GetButtonDown, which is only true for the first frame,
// you use GetButton, which will remain true for the entire time the player holds the button.
else if (isHoldButtonEnabled
&& isInteractableHit
&& currentInteractable.interactableType
== InteractableScript.InteractableType.strengthInteractable
&& Input.GetButton("Fire1"))
{
currentInteractable.Interaction();
}
else if (isHoldButtonEnabled
&& isInteractableHit
&& currentInteractable.interactableType
!= InteractableScript.InteractableType.strengthInteractable
&& Input.GetButtonDown("Fire1"))
{
currentInteractable.Interaction();
}
There are a few different types of interactable in the game. strengthInteractable
is the one you need for sustained button presses or a sustained hold.
The first else if
statement ensures a strengthInteractable
keeps receiving a message for the duration of a button hold by using GetButton
as opposed to GetButtonDown
. The second else if
ensures other interactables still only receive a single message.
For the final step, return to Unity and wire everything up.
Select SettingsManager in the Hierarchy. Drag the MainCamera from the Hierarchy under RigidBodyFPSController to the Crosshair Ray field in the Inspector.
OK, click Play, toggle ‘Enable button hold’ in the Settings Menu and go to that rusted door lever. Ha! No amount of rust can slow you down anymore!
Addressing Cognitive Disabilities
Your audience is broad, and no matter how you’ve targeted your game, people with a diverse range of ages and abilities will play it. Adjustable difficulty and balancing can help people young and old and of all levels of ability to enjoy your game.
It may be difficult to balance the desire to challenge your players with the need to let more people play. But there are many ways to incorporate adjustments that consider everyone’s needs. For example:
- You keep the main story more accessible but add side quests for players that like an extra challenge.
- Offer an optional hint system. The Room series by Fireproof Games is a good example.
- Use Unity Analytics and funnels to identify sticking points and adjust the level design to ensure an enjoyable, challenging but not impossible playthrough. For more detail about Unity Analytics, have a look here.
For now, you’ll make a few adjustments to your simple game. You’ll add a clue system that can offer hints when you enter a new room and you’ll make a few quality-of-life changes.
Adding Clues
You already created a system to provide information to the player via subtitles. In this section, you’ll use that system to add hints.
In the Hierarchy, use the Create drop-down at the top to select Create Empty and add a new, empty GameObject to the Scene. Drag it into SceneObjects to keep your scene organized and select it so you can make some adjustments in the Inspector.
Adjust the objects Transform/Position to (X:40.5, Y:2, Z:-34) and rename it HintTriggerZone. Next, you’ll add a CapsuleCollider with the Add Component button. Adjust the Radius to 2 and, if you don’t want the player walking straight into an invisible wall, tick the Is Trigger property.
This should place a trigger zone just on the inside of the gate to the room with the plinths.
Here is how it should look like from above (using Wireframe view in the Scene window).
This is how it looks from a different perspective in the Scene view.
Next, you’ll add some logic to your trigger.
Setting Up Your Trigger
Click Add Component a second time and type SubtitleTriggerScript. Press Enter followed by Create and Add to create a new script.
Move the script from the root of your Project Assets folder into Assets ► RW ► Scripts.
Now, open it and add the following variables to the top of the class:
private GameManager gameManager;
private bool clueWasTriggered = false;
public string clueText;
The first variable grants access to the GameManager so that you can post a subtitle. The clueWasTriggered
Boolean ensures the subtitle isn’t continuously triggered. The third variable, clueText
, enables you to add an appropriate hint from the Inspector.
Now, add the following code to Start
:
gameManager = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameManager>();
This stores a reference to the GameManager.
Finally, add this OnTriggerEnter
method:
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player" && !clueWasTriggered)
{
gameManager.PublishSubtitle(clueText);
clueWasTriggered = true;
}
}
This method will send the clue subtitle when the player enters the trigger area. You then set clueWasTriggered
to true
to ensure you do not send multiple clues each time the player wanders through the trigger zone.
Head back into Unity and add an appropriate subtitle to the public clueText
variable in the Inspector:
“A gate with no lock? Perhaps closer inspection of the plinths will yield a clue.”
Click Play and try it out. Perhaps now, you’ll finally conquer this fiendish puzzle!