Ink and Lines #2: Document Censoring with TextMeshPro


If you don't know, Ink and Lines is a game about censoring documents for an authoritarian cult government. You play as a new Ministry "Cleanser",  which is their alternative term for a censor. Censoring text and images will be the primary method of interaction for the player, apart from managing documents on a desk and passing them through a fax machine. 

But what is the best way to implement such a feature in Unity? I don't know, but here's how I did it:

TextMeshPro has long since proven to be the best option for handling text rendering in Unity, and it does not disappoint in this case. Here's an example document in the game that is using a TextMeshProUGUI text element. 


I want to be able to right click on any of these words to censor them. And I want to be able to right click again to un-censor. Because mistakes happen. First things first though, how can I even detect when a word has been clicked on?  TextMeshPro has got me covered. 

int wordIndex = TMP_TextUtilities.FindIntersectingWord(textMesh, Input.mousePosition, null);

FindIntersectingWord() takes a TextMeshProUGUI text element, a position and a camera to do the raycasting necessary to find if a word is at the given position. In my case, my UI is in Screen Space render mode, so I pass null instead of a camera. This method returns the index of the word at the point in the given text mesh, or will return -1 if no word intersects. 

Brilliant! So now that I can find any word that I click on, how do I censor it? The answer of course is rich text tags. They don't count as words in the text element, and I can easily add and remove them from the surroundings of any given word. In my case, the <mark> tag is what I want. It gives a useful highlight effect over the text within the tag, and by providing my own hex color value, I can turn this highlight into an outright censor. Like so: <mark=#000000FF> Full black, max opacity.

So to tie all the logic together, I just need to keep track of the active text elements in my scene that I want to be censorable (i.e. all of them) and then do some basic .Subtring() and .Contains() checks to determine if the word I clicked on is censored or not, and then add or remove the rich text tags as necessary. Here is the Update loop of my DocumentCleanser:


You can see I also added a couple flags documentInteracting and isCleansing. These allow me to hold right click and drag across multiple words. It will lock into whatever action I do first, which prevents repeatedly censoring and un-censoring a word as I drag over it each frame. 

CleanseWorldIfUncleansed() and UncleanseWordIfCleansed() do as they say, adding or removing the rich text tags to words if necessary using standard string .Substring(), .Contains() and .Remove() functions. 

Now check out the code in action!

 

Easy! This works... mostly. Unfortunately this doesn't handle the case of documents being on top of one another, so it is entirely possible to censor a word of a page that is buried beneath another. I'm not sure exactly how I will handle this yet, but I suspect I will need to do a raycast to find a document at the mouse position every time I click, instead of checking all documents active in the scene. Thankfully that should just be a wrapper for this code I've already got working. 

So now that the player can censor documents, and since I've handled tracking which words need to be censored and why in the last devlog, once the player turns the documents in its a simple matter of iterating over every word, using the tags to the determine if they've been censored, and compare that to the rules data. If there is a mismatch, we can punish the player. If not, they succeeded flawlessly! 

That's the core game loop mechanics more or less functional, the rest of the game will just be building on this with more censorship rules and puzzles involving clues and secret messages. I kinda have the whole game planned out, but my plan is to focus on getting a playable prototype out asap, which I think will end up being about half of the story that I have planned at the moment. I foresee creating lots of documents in my near future! 

Thanks for reading, see ya in the next devlog! 

Get Ink and Lines

Leave a comment

Log in with itch.io to leave a comment.