How to Make a Game for Blind Players?!




Hey there everyone! Today I wanted to write a little bit about the experience of writing the demo for The Castle, a narrative-driven microgame collection about a schizophrenic ending up in a mental asylum.
Design
Before working on the game, I thought a lot about how I wanted to design the game. It was important for me to know the workflow of the main game loop before getting too much into the game. This way I would know how everything would fit together and not get caught in any bad design traps - I’ve learned my lesson from the past.
To design this project, I wanted to make it so that everything runs off a UI system. This UI uses a data structure called a “stack”, that acts like stacking blocks - you put something on the top when you want to add to it, and if you want to take away from it, you take from the item on the top. This way, the stack can function like a stack of Windows, and I always have control over which Window receives and processes input.
With that, I can design three important parts of the game:
- A menu system, that allows me to go through menus such as options, credits, and textboxes.
- A cutscene system, which is a unique UI element that can create new UI elements by processing a script written in JSON.
- A game manager, which is a special UI element triggered by the cutscene system to produce a bunch of microgames for the player to play.
So as you can see, I have to first build the menu system, then the cutscene system, then the game manager. All that work before I can even make any microgames!
First Round of Accessibility
Since I would be designing the UI manager first, and likewise all the basic menus such as the title screen, options menu and credits menu, I needed to make sure that my menus had some base level accessibility.
First, I installed my Godot-Screenreader plugin for Godot 4.3. Future versions of Godot are being integrated with AccessKit, a cross-platform screenreader compatibility library, but I’m not familiar enough with Rust to do the dirty work. Instead, this screenreader is a fully functional tool within the Godot engine that navigates the UI elements. In addition, I made sure NVDA support was provided with godot-nvda-integration - however, I have not gotten around to adding Mac support yet! If the game detects NVDA is active, it will read through NVDA, using all of the custom settings that the user has configured. Neat.
However, I had to make quite a bit of modifications to the screenreader. First, there were some bugs, but also to support the game more fluidly, I had to make many minor edits to the screenreader classes to support integration into the way I designed my game. This gave me a good opportunity to see how godot-screenreader functions in an actual project. Beyond the minor initial bugs, it actually works very well most of the time.
To use it, when a UI is opened or updated, a special function called AXController.set_dom_root()
is called. This function updates the screenreader’s internal map of the UI elements to be navigated. The root node is used to recursively search for all compatible nodes, and its organization can be controlled with special scripts attached to the nodes. To clear the screenreader’s map, such as when there are transitions or other times that you shouldn’t navigate at all, you can set the root to null. It’s very easy, although a few timing bugs caused some issues when integrating some more complicated UI elements.
This means I will have to make a lot of careful modifications from the changes I made for The Castle to merge back with godot-screenreader, but these improvements will help extend the functionality of godot-screenreader and improve its usability.
Some additional blind accessibility features were implemented in this stage as well. For example, I added a magnifier that can be enabled in the Options menu, however it is in a prototype stage that I’ve only tested with static UI elements and not the microgames. I added an audio bus for accessibility-only sound effects. These are turned off by default, but enabled by the default screenreader settings when you first enable the screenreader. An important feature with a large curb-cut effect is to include volume ranges for sound effects, music and other sounds through the game. I also added a slider for the typewriter sound in textboxes specifically since they may mask screenreader speech. Another minor but useful feature is the ability to adjust the pitch of sound effects - some hard of hearing people have specific ranges they are more in-tune to hear, so this can allow for some minor adjustment. Finally, I implemented a sound panning feature to allow sounds to be concentrated in the left or right ear.
I also included some accessibility features for people with other disabilities. This includes reduced animation, hiding the “voices” that can be distracting to some players, and audio descriptions of sound effects.Some accessibility features I was not able to implement in time include keybinded controls and a feature to transform positional sound panning into pitch for certain kinds of hearing impaired disabilities. Since this game was not strictly an audio game, I ensured that every game was able to be completed either with no graphics or with no sound.
Cutscene Processor
One I felt confident in the UI system and the menus, it was time to design the cutscene processor. Since this game is like a combination of a visual novel and a microgame collection, it makes sense that everything can just run on a cutscene. What the cutscene does is it processes an array of commands until it reaches the end, and when there are no more commands, it will cut to the title. It will read commands and execute them with arguments to produce the narrative components of the game. These cutscenes can support a bunch of cool features, such as changing backgrounds, displaying sprites, textboxes or starting a series of games, and it is all controlled through JSON, reading off an array of commands.
It’s really nice. New commands can be easily added. There is a function for each command that processes the arguments independently, making it trivial to add new functionality. There were a few times where I realized that I didn’t quite have the command I needed. No big deal - just add a new one!
Microgame Madness
Now for the fun part - or so I thought - the microgames! For some reason, I decided to start with “Defeat the Monster”, which is a parody of Pokemon. Fun fact! The sprites come from an infamous ROM hack I made as a teenager, called “Pokemon Jupiter Version”. Maybe you’ve heard of it? I feel sorry for you if you did.
Anyways, building the microgames was tricky. I needed to build a few things first.
- A game manager, which accumulates the score between microgames, and loads microgames in quick succession until the victory criteria is met.
- A game template, which has all the expected default behaviors of a microgame, such as displaying its name, tutorial, opening animations and calculating end game behavior.
- The games themselves…
This was a point of the game I had not planned very well. Big mistake - I had to refactor my code many times to make things quite work. For one thing, I needed to use SubViewports to make the Gameboy palette shader work through the whole game. This was problematic, since I didn’t realize that this interferes with some ways that Godot interacts with focus, audio, etc. Little stuff like that which catches you off guard, eats hours of your time and only to find out later it was a small little thing! That’s the majority of development in general, bad assumptions leading to gaps in the debugging process. Not only this, but because each game manages its own elements, I kinda messed up how UI interactions work with the screenreader, leading to days of development lost.
Anyways, after several days of frustrating development, which I started to really get quite anxious because the deadline was starting to get close (this was around the 19th or 20th), I finally was able to finish the game template and my first game. It worked perfectly! And I was really pleased with the result. The remaining microgames were not as difficult to produce, and I was able to put them out relatively quickly, about 1 a day - however, I was not super inspired and wanted to focus my microgames with the budding narrative I was working on…
Accessibility: Part Deux
But before I could do that, I needed to make sure that the games were actually… well, playable for blind people. And to be honest as a sighted person, even after doing blind accessible games for a while, its not easy. Sure, a user interface is intuitive, just build it like you would a website, but what about a game? This is why a blind consultant at the bare minimum is necessary. But in the future, I really want to involve a blind designer to tighten this process even more.
What do I mean exactly? Well, it’s simple - get the blind player to play the game! And it was quite embarrassing at first. Even though I tried the games with no graphics, I breezed through them while they struggled significantly. What was I doing wrong? The truth was, I had muscle memorized the game too much! So a new, inexperienced player with little or no vision is going to struggle a lot here. By asking my consultant about the games and proposing new solutions to focus specifically on the information that was missing to construct the full game in their heads, I was able to make all four microgames accessible to blind players.
Narrative
Finally, I wanted to rewrite the filler that I put in the game for testing purposes and really flesh out the narrative. The game was designed from the beginning to be about a schizophrenic going to a hospital and gradually recovering from their illness. As those who watch my channel may be familiar, I have Bipolar 1, which results in me having periodic episodes of psychotic mental illness. Later down the line, I want to also incorporate features of a case study mentioned in the book Psychoanalysis and Transversality by Félix Guattari, which has publications about the case of a particular schizophrenic patient at the La Borde Clinic. I wanted to express these experiences through the interface, but not just depend purely on textboxes, since that’s boring.
Instead, I wanted to think how I could use the interface itself to portray the illness. I thought a lot about my experiences, and perhaps somewhat serendipitously I had a minor bout of my own illness while working on development. I thought a lot about what I was experiencing, and what I had experienced in the past. This can be quite traumatic for many people, but I also found it as something that was valuable in processing my feeling and experiences.
First, I thought a lot about how “noisy” it was whenever I was crazy. This is what a lot of people call “voices”, but for me, it was more like thoughts that kept being made that didn’t feel like mine. Like, think of just random thoughts but they have no identity or speaker, and you can’t stop them, and they’re constant. Over time, they feel like they’re coming from outside of yourself, such as an external sound, but more often for me, the experience of “thought insertion”. So I emphasized how it “inserts” visual territory by forming a textbox that takes up a decent amount of the screen. These textboxes generate randomly with a randomly selected text depending on the situation.
Unfortunately, for the time frame of the game jam, I didn’t have time to add the sound assets to read the voices to blind players, so it is currently inaccessible - but for a future full release, I want to add all the voice samples. They are not read with text to speech since it is a purely aesthetic feature with only minor gameplay guidance that is mostly triggered randomly, and so it should not interfere with core functionality.
Another aspect I wanted to capture with schizophrenia is the sudden shift in the way that you experience things. Sometimes it feels like the world completely changes under your feet, and now you are functioning under a new ontology. This is hard to understand with words, but easier to express through rapidly cycling through a bunch of microgames. These microgames can represent not just individual experiences but also the constant shifting confusion of the illness.
Additionally, it was really hard to quickly think of a short narrative that would be enticing to players. The problem with writing a schizophrenic main character is that a core aspect of experiencing psychosis is an inconsistent sense of identity, a constant struggle with dissociation and loss of self, poor memory and periods of complete blackout. To transfer these experiences, I wanted to write a character who’s motives were not clear, but was extremely paranoid of being interfered with. This could capture the instability of the character and his confusion of what’s going on. What is really unique here too narratively is that the player, even without being told, can tell pretty quickly that the main character is probably schizophrenic. So there is a divide between what the player knows and what the main character knows. This difference is intentionally acknowledged when I am writing the script, so that the player can have a glimpse into the mind of a schizophrenic but from a gazing perspective.
In the future, I want to add more game modes, such as the ability to explore the grounds of the hospital, as well as building more and more microgames that really capture the aesthetic of these experiences. Of course, I lean in very heavily to my own experiences while intersecting them with others, so it really is a unique production!
Conclusion
I have many plans for where I want to take this narrative in the future with extended functionality for the game, and I want to release a demo before possibly trying to seek some crowdfunding and further visibility. In the meantime, I hope you enjoy what I’ve produced! I worked really hard on it. Thank you so much!
Files
Get The Castle
The Castle
Descent into Madness
Status | In development |
Author | Punished Felix |
Tags | Arcade, minigames, Narrative |
Accessibility | High-contrast, Blind friendly |
Leave a comment
Log in with itch.io to leave a comment.