Understanding Gaming Experience: Research Log 1

The following represents some general research on narrative, involvement, player role and game information that underpins my paper. I found Calleja’s work particularly fruitful, and will try to order a copy of his book In-Game to the library in time for my thesis.

The cognitive, emotional and kinaesthetic feedback loop that is formed between the game process and the player makes games particularly powerful means of affecting player’s moods and emotional states. 

Narrative involvement deals with the engagement with story elements that have been written into the game as well as those that emerge from the players’ interaction with it. It considers two inter-related dimensions of narrative in games: the narrative which is scripted into the game and the narrative that is generated from the ongoing interaction with the game world, its embedded objects and inhabitants along with the events that occur therein. 

Shared involvement deals with the engagement derived from awareness of and interaction with other agents in a game environment. These agents can be human or computer controlled and the interactions have here been discussed in terms of cohabitation, cooperation and competition. Thus, Shared involvement encompasses all aspects relating to being with other entities in a common environment, ranging from making collaborative battle strategies to discussing guild politics or simply being aware of the fact that actions are occurring in a social context. 

The ludic involvement dimension expresses players’ engagement with the choices made in the game, and the repercussions of those choices. These choices can be directed towards a goal stipulated by the game or established by the player or decided by a community of players, as described by Oriel above. The can also be spur of the moment decisions without a relation to an over-arching goal. Seasoned game players understand that well balanced game-systems emphasise the opportunity cost of any particular action taken. Without repercussions, actions lose their meaning and thus the emotional excitement (affective involvement) generated by their execution (kinaesthetic involvement). 

For those suffering from a lack of excitement, games offer an immediate channel of emotional arousal. Conversely, for those whose work or personal lives are too hectic, games’ compelling nature makes them ideal for shifting one’s attention to a performative domain that suits the players’ needs 

Game design, like other forms of textual production, is imbued with the rhetorical strategies of affect. But unlike other forms of text this rhetorical power is emphasised by the conjunction of textual interpretation and the performed practice of gaming. 

However, the effects they are intended to have are by no means those that materialise in the actual gaming instance. This can be due to a variety of factors ranging from a lack of interest towards the particular game or game genre, interruptions from other sources demanding attention, or quite simply, the personal interpretation of represented events that diverges from those intended by designers because of reasons personal to the player, or ineffective design.

Calleja, G. Emotional Involvement in Digital Games

An alterbiography refers to the active construction of an on- going story that develops through interaction with the game world’s topography, inhabitants, objects, game rules and coded physics. 

Alterbiographies are generated by the player adopting a narrative attitude towards the interpretation of certain representational signs and the mechanical operations that animate them. 

[A game’s] narrative elements, only comes together after a considerable amount of synthesising work from the part of the player. 

Calleja, G. Experiential narrative in game environment

The text itself, however, is neither expectation nor memory- it is the reader who must put together what his wandering viewpoint has divided up. This leads to the formation of syntheses through which connections between signs may be identified and their equivalence represented. But these syntheses are of an unusual kind. They are neither manifested in the printed text, nor produced solely by the reader’s imagination, and the projections of which they consist are themselves of a dual nature: they emerge from the reader but they are also guided by signals which project themselves into him. It is extremely difficult to gauge where the signals leave off and the reader’s imagination beings in the process of projection.

Iser, W. The act of reading: an aesthetic response

A player who is consciously role-playing […] is seeking to ‘create’ a character that transcends the mechanic of the game and takes on a plausible, defined reality of its own. 

MacCallum-Stewart and Parsler, Illusory Agency in Vampire: the Masquerade Bloodlines

[Narrative] fragility causes two problems in relation to agency. First, breakdowns damage the sense of dramatic probability in the situation. Second, they make the audience member question whether the materials presented for action (the whole of the English language, as invited by the open text field) can actually be used intentionally. As play continues it is revealed (as Lucy Suchman and others have discussed) that the Eliza effect works, for however long it works, because of the power of the initial expectations of the player, which are eventually too greatly violated. The illusion of agency is short lived. 

Mateas, Wardrip-Fruin, Dow & Sali, Agency Reconsidered

The systemic properties of a game become actualized once one or more players engage with them (Klabbers, 2009), and the game would not function without information that the players themselves bring into play (Crookall, Oxford and Saunders, 1987) 

According to economic game theory, information is either perfect or imperfect. Perfect information means that a participant has access to all relevant data regarding a situation, while imperfect information means that at least something is outside that person’s control. 

Lankowski & Bjork, Game Research Methods

The following is a large excerpt that might stretch the complexity of my essay too far, but its applications of frames to tabletop RPGs sits nicely alongside my (early) steps to model an understanding of theatrical preparation on the embodied player experience.

One prominent strand of research revolves around Goffman’s (1974) con- cept of ‘frames’ and its adaptation for tabletop role-playing games by Fine (1983). Studying players of said games, Fine identifies three frames that serve as schemata of interpretation (or rather ‘comprehension’) for the games’ events and existents (including characters): First, gaming “is grounded in the ‘primary framework’, the commonsense understandings that people have of the real world” (ibid., 186). When players apply this frame to the gaming situation they recognize each other as co-players and act according to the social situation (e.g. a gaming event with friends). Second, players operate “in light of the conventions of the game” (ibid.), their actions are “governed by a complicated set of rules and constraints” (ibid.). Finally, players may apply a ‘narrative’ frame, ‘keying’ the events in a game of make-believe: They pretend being characters in a fictional (story)world and act according to its lore and logic. 

They postulate a three-fold framing of player consciousness “as a charac- ter in a simulated world, as a player in a game, and as a person in a larger social setting” (Salen / Zimmerman 2004, 454, original emphases). Similarly, Lin- deroth (2005) identifies three ways of describing the player-avatar relation: Players recognize the player-controlled character as a role (“a fictive character that you can pretend to be”, ibid.), a tool, (“a piece of equipment, a tool which extends the player’s agency in the game activity”, ibid.), and a prop (“a part of the players [sic!] setting, […] which can be used as a part of the players [sic!] presentation of self”, ibid.). 

First, in what we propose to call ‘narrative experience’, the player perceives game characters as identifiable fictional beings with an inner life. Players construct mental character models that represent, for example, the bodily, mental, and social properties of a fictional entity and connect these with situation models related to diegetic events and existents. When characters are experienced narra- tively (or fictionally, or representationally), event or story schemata are em- ployed to establish mental representations of chronological and causal relations between characters and events, which might lead, for example, to expectations concerning future narrative happenings (or ludic events for that matter, see below). Put bluntly, it is the dimension of the fictional being that everyday conversations about characters across media most commonly refer to – but this does not apply to everyday conversations about video game characters to the same extent. 

Second, in what we call ‘ludic experience’, the player’s attention is focused on characters as elements of the game mechanics, as game pieces that are defined by game-related properties such as ‘health points’, ‘speed’, ‘special abilities’ and so on. In this mode, the player-controlled character is perceived as a tool, which extends the player’s agency into the game world. The player constructs a mental model of their character (or of other characters), which consists of game-related features and abilities as well as character-related goals and rules. The representational schemas that include such feature lists are not primarily learned in real life but, rather, are made available to the players by playing other games and gaining knowledge about rules and game systems. Similarly, (genre-)specific gameplay schemas are employed to generate motor output in response to the ongoing perception of the unfolding game, as well as the men- tal simulation of future ‘moves’ (see Lindley / Sennersten 2008, 3). 

Third, in what we call ‘social experience’, characters are perceived as avatars, as representations of other players in a multiplayer setting. In this case, players not only form mental models of a fictional being or game piece but also of the player ‘behind’ the avatar, resulting in a connected or mixed representation which includes features of both. This mode, which directs attention to the real- life context of the game and the forms of communication and interactions that it affords, certainly challenges structuralist-semiotic conceptualizations of char- acter which predominantly rely on textual structures. However, ‘textual’ fea- tures of multiplayer games still facilitate and constrain the possible social inter- actions – which themselves leave textual ‘traces’ and, thus, can become a relevant subject for a ‘text-oriented’ analysis of video game characters. 

Distinguishing not only between three representational modes (narration, simulation, communication) but also between three ways of experiencing (nar- rative, ludic, social) and three ontological dimensions of video game characters (fictional entity, game piece, representation of the player) finally also allows us to emphasize that the relation between the modes of representation and the experiential affordances as well as the ontological status of video game characters are far from clear-cut and should not be conceptualized as being overly stable. While there certainly is an emphasis on ‘ludic experience’, the interactive gameplay that characterizes the mode of simulation usually also contributes to the representation of video game characters as fictional entities – just as the cut-scenes and scripted sequences of events that characterize the mode of narration and, hence, tend to emphasize ‘narrative experience’, can also be used to convey specific information about video game characters as game pieces. Moreover, the video game character as a fictional being usually gets features ascribed to it that correspond to certain ludic abilities or characteristics, and vice versa. 

Schroter & Thon, Video Game Characters: Theory and Analysis

Understanding Gaming Experience: Forming a Research Question

Our lecturer Maddy led us through a series of preparation exercises and presentations to help us formulate our research question for this paper. The first was a mind map of areas of interest.

Areas of interest

As you can see, my initial areas of interest included:

  • VR Theatre (towards emotional / expressive inputs for actors and audiences)
  • Tabletop games (authorship in solo / journalling games)
  • Narrative (towards alternative narrative models, inspired by the operatic game OIKOS (A Dog Opera) and the cinematic game 30 Flights of Loving)
  • Dialogue (towards alternative dialogue systems, or looking at representations of internal voice in dialogue)

I felt like alternative dialogue systems might be a useful avenue for thesis work, but also that the area interested me the most. I resolved to crunch down on this area and formulate a much narrower field of investigation – if it remained as interesting to me as I expected, I could use the work as foundation for a wider-ranging thesis.

I sharpened my enquiry into a specific genre (narrative card games), gave it a specific lens (Stanislavskian actor theory – something I have a decade of experience with) and identified two case studies to support my investigation (Griftlands and Signs of the Sojourner). Maddy encouraged us to identify the keywords of our paper, as well as singular texts that would support defining those keywords. As you can see, I landed on Uncertainty and Game Research Methods for my analytic work, The Game Narrative Toolbox for understanding narrative, and An Actor Prepares for referencing theatrical concepts.

The above presentation constitutes my early research, drafting and analytic work on the paper. My research question went through various drafts to make it more specific; even here I don’t think it’s quite at its sharpest. The Stanislavski quote about ‘conscious technique’ was a great find, and helped to frame my arguments about theatrical work being central to deeper understanding of player character. The quote from Robert Yang – ‘gamers have been trained specifically to ignore subtext’ – would turn out to be central to my paper, pointing me to an accessible and oft-discussed term that a reader could relate to throughout. The graphs are examples of gameplay flowcharts, with moments of Stanislavskian ‘technique’ marked with yellow stickers.

All in all, Maddy’s provocations were extremely useful in preparing for this paper. I look forward to repeating the process for my thesis.

Experimental Development: Writing with a Text Generator

Further tweaks to the generator

I created a ‘printText’ function which would run through the generator for as many times as Jacky had set the levelCount to (6 at the time of writing, plus one ‘end’ scene), and dump the generated text into an empty game object. I could then, with a few clicks, export that text into Notepad and check through it for errors, repetitions, or just ways in which it could be improved.

I played through Jacky’s completed build, and one of my earliest reflections (and echoed in some feedback from players) was that while the information within each level hung together, a sense of progression was lacking.

In order to regain this, I implemented a new rule: {0:option|3:option}. A regex would check for a number followed by a colon, then parse the string number into an int, and add that plus the option string to a temporary Dictionary<int, string>. By iterating through the Dictoinary and comparing the int keys to PlaythroughCount, returning the highest int that is equal to or lower than the PlaythroughCount, I could guarantee that the most structure-appropriate options would be shown.I also divided the introductory texts up into levels, and had PlaythroughCount determine which table to draw from.

Writing

Stephen King’s book Danse Macabre provided a useful reference on what drives horror – while I can’t say that I was able to implement all of its guidance, I did find the following useful:

  • The idea of ritual – an image or a phrase that, when repeated, gains added dramatic significance or weight. The games writer and narrative designer Whitney Beltran (aka Strix) agrees on the usefulness of ritual, and given more time I would certainly deepen my research to include works like Victor Turner’s From Ritual To Theatre and Dramas, Fields and Metaphors. I defined at the top (in a json called ‘constants’) one of six sentences that would be repeated with increasing frequency the further the player wen through the game.
  • Horror is always “in search of another place, a room which may sometimes resemble the secret den of a Victorian gentleman, sometimes the torture chamber of the Spanish Inquisition… but perhaps most frequently and most successfully, the simple and brutally plain hole of a Stone Age cave-dweller.” This prompted me to refocus my writing on place, and what might come into it…

Bouncing off Jacky’s work was great for me – I’m a reactive creative, after all. I particularly enjoyed the more grammatically complex areas of generative writing – nesting verb tenses and different adjective lists, for example.

Player feedback

  • ‘A way to skip the typing text would be good’
    • Added an ‘E to skip’ popup and function to the canvas
  • ‘Not clear what’s going on at the start, or where I should go’
    • Brute forced this by making level (0,0) draw from a discrete ‘tutorial’ pool of text, which sets out the basic story, introduces movement, the purpose of the hedrons, and what the player should be looking for in terms of an exit.
  • ‘It would be easier to read if the text would break between punctuation.’
    • Exposed different WaitForSecond values for letters, commas and full stops.

Conclusion

Though the final result hangs together well enough, I think I would need at least another week of testing and writing to really make it sing. It was astonishing to me just how much groundwork I needed to lay before I could even begin writing the thing properly, and though that led to me doing a great deal of experimentation in programming the generator, it left me with little time to experiment with what it could generate.

This process was also useful in reflecting on my assumptions about design processes. Without the prototype in Perchance, then my parsing system, then my new structuring system, I felt lost in the woods; with them, I started re-appraising the design ideas I had junked during scoping. Maybe they were more appropriate than they had seemed? Despite my earlier disappointment with storylets, I had essentially ended up using them in the final product, after all.

I’ve learned from this that I might be more of a problem-solving designer, and that my route to uncovering a final design lies in lots of prototyping rather than too much diagramming. In future I will try to stay aware of this, and build in time to prototype, reflect, plan, and iterate as many times as possible during the development process!

Experimental Development: Building a Text Generator

Input language

Taking my cue from the construction of both Perchance and Tracery, I chose to use the following symbols the signify variables and options: [variable] and {option|option}. A [variable] might represent a call to another structure, or a randomly chosen item from a list. An {option|option} represents an either/or choice – the generator will display one of the options. This is more useful for quickly changing grammar on the surface, or adding ‘stings’ to the end of phrases{; like this, for example|.} And of course, it allows for nested grammars and variables, like {this one, [name].|{this|that [adjective]} version [location]}!

By choosing a familiar language I avoided the pitfalls of ‘reinventing the wheel’, and could take advantage of a ‘reverse engineering’ mindset in order to build this generator from scratch.

Input method

I decided on using the .json format, as it is lightweight and simple to write. A json consists of ‘tiers’ of information organised into {objects}, values and arrays[]. Here’s an excerptof a json with multiple objects, values and arrays:

The major upside to working with jsons is that they don’t require anyone to open Unity or search through any code in order to edit the generator’s content – if I were collaborating with someone on this generator, they could add in as much as they wanted, and as long as their entries followed the correct structure they would be absorbed by the generator with ease. I understand that there are Excel-to-json convertors that make this pipeline even easier…

Importing Jsons

Well, this was boring to learn. Apparently Unity’s JsonUtility doesn’t speak directly to Jsons that contain arrays, so you have to create a ‘wrapper’ class to import the file. For example, here’s my GenericJsonArray class:

Then you have to declare your regular Json class – in this case, GenericJson, each of which contains a single string ‘id’ and an array of strings called ‘choices.’

In the event of needing more complex nesting – for example, with each level’s concept, which contains multiple string arrays of ‘references’ and ‘aesthetics’ – I needed to define a whole other pair of classes. Below are my ConceptArray and Concept classes:

With the classes defined, a single line of code ‘deserializes’ the json (attached as a public TextAsset) into game-readable information. I kept all of this code in a single script called LoadJSON.cs.

Deserializing all the json containers for the game!

Phew! (Apparently external tools like NewtonSoft’s Json.Net can work more directly with jsons than Unity’s built-in tools; I found them to be just as difficult to use, but I think that speaks more to my lack of experience than to the quality of the tool.)

Filling the dictionary, setting constants and selecting structures

The first thing that TextSelector.cs does is fill a Dictionary with terms. This was my first time working with the Dictionary class, and I found it a really useful way of accessing variables – it’s essentially a container for pairs of information, organised into a ‘key’ and a ‘value’. A series of forloops enter the ‘id’ of almost every GenericJson (things, adjectives, inserts, features, verbs) into the key column, and a randomly selected ‘choice’ from that ‘id’ in the value column. That way, if a [variable] is encountered that matches one of the Dictionary’s keys, then it can immediately access the value at that index! (Dictionaries aren’t limited to pairs of strings – by using ints or floats one could tie most kinds of simple, game-pertinent information to another value…)

CreateDictionary()

Next, the script sets the constants for the level – level name, concept, and the features most prominent in the level. It can receive guidance from the level generation script in this, but mostly it’s just making random choices.

The subsidiary functions of SetConstants()

Finally, it chooses the appropriate structures through three different functions: SetStartText(), Populate() and SetEndText(). SetStartText() draws from the ‘introductions’ list in frames.json; Populate() assigns a randomly chosen structure from structures.json, and SetEndText() chooses from either a ‘generic’ signoff or a ‘spooky’ one, again stored in frames.json. (Why store the structures in different jsons? So the code just has to worry about returning [Random.Range(json.options.Count)] rather than knowing which index to pick! With this approach I can also add new content arrays into structures.json without worrying about pointing to the wrong index. In fact, in polishing for submission, I might even split frames.json into startstructures.json and endstructures.json for even more programming clarity…)

Parsing variables

But how do we know what a variable contains? It would be extremely performance-intensive to parse every character into lists of words and try to match each one to the Dictionary. Instead, I used regular expressions – or ‘regex’ – to parse each string for a number of matches, and String.Replace() to alter the structure in question.

Regex are sequences of characters used in string searching, and also in find-and-replace functions. They also look like gibberish – luckily, regex101.com allows you to test your regex on a string, as well as to consult a database of legal expressions.

My parsing function uses three different regex(es?) to process a string:

  • {options} – basically, this regex searches for anything between a pair of curly brackets, and includes the curly brackets themselves by using a ‘look behind’ and ‘look ahead’ as capture groups. The output is helpfully organised into two groups – {options} and options. If there are any matches, we increment the integer matchCount, save the first group (which will be replaced later) and process the second like so:
The beginning of ParseText(), using a regex to find a group of characters between two curly brackets
  • split|split – a new Regex is applied to every {options} result, looking for any series of characters on either side of a vertical slash. It will then choose one of these ‘splits’, and replace the entirety of {options} with that split. Importantly, in the case of {this option {another option|and another} | or this one} the function will ignore {this option {another option|and another} | or this one}, even though it’s possible for the ‘top level’ option to remove the ‘lower level’ option from consideration. This isn’t super-performant, but the Regex required to define anything more complex than this is basically magic to me. Since the function loops back on itself, it also avoids any errors caused by dangling {‘s or }’s. At this point we reset the matchCount to 0.
ParseText() splitting function
  • [variables] – with one round of simple {options} parsed, it’s time to move on to matching for [variables]. Luckily, the same capturing rules apply from my first Regex, returning [variable] as well as variable. If there are any matches, we increment the matchCount, then as long as the string variable is a match for one of the Dictionary’s keys, I can replace [variable] with that key’s value, which is a random choice from the ‘id’! (If there’s no Dictionary match, I have it output ‘NOVAR’ to signify a ‘broken’ or ‘dangling’ variable.)
ParseText() variable replacement code

If, by the end of the function, the matchCount has not reached zero, it loops back to the first {options} check, and continues looping until the matchCount rests at zero. Then the function returns the final version of the initial text so it can be displayed to the player!

Within the parsing function I have also secreted the RegenerateSeeds() function, which essentially causes every random variable in the Dictionary to ‘reroll’. I’m sure there’s a more performant way of doing this, but I couldn’t find a safe way of altering the Dictionary while it was being searched.

RegenerateSeeds()

Useful modifiers

For ease of writing (and my own sanity) I implemented the following extra modifiers as regex checks of their own:

  • [c.variable] – if the function encounters a ‘c.’ in a variable string, it will return the result but with the first letter in upper case, using C#’s String.ToUpper() method.
  • [r.variable] – by prefacing a variable with ‘r.’, I instruct the program to return the variable in duplicate, depending on the number of levels the player has visited. This results in unpunctuated, repetitive stream of consciousness, a technique that can quickly create a sense of acceleration, loss of control, or sensory overload.
  • {number-number} – if the ‘split’ regex encounters two numbers separated by a dash, it knows to return a random number between the first and second number.
  • {*|*} – if the ‘split’ regex encounters an asterix, it knows to replace it with [*], which I use to represent an empty string. This is handy if I need to quickly change the likelihood of a particular option being chosen, eg. {x|*|*} has a one in three chance to return ‘x’.

Possible tweaks

A method I have yet to code (and may run out of time in which to do so) is the ‘spookifier’, a way of tracking how long the player has gone without seeing a ‘spooky’ bit of text [reference procedural storytelling]. I imagine this could be achieved by adding a variable prefix – let’s call it [sp.] – which will only return the following variable if an integer is high enough, and on doing so resets the integer to 0. The integer would increment every time a string is fully parsed, as long as it wasn’t reset during that parse. This approach would yield a more consistently structured result than the current approach, which leaves ‘spooky’ interventions up to chance.

Experimental Development: Scoping a Text Generator

When I had finished planning what I wanted my generator to do, I assumed I would be able to jump straight into building it. This was far from being the case – I quickly realised that I would have to define the scope of the generator more clearly if I were to have any hope of finishing it before the deadline, as understanding what I wanted the generator to do and how it would go about it were two very different propositions. I wasn’t prepared for quite how long this was going to take, or quite how many false starts I would end up making. Jacky’s work was continuing apace, and I felt like I was lagging behind.

Design Attempt 1 – structures and storylets

My first swing at designing involved using a storylet system (as mentioned in the previous devlog) which would check for levelCount, progress, and any other prerequisites set by previous storylets. However, I would need some consistency in how the levels worked in order to deliver a coherent narrative structure, akin to the one I had defined in my research. Through a discussion on campus, Jacky and I decided that each ‘level’ would be divided into three ‘versions’, each depicting a different phase of the development process: graybox, textured, and populated. For each version we landed on a three paragraph structure – one triggered on entering a level, one on entering the ‘killbox’ in the centre, and one on leaving the level. The idea was for an unnamed lead developer to reflect on the contributions of various ‘disappeared’ level designers on their lauded 90s FPS – by the time the player entered the second and third set of stages they would be assuming something about what had happened to the developer; in the fourth set they would question that assumption, and in the fifth they would be hit with the reality of what had happened.

I used Unity’s scriptable objects as a way to integrate my storylets. Jsons might have been appropriate, but I didn’t want the game to have to parse every single json in order to find out which ones were appropriate to show the player; better just to list all the ‘segment’ scriptable objects and have them point to individual jsons which could be imported and presented to the player. First, the script ‘stacked’ the deck by removing all inappropriate segments; then it would shuffle and return a random segment. Each segment contained three paragraphs, which would be assigned to three different colliders in the generated level, and displayed to the player OnTriggerEnter().

A spreadsheet of storylet ‘segments’

The problem was ultimately one of time, effort and coherence. Having designed this system, and then begun work on filling in the text, I realised just how interdependent each storylet would be on the others, and how – in order to avoid a sense of repetition or dissonance – I would be doing both high intensity curatorial work (to make it make sense) and high intensity procedural work (to make it feel different with each playthrough). They may have been the correct fit for a horror story generally, but storylets (seem to) function best when they’re used as events, and tied to specific player actions. With little in the way of player interaction in this piece, they ended up feeling neither particularly reactive or elegant.

In hindsight, I also think this decision constrained Jacky’s creativity somewhat; in order to accommodate what I perceived to be an easier approach to text generation, he directed his generator away from some of the more surprising levels it had been making.

Design Attempt 2 – setpieces

Frustrated with the vagueness of my storylet approach, I revisited one of my earlier devlogs (it’s the same one that’s linked above). Convinced that a lack of set-pieces was blocking me, I talked to Jacky about changing the game’s construction so that it reflected one of three possible set-pieces:

  • the multiplication of features (more barrels or lights or stairs)
  • the subtraction of features (fewer walls or floors or lights or textures)
  • or a presence being felt in the levels (perhaps the previous developers spawning as ghosts)

Ultimately, though this provided Jacky with new ways to deepen his level generation (he ended up pushing the multiplication side of things), it rendered my text generation somewhat moot; the randomisation would’ve had little narrative effect, and I might as well have written each of these set-pieces myself.

Design Attempt 3 – just build a thing

I returned to probably the most fundamental question – not ‘what would be best to build?’ or ‘how should I build it?’ but ‘what am I currently able to build?’ and ‘what can I build in the time that I have?’ In some design tasks, responding to time pressures and working within one’s own limits are better actions than planning something ambitious. Maybe I would be able to alter or develop a simpler core generator into something more structurally responsive, but for now I just needed to make something that would consistently output the text.

I revisited the experimental procedural text generators I had written in Perchance, and set about jamming out a 5-beat structure similar to the 5-act one proposed in Design Attempt 1, but limiting each ‘beat’ to a ‘comment’.

My Perchance prototype, showcasing a five-beat structure with three shuffled middle beats

It was during this design iteration that I reconsidered one of my earliest assumptions: that this story needed to be about somebody other than the narrator. It was far simpler to construct something in the first person, and have the player relate – through listening/reading – to that character rather than to another that they were talking about.

While talking about this potential new direction, Jacky suggested we define how both the level and the story would change over time. I thought this was a brilliant suggestion, and one that I’ve found myself positing to designers and writers when working on theatre shows, but never really in game design!

By leaning into this idea of change over time, I could circumvent the problem of procedurally generating narrative immediacy. Instead, the sense of horror could be tied directly to the number of playthroughs a player had completed – things would get stranger and more complex as the player continued. This, we figured, could be juxtaposed nicely with a gradual deterioration in level fidelity – blockier textures, posterized textures, more noise in the audio mixer – to create a sense of chaos, terror, gradual unwinding, and to erode trust and create sympathy for an obviously haunted narrator.

Conclusion

From this process I concluded that procedural text generators are naturally good at some things – atmosphere and tone, different versions of the same thing – but quite inflexible when it comes to others. Working procedurally with narrative structure, while obviously possible, takes a lot of design time – something that, when taken alongside learning how to create a text generator in the first place, I ended up lacking on this project. Ultimately, the product worked at a much simpler level than I had first imagined, but that was only appropriate for the timescale (and my relative level of skill!).

Experimental Development: Planning a Text Generator

As per last devlog, I started by answering some of Kate Compton’s questions for defining a generator’s ideal output, its properties and its constraints.

What am I trying to make?

I would like my generator to create an epistolary horror story – told through the medium of a developer commentary – about developing a 90s FPS.

By narrowing down the genre of my artifact, it became much easier to identify sources for inspiration and analysis. Below I’ve listed some examples:

  • Epistolary horror
    • Dracula (Bram Stoker)
    • Frankenstein (Mary Shelley)
    • House of Leaves (Mark Z. Danielewski)
    • Graveyard Shift (Roger Matheson)
  • Developer commentary
  • Works about game/software development
    • Microserfs and Generation X (Douglas Copeland)
    • Halt and Catch Fire
    • Silicon Valley
    • The Social Network

What makes for a good example of this artifact?

Even without performing a deep analysis of each genre, I could come up with a number of factors that successful examples have in common:

  • Epistolary horror
    • Is scary
    • A sense of foreboding
    • Often concerns an offscreen terror, or something that cannot be easily expressed in language
    • The speaker doesn’t know whether the message will be received or understood
    • A character not comprehending what is happening
    • Is full of questions
    • Feels like a subjective experience
    • Moments of respite vs mounting tension
    • Initial perspective (what’s happened?) -> a shift in perspective (this has happened) -> the true perspective (oh no, that has happened)
    • Mad science / the breaking of a natural boundary
    • A logical conclusion, given the information available (rules for dying to / defeating evil must be logical)
    • Populates imagination with a cast of unseen characters
    • A revelation
    • Language is the language of a correspondent/speaker
    • “What possessed them?”
    • Draws attention to details about a situation or environment
  • Developer commentary
    • Populates imagination with a cast of unseen characters
    • Draws attention to (and recontextualises) details about a situation or environment
    • Delivers an understanding of the team or team members aims; sense of whether they succeeded or not
    • Reveals paths not taken
    • Accounting for or explaining decisions
    • Feels like a subjective experience
    • “What possessed them?”
  • Works about game development
    • Mad science / the breaking of a natural boundary
    • Populates imagination with a cast of unseen characters
    • A revelation
    • “What possessed them?” -> interested in innovators and mavericks; what drives people to create new things

What makes for a bad example of this?

  • Epistolary horror
    • Overly descriptive (literary language) or too direct in its description (no mystery)
    • Not scary, not thrilling
    • Exists in the realm of the known
    • Predictable
    • Structureless – no sense of build or direction
    • Overly structured – no sense of surprise
    • No consequence or cost to characters
  • Developer commentary
    • Uninformative – doesn’t provide design insights
    • Too jokey
    • Unclear
    • Few observations – dead air
  • Works about game development
    • Overly technical
    • Lacking in a human element / characters

How would a human build this thing?

It is helpful when making a generator to sit down with someone who makes the sort of artifacts you are building, and have them walk you through the process of making something. What questions do they ask themselves along the way? How do they make decisions? How do they describe the tradeoffs between choices? How do they describe the different problems that they have to keep in mind? How do they name all the parts of what they are working on, and all the relationships between them? (the academic term for this is an “ontology”)

Kate Compton, So you want to build a generator?

With the above questions as a framework, I approached my friend Stewart Pringle, currently Dramaturg at the National Theatre and also an expert in horror writing. His answers are too detailed to be published here in full, but here are some of the most useful provocations:

  • ….horror is most closely aligned to comedy, and it’s really in that structural respect that it’s most true. Horror usually relies on a structure very like a joke, setup, assumption, shattering of that assumption, punchline – except whereas in a joke it’s the establishment and twisting of a convention into absurdity, in horror it is the twisting of a convention into uncomfortable or frightening territories…’
  • Good questions:
    • ‘What’s the worst thing that could happen in this situation?’
    • ‘What’s this really about?’ – ‘horror isn’t an interesting end in and of itself, it’s a sublimated territory which your characters traverse, and what exactly it is that is being sublimated by it is the key question in the drama. What is The Wicker Man really about? Isolation, conventionality, the dangerous things in the wild parts of our nature. What is Suspiria about? Puberty, sexuality, suffering for art. You can do the same with all but the most pointless horror stories.’
  • What constitutes ‘good horror’?
    • Having something to say
    • How much it raises the pulse
    • How long its images linger
    • How it encourages you to think about something differently (grief in Midsommar, racism in Get Out)
    • Being in ‘good taste’, ie not having ‘unpleasant and stupid things to say’, or saying them unpleasantly (Hostel is an example of horror being in poor taste)
  • ‘The big trade-off between choices that I always think about is sort of a question of how much you tell an audience vs how much you leave mysterious.’
  • ‘You have to keep in mind the story’s relationship to reality, particularly if it’s quite a wild or heightened story, and that can be a challenge.’
  • ‘In any kind of narrative fiction you sort of want to teach the audience how to ‘read’ what you’re creating, but in horror there’s a real power in teaching them incorrectly, or teaching them differently, and then creating an exciting shift.’
  • ‘If dramaturgy is only ever a series of small surprises followed by a bigger one, in horror I sort of think of it as a series of set-pieces leading to an almighty fuckstorm at the climax. In Whistle and I’ll Come To You, it’s a series of dreams that eventually lead to a full-on malignant apparition. In The Weir it’s a series of unconnected stories that gradually paint the picture of a dangerously unprotected and haunted universe.’

Stewart also provided my with some more examples of epistolary horror that I can look into:

  • Whisperer in the Dark, Call of Cthulhu and Herbert West: Re-Animator (Lovecraft)
  • Carrie, Jerusalem’s Lot and Survivor Type (Stephen King)
  • A Story of a Disappearance and an Appearance (M R James)

Conclusions and Actions for my ‘Artist in a Box’

From my research and correspondence with Stewart, I could define my epistolary horror generator as something that needed to:

  • Have a cogent theme (either consistently across the entire game experience or limited to, say, a group of 5 stages)
  • Write in set-pieces, which collectively progress to a ‘larger’ set-piece near the end
  • Divide set-pieces into four ‘beats’: setup, assumption, shattering that assumption, punchline
  • Generate memorable images
Simple timeline of generator steps

Obviously it’ll be a little more complex than the above diagram, but having three design goals on which to focus – theme, structure and imagery – feels helpful.

Since structure is going to play such an important part, I am sure I will be making use of storylets. Storylets (summarised in this blogpost by Emily Short) are pieces of content with prerequisites that govern when they are displayed, and which have an impact on whether other storylets are displayed after them. A simple example of this approach’s relevance to my project would be in ensuring that, in a given set-piece, a ‘setup’ piece of text is generated first, then followed by an ‘assumption’ piece of text, a ‘subversion’ then a ‘punchline.’

  • Every time a storylet is displayed, it could tick up a ‘progression’ indicator.
  • Setups are only displayed when progression = 0; assumptions at 1; subversions at 2; punchlines at 3.
  • When progression is more than 3, it resets to 0, starting a new set-piece and beginning the process anew.
  • Each reset might tick up a higher-level ‘tension’ indicator, which would unlock storylets more suited to the later set-pieces of a story.

I’m imagining these storylets to be structural ‘containers’ rather than bespoke pieces of writing, with [details] filled in by the theme-related imagery decided at the beginning of generation; they could even contain their own degrees of randomness, like the {A|B} functions of Perchance and Tracery.

The next steps are to begin coding the generator itself!

Experimental Development Project: First Steps

Identifying a Project

In my experimental mini-devs I had mostly focused on procedural text generation, researching VR, and messing about with shaders. I enjoyed working on procedural text, so was keen to push that further, but didn’t have a clear starting point for what I wanted to create.

Luckily, Jacky shared the beginnings of his Experimental Development project – a procedurally generated maze that would make the player feel like a ghost – on the support group chat. I was struck with a lot of ideas for how a procedural text generator might interact with a procedural level generator (finding spooky notes in different rooms, ‘hearing’ a voice as you explore, an isometric dungeon generator with procedural encounter descriptions), and we soon agreed to collaborate.

We set up a meeting to talk through possible avenues, and settled on a direction partly inspired by the low-resolution shader techniques Zsan had shared with us: the levels would be from a 90s/early 2000s FPS, and the player’s progress would be accompanied by a procedurally generated commentary, displayed in text on a era-appropriate HUD.

We also put together a Miro for collecting design tutorials, aesthetic inspiration, useful tools and examples of developer commentary.

Our Miro after 1 week

From our research (and also a suspicion that this might be the best way to keep scope manageable) we concluded that deathmatch levels might be an appropriate constraint:

  • Deathmatch levels are self-contained and generally encourage players in a ‘looping’ direction. These loops are arranged around central ‘killboxes’ – open spaces that players are naturally directed towards. We suspect this design will make generating levels easier than ‘single-player’ levels; indeed, Jacky’s generator already functioned off a ‘figure-of-eight’ rule, which connected two ‘edge’ rooms to one ‘central’ room.
  • Levels each have a unique, vivid aesthetic, but their architectural and environmental design aren’t necessarily governed by a linear or progressive narrative, nor do they have to connect to each other. This means the level generation procedure doesn’t have to worry about building ‘towards’ a particular end, funnelling the player toward an exit, or having a logic to the order of aesthetics (textures going from light to dark or warm to cold, for example).
  • Deathmatch levels are arenas and play-spaces rather than puzzles or set-pieces. The logic of the former approach is much quicker to code than the latter, which requires a more rigorous set of conditions to be met in order to produce a ‘correct’ map (a room with a key cannot be spawned behind a locked door, for example; the lever to control a bridge must be on the side at which the player will first arrive, unless there is an alternate route – complicated!).

The first instance of FPS levels being designed and released specifically for multiplayer occurred in Quake, so on Friday we sat down to watch some walkthroughs of Quake Deathmatch levels for inspiration.

A video walkthrough of Quake’s DM5 – The Cistern

Identifying My Tool

In practising procedural text generation, I had already used two tools: Kate Compton’s Tracery and Perchance, a web-based platform for creating and sharing text generators (which is very popular with the indie TTRPG scene).

The first product was a simple NPC generator, which I initially built in Tracery and then exported to Perchance.

Code, output and html for Sad NPCs

It outputs three sentences:

  • A character (adjective and occupation) and something they are doing
  • A description of something they are carrying (item, adjective for item, location on character)
  • An action by another character that affects them, or an objective they pursue and how they pursue it

In building this I found that using grammatical prepositions (after, before, with etc) as the first generative step made for much more distinct sentences, and allowed me to be more granular in my list-making. I also noticed that adjectives often made lines overly unique, which had the odd affect of making them feel more similar to previous lines. [reference Procedural Storytelling for Games here] This problem was solved by decreasing the likelihood of the generator assigning adjectives.

The second product I wrote was a Contestant Generator for Love Island. I analysed examples from ITV’s own Islander introduction copy and created a generator capable of outputting five short paragraphs, defined at the top by two random choices – gender (for grammar) and occupation (for puns) and gender (for grammar).

This generator was slightly more complex in the sense that more dictionaries were required (for hometowns, hobbies, attitudes etc.).

In order to achieve even this level of logical sense within a reasonable timeframe I had to sacrifice variation in sentence structure, so in some ways this generator is much simpler than the previous.

Two options for paragraph structures

Unfortunately, my research failed to find an easy way to connect a powerful tool like Perchance to Unity, so I was left with the following options:

  • Tracery
    • Pros:
      • Easy to understand
      • Built for randomness
    • Cons
      • Can’t see a super easy way to get it to ‘remember’ previous states
      • Less variable-friendly
      • JSON syntax a bit tiresome (lots of quotations)
  • Ink
    • Pros:
      • I’m already familiar with the syntax
      • Easy to implement in Unity
      • Remembers states very well; variable-friendly
    • Cons
      • Not explicitly designed for ‘generation’
      • Lists & variables are locked to single words, so might be hard to integrate more phrase-centric grammars
  • C#
    • Pros:
      • Native to Unity, no need for ‘bridging’ scripts or functions
      • I’m already familiar with the syntax
      • Very flexible, editable Lists
      • Feels like the Perchance ‘method’ could be relatively easily translated to C#
    • Cons:
      • Would have to write own functions for shuffling, choosing, etc.
      • Probably a similar level of syntax ‘stickiness’ with quotation marks for strings etc.

I’m still mulling over which to use, but I’m leaning towards creating my own functions in C# – this would add another facet of technical experimentation to this project, which might help me grow my skills further.

Planning a Generator

Kate Compton’s ‘So you want to build a generator?’ provides a handy guide to ideating, defining and then building a procedural generator, summarised here:

  • Write down the thing that your generator will make
  • Write down everything you know that makes for a successful example of one of those thingsproperties to strive for
  • Write down everything you know that makes for an unsuccessful example of one of those thingsconstraints to work around/within
  • Consider how a human would build these things – consult an expert, research ‘frameworks’
  • Decide on a generative methods – options include Distributive (like picking options from a deck of cards), Parametric (altering individual elements of a handmade object), Tile-based (chop the problem into units, have pre-made objects fill those units in different orders), and Grammar-based (a series of rules and symbols that ‘unpack’ into sub-rules and sub-symbols, like language, for instance).
  • Build and test your generator!

Over the next week, I will endeavour to answer these questions about the artifact I would like the generator to create, as well as getting in contact with some horror writers that I know and researching frameworks for writing these kinds of stories. I will also start scoping the generator, deciding how much text, how many times per level the generator will need to run, and what kind of connectivity I would like the generator to have with each level.

Experimental Development: Case Study (Denizens of the Dying World)

Denizens of the Dying World (abbreviated from now on to DDW), by Brian Yaksha, is a small character generator, ostensibly designed for the dark TTRPG system ‘Mork Borg.’ Brian is a game designer who both writes his own games and works on others’, as well as blogging at https://www.rakehellzine.com/.

DDW is written using Perchance, and the great thing about Perchance is that anyone can look under the hood of its generators by pressing the ‘edit’ button in the top right.

A collapsed view of DDW’s structure

On the left you can see the ‘grammar’ – the rules by which the generator is governed. It’s actually extremely simple, outputting a [name], a [surname], a [type], a [want], and a [vibe], followed by some [combat] stats. However, by avoiding overly complex grammatical rules and focusing on highly specific list entries, the generator can produce consistent-feeling characters, with a few surprises.

Types

Above are just five of the generator’s 100 types (100 is apparently a good number). The types follow a consistent grammatical rhythm of four (sometimes five) clauses, which create a sense of past and present, and contrast description with action. This approach is highly reminiscent of Adam Saltsman’s ‘couplet’ technique in Overland, where he paired a past biographical detail with an intention for the future.

The [want] is the only rigid selector in the generator: ‘they know of [placetype] [placename].’ Perhaps it is unfinished?

Takeaways

  • Lots of options make for better-feeling randomness (100 is a good number)
  • Specific and highly differentiated options make for better world- and story-feel
  • Contrasting couplets create drama

With regards to writing stories, of course, I can’t rely on such consistency in player action, and will need to account for players missing beats or skipping through text entirely. By making unskippable intros and outros to each level that tie into the environment or set up the next one, I ought to be able to ensure a sense of continuity; any middle story beats (say, contained in a pickup or interactable) should probably be general enough to apply to any level (unless I can magic up another month to work on this!).

Personally, I am interested in digging further into grammatical rules. The generator I am currently working on – Sad NPCs – has a grammatical system predicated on prepositions. If it chooses ‘by’, for example, then both the [verb] and the [influence] can select from only the [by] pool. This also works for genders. Obviously, the combinatorial issues are fairly serious, but I prefer the potential for structural surprise! I can already see that creating a deep-feeling generator is not the work of days or weeks, but months and maybe even years…

Critical Play Project: UI, Text and 3D Animation

Having identified exposed systems and UI feedback as areas to explore, I set to work in two directions: developing feedback around text and UI, and learning how to rig a humanoid 3D model for procedural animation.

Text & UI

My initial designs for the scenes didn’t change much – I think subconsciously I was already influenced by the radial menu of Mass Effect, so the bottom of the scene became the location of the ‘choices.’ I experimented with bringing the choices more into the mise-en-scene, like in Fallout 4, but with few non-textual elements (like sprites and backgrounds) to consider the frame became unbalanced. I think I was also assuming a phone-shaped viewport (9:16 rather than 16:9), so arranging the text along the vertical eyeline made more sense to me.

In terms of feedback, I experimented with fading both the choice text and the story text towards ‘impel’, ‘compel’ and ‘repel’ colours in order to expose the possible outcomes. The most logical to me was having the choice text fade towards the choice, and the story text fade towards the likely reaction, but players found this to be confusing, as the story text wasn’t the thing that would react. I opted for some rotating circles that would grow with the likelihood of each choice; this seemed to make more sense to players. Following Disco Elysium’s example, I also changed the colour palette to something a bit more striking.

Ultimately, the rotating circles just seemed a bit nonsensical, so I opted for introducing a gradient background that would shift colour proportions depending on the likelihood of the previewed outcome, and fade to the ultimate reaction once a choice had been made. I also intended to add a ‘splash’ effect inspired by DE’s dice roll feedback, but rather than using it to communicate which response the weighting algorithm had chosen, I made it check for whether the response was in line with the prediction – i.e. whether it was a felicitous or infelicitous response. However, with Unity’s shader graph system giving me trouble and time pressures mounting, I was unable to get these to look slick enough, and had to cut them before submission.

To expose the ‘actioning’ system, I floated some new text boxes in the scene, which would be filled by actions randomly selected from certain lists, depending on mouse position – this was simple enough, but timing their appearance and disappearance took some experimentation. If they disappeared too quickly, players didn’t fully absorb them; if they stuck around too long, they over-coloured the next response.

3D Animation and Rigging

For scene four I had set myself the challenge of animating a ‘scene partner.’ I didn’t expect to be doing any facial animations, but I did need something with a head and shoulders, and I didn’t feel like a 2D sketch would be able to capture much subtlety without a lot of work. So I searched the Unity Asset Store for some free 3D models; most were fantasy or science fiction creatures, or young women in the anime style, but I did find one asset pack of suitable models, from a game called Distant Lands.

These models came with their own rigging data, and one of the comments praised the pack for its use in rigging practise, so I downloaded it. With Unity’s own rigging package, accessing these free models’ bone systems was a two-click process, and I had soon programmed the head to follow a ‘tether’ game object, which would move in relation to the ‘distance’ variable in the Ink script. By tying the x, y and z positions of this tether to different variables, and having the head lerp towards the tether rather than snap to it, I had created a rudimentary but effective procedural animation. 

Now for the body. In my sketches I had only considered the head and neck, but if they were the only moving parts the model looked extremely strange. I needed to move the chest as well. I didn’t have time to investigate particularly complex approaches, but my solution was satisfactory: I created two new rigs, both affecting the same piece of the model’s ‘spine.’ However, one would rotate the spine around the Z-axis normally, and the other would do so inversely. The effect would be of someone ‘opening’ or ‘closing’ their chest to something. Next, I wrote some code that would alter the ‘weight’ of each rig, tied to the partner’s ‘attitude.’ The further into the negative the attitude, the more heavily weighted the inverse rig; vice versa for the positive. This connects quite nicely to the Santa Cruz paper’s coverage of Stanislavskian approaches to animation – by ‘opening’ or ‘closing’ the model’s chest depending on its attitude, I could give the impression of different kinds of performative ‘energy,’ which not only coloured the impact of player choice, but also the next line of partner dialogue! (Of course, this only works with unvoiced lines – a voice actor would either have to record nigh-infinite emotionally ‘tinged’ responses, or lock the responses down to only a few.)

The only thing missing was a sense of ‘breath,’ but this was a doddle. I added a script that moved its ‘facing’ tether up and down on a cosine function. If I were to dig further into this project, I would investigate tying the frequency and amplitude of this script to some of the reaction values, in order to mimic emotional changes in breath.

Now I had a reactive model, but I found that player attention on the previewed text had fallen off. Players needed the preview feedback in this scene to be tied more closely to the central visuals – I needed to re-expose the possible responses. I duplicated the models and connected each one to the three different ‘likely’ variables, giving each a different degree of transparency.

When the preview function was called, each would shift towards the likely outcome, as well as change mesh colour. The effect was ghostly, and a little awkward, but seeing these holograms respond to mouse position gave some good gamefeel, and watching the ‘real’ partner model merge with one of them gave a clear indication of the narrative and emotional outcome of a choice.

Critical Play Project: Working with Ink + Unity

When researching different dialogue engines / narrative scripting languages for this project, I came across three: Fungus, Yarn and Ink. I had already used Ink before as my first step towards understanding scripting last Spring, so I decided to stick with it – learning a new language for the purposes of this project would have made for a good learning outcome, but I was conscious of time. Additionally, I wasn’t confident in how ‘deep’ Fungus and Yarn could go into under-the-hood mathematics, and I knew Ink could handle the kind of functional programming I was after. I didn’t expect the story to ‘go’ very far, but I did anticipate needing to access large lists and booleans across multiple scripts. Ink is flexible and hardy enough for that.

I set out an initial dialogue ‘flow’ (or ‘weave’) by writing ‘First line of dialogue’, ‘Second line of dialogue’ etc., with the player afforded three choices connected to ‘impel / repel / compel.’ 

I was also able to expose these different choices or reactions by prefixing each line with a command to show the current ‘intention’ values. In Ink this is achieved by writing the variable within curly brackets: ‘{inflection} First line of dialogue’ would produce a result of ‘3 First line of dialogue,’ if 3 were the value of the intention variable. This would prove invaluable in debugging the story’s sometimes finicky behaviour.

I also wrote a simple version of my weighting function, which would react to a player choice by calculating the ‘difference’ between the previous ‘partner intention’ and the new ‘player intention.’ Based on that difference, it would add or subtract ‘weight’ from three integer variables, one for each basic reaction. These weights would be totalled, then a random number generated between 0 and the total – if the number fell inside the range of one of the weighted ‘buckets’, then it would return that bucket’s reaction. Programming this variance into it meant that each runthrough would be different, and players, though able to influence the weighting significantly, would be unable to guarantee results.

Connecting Ink’s output to Unity was a cinch. The second scene (readthrough) was actually the easiest to create, as Ink’s out-of-the-box Unity plugin provided code for connecting story text to a text box and choices to instantiated buttons. It was easy to arrange the scene as I had imagined. 

Building the first scene (the script) was a little more difficult, as I actually had to instantiate buttons over where I imagined the chosen dialogue text would appear. The trick here was actually in the animation – by creating different prefabs for the button text and the dialogue text I could time the OnClick() disappearance of the former with the fade in of the latter. I also had to rewrite some of the cleanup code so that only the choices were removed on story refresh, rather than all the text.

Although the surface elements of connecting Ink to Unity were easy, I encountered many problems in connecting Ink’s functions to Unity. This was mostly a symptom of the difference in how Ink and C# run through their code. While C# runs quite predictably frame by frame, Ink (as I understand it) will only ‘output’ once it hits a ‘stop’ in the story flow (usually a player choice). What can happen as a result is that Ink can encounter a function call within its code, run that function, and print the next line of story text – but Unity might need to change something in the UI before the line is printed! I spent at least two days working out how to reliably get Unity to inject its changes into Ink before the story was loaded, and vice versa.

One of my solutions, which I regard as unsustainable, was to write the same ‘reaction’ function in both C# and in Ink. The version that previewed likely reactions was run on the Unity side, while the version that ‘committed’ choices to the story was run in the Ink story. This was tiresome to code (Ink, while similar in architecture to C#, replaces many of its symbols, so curly brackets become colons, if statements are dashes within curly brackets, etc. etc.), and were I not under deadline I would have liked to have spent a lot more time digging into a better approach. Something for next time.

Another difficulty was the semantic and functional difference between C# arrays and Ink’s lists. A C# array, while it can be coded to include multiple values, is generally referenced to check if it ‘includes’ a variable or object. If a variable or an object is in an array, then it ‘includes’ that variable or object. In Ink, every variable is both a value (an integer or a string, for example) and a boolean. This is useful for, say, organising a list of clues, then checking off whether a player has discovered them, or for progressing along a list of chronologically connected states (Monday, Tuesday, Wednesday…). What this means is that a list can ‘contain’ one hundred different variables, but they could all need to be declared ‘true’ before (for example) a random output function will recognise that they’re actually *in* the list. The solution in this case was to make a master list of verbs, then ‘add’ every verb to its relevant list at game start. It took an embarrassingly long time to figure this out, and in future games I will look for more elegant solutions. It might even be more useful to contain this sort of function in Unity entirely…

Once the UI feedback was in place, I realised that I didn’t need my earlier multiple choices; indeed, for the Ink script to work as I wanted it to, I would have to either present a single choice that output various values depending on previous choices and mouse position, or nine choices for each line of dialogue! Neither looked particularly easy to implement, but the nine choices seemed the least flexible and most time-consuming. I took to writing the code for the first option.

This took the form of extending the existing functions quite extensively, and I spent a lot of time doing tidying work, like converting variables from one format (-1, 0, 1 for altering the visuals of the game) to another (the list and array-friendly 0, 1, and 2). Having to update functions in two languages was extremely time-intensive, and I’ve definitely learned a lesson about not coding myself into a bind. In future I will plan out functions more completely, regardless of which language I’m using.

One final discovery (is discovery the right word for something you remember at the last possible minute?): since each ‘scene’ required Ink to function differently (early stories didn’t need access to the lists of verbs, for example), I had been creating new Ink stories for each scene. But, like coding a ‘class’ in C# to pass down functions to its children, Ink can ‘include’ different stories, removing the need to rewrite every function or preface each story with the same block of lists. Migrating my work into this format was time-consuming – were I to return to Ink as a language I would begin with a stricter project hierarchy, and use multiple ‘includes’ from the get-go.