Fugue Devlog 14: Authoring Tools

06.05.2022

Wow, it's been almost a year since I last updated this blog.

I haven't had time to work on Fugue until a month or so ago. Since then I've been chipping away at more tooling. Once the core game mechanics/systems are in place, I'm expecting that most of the time will be spent creating content for the game: writing, modeling, environment design, etc. So I'm building out tooling and figuring out strategies to streamline all of these processes.

Godot makes it easy to develop editor plugins that integrate relatively seamlessly. It's not without its challenges and frustrations but those are more to do with Godot in general than specifically about their plugin development process (see below).

Writing

The game will play out mostly through characters saying and doing things, and these actions need to be specified in a way where I don't need to meticulously program each one. Previously the game's narrative elements used "Dialogue" as the main organizing element, focusing on spoken dialogue, and let me write "scripts" of spoken dialogue lines with a playback system to have the appropriate characters say their lines in order. That ended up being too limiting because I want to write not only dialogue but to specify various actions/stage directions to write scripts that basically describe entire scenes, including character movement and animation, sound and environmental cues, and so on. So I restructured that whole system around "Sequence" as the main organizing element, with "Dialogue" as a sub-component.

A Sequence is composed of "Actions", which include dialogue lines, choice prompts, animation triggers, game variable setting, character movement and rotation, etc. At the time of writing the following actions are available:

  • Line (L): A line of dialogue, spoken by a single Actor.
  • Decision (%): A set of choices that the player must choose from.
  • VoiceOver (V): A line of voice-over dialogue. The difference between this and Line is that it does not require the speaking actor to be present and shows in a fixed position on screen.
  • Prompt (?): Basically a combination of Line and Decision. A line of dialogue is displayed with the decision's choices.
  • Pause (#): A blocking pause in the sequence
  • SetVar (=): Set a state variable to the specified value (strings only). There are a number of targets
    • Global: Set it on the global state
    • Sequence: Set it on the local state (local to the current sequence). These values persist through multiple executions of the same sequence (i.e. they aren't reset whenever the sequence is run again).
    • An Actor: Set it on the local state (local to a specific actor).
  • PlayAnimation (>): Play an animation with the specified for the specified Actor
  • MoveTo (->): Move the Actor to the specified target
    • You can use this to "bounce" the player character if they enter somewhere they aren't supposed to.
  • LookAt (@): Have the Actor look at the specified target
  • ToggleNode (N): Toggle the visibility of the specified node. Can fade it in/out (but looks quite janky)
  • RepositionNode (>N): Move a node to the position and rotation of the specified target. This happens instantaneously...so you could use it for teleportation; but more likely you'd use it to rearrange a scene while it's faded out.
  • TogglePortal (P): Enable/disable the specified portal.
  • AddItem (+): Add an item to the player's inventory
  • PlaySound ())): Play a sound
  • Parable (~): Start or end a Parable (Quest)
  • Fade (F): Complete fade the scene in or out
  • ChangeScene (>S): Change the scene. Because sequences are associated with one scene, this will end the sequence!

Sequences may be triggered in one of three ways: the player interacting with an object (such as talking to an NPC), the player entering a zone/area, or they automatically start when a scene loads ("ambient" sequences).

A "Sequence Script" is a graph of two types of nodes: "Verses", which are lists of actions, and "Forks", which include one or more "Branches" that each have a set of conditions. If a branch's conditions are true then its child verses are executed.

Sequence Editor

Sequences are associated with only one scene. Generally multiple sequences will be related in some way: the might be part of the same narrative arc, for example. So Sequences can be further organized into "Stories" which is basically just a grouping of Sequences, without any significant additional functionality.

The Sequence and Story Editors both make it very easy to quickly sketch out scripts and later refine them. They both have built-in validators to ensure that scripts are correctly specified, i.e. they don't refer to any objects that aren't in the scene, aren't missing any required data, etc.

Sequences and Stories are just stored as relatively simple JSON so they can be further processed/analyzed outside of Godot easily.

I expect that as the game's writing and development continues more actions will be needed. But for now this set has been comprehensive enough.

Example script showing different sequence actions

Textures

Finding source images that fit my licensing requirements and then editing them into textures is a very tedious process. I built a web tool that makes it much easier to find public domain and CC source images (vastly simplified by Openverse), cut out clippings from them and pack those clippings into textures or generate seamless textures by wrapping and blending their edges. It tracks where the clips were sourced from so that attribution is much easier to manage.

Texture Editor: Search

Texture Editor: Clipping

Texture Editor workflow

Music

I'm not at the point where I've given a ton of thought to the game's music, but I do have one tool, dust, that I developed to help sketch out musical ideas. I didn't develop it specifically for this game but it'll be useful here too. It's a chord progression generator/jammer that outputs MIDI so it can be used as an input to most DAWs (tested with Bitwig Studio and Live 11). It helps to get around blank-canvas-syndrome by giving you a chord base to start working with.

dust

Miscellaneous

Items

I've started working on the item system, which is very simple at the moment (and hopefully will stay that way). To manage the items I created an Item Editor, which, though a lot simpler than the Sequence Editor, is just as useful.

Item Editor

Blender scripts and templates

Blender's also been nice to work with because of its support for Python scripts. It's a little clunky to get things integrated, but can be powerful once you're going. In my case I'm mostly using a "quick export" script that helps me avoid the tedious work of keeping exported files organized (navigating to the correct folder, setting the filename, etc) and double-checking my export settings are correct. In the case of items, which require a static icon to show in the UI, the export script automatically exports a properly-cropped render of the item to the item icons folder so I don't have to bother with that at all.

Another small but immensely helpful thing is having a specific template for Fugue modeling work, with materials, cameras, and what not preconfigured. My material settings change very infrequently; I'm usually just swapping out textures, so this saves me a lot of time configuring materials over and over again.

Dialogue Layout System

Not really a tool, but something I've been refining for awhile now. This is the system that determines where dialogue boxes are placed on screen. Many games have a fixed dialogue box, e.g. at the center bottom of the screen, but I want it to feel more spatial, especially as there won't be any voiced lines in the game (too expensive/too much work/difficult to change and iterate on) so there won't be any 3d audio to offer that auditory depth.

Dialogue from Breath of the Wild

As far as I know there is no easy or reliable way to layout rectangles in a 2d space to guarantee that there are no overlaps. Not only should there be no overlaps, but each dialogue box should be reasonably close to its "host" (the actor that's speaking) so that it's clear who's speaking. I have a reasonable expectation/constraint for myself that something like five at most actors should be speaking at once and the game has a minimum viewport size to ensure there's a reasonable amount of space. That is, I'm not expecting that overlaps will be impossible, only that they are unlikely given these constraints.

The approach I'm using now is using a fixed set of anchors for each object and a quadtree to detect collisions. We just try placing a box at one of an object's anchors, and if it collides with an existing dialogue box or object, try the next anchor.

Dialogue layout prototype

As you can see from the prototype above (on-screen objects are beige, off-screen objects are grey, and dialogue boxes are black), it's not perfect. The box 8 at the top overlaps a bit with object 2 — this is due to how dialogue boxes for off-screen objects are handled, which could be refined, but I'm treating as an acceptable edge case for now.

Another shortcoming is how 2d bounding boxes are calculated from 3d objects. Basically I compute the bounding rectangular prism around the object and project that to 2d space. Depending on the shape of the object that may work well or it may end up placing an anchor far-ish from the object's mesh. You can kind of see it in the screenshot below, the "I'm on the move" dialogue box is meant to accompany the smaller NPC, but it's kind of far away. Tighter bounding boxes might be possible but I'm worried about the overhead they'd require. Something to look more into.

Dialogue layout system in action

Unit Testing

Godot doesn't have its own unit testing framework but there are two popular third-party options: gdUnit3 and Gut. They both seem fairly powerful but Gut felt a bit clunky and I couldn't get gdUnit3 to work properly (compile errors, which I chalk up to Godot's weird stochastic-feeling nature, more on that below). I ended up writing my own very simple testing framework instead. It lacks basically all of the advanced features present in other testing frameworks (spies, mocks, etc), but for my needs it's working great.

Tester

Things not covered here

There are still a few key content areas that I don't have a good approach for:

  • Character animation. This is something I'm not very good at and a huge factor in the visual quality of the game. Crunchy textures and low-poly models are a lot more forgiving than terrible animations. There are now deep learning motion capture tools that might work with a commodity web camera, but I haven't tried them yet so I don't know if their output is good and what the workflow is like.
  • Mapping textures. Taking a texture and then adjusting a model's UV map so that it doesn't look warped is also really, really tedious. No idea how to streamline that.
  • Object modeling. This is harder to streamline/automate because there's so much variation. Some categories like buildings and plants could be streamlined through procedural generation via Blender's geometry node system. Fortunately I enjoy modeling so I don't really mind doing this, it'll just be very time consuming. One more general possibility is to figure out a decent processing pipeline for taking free models and converting them into an polygon count that matches everything else. But finding an approach that is robust enough seems unlikely.
  • Character modeling. To make the world feel lively I'd like to have many, many background characters and a fair amount of more important NPCs. This might be doable with some kind of procedural/parameter character variation system (i.e. creating a few key archetype models, then having a script to vary some vertices, scales, etc) alongside with a procedural texture generation system (for clothing, etc). Again, this might be doable with Blender's geometry node system.

Thoughts on working with Godot

I've spent a far amount of time with Godot while working on all of this. My only reference point is Unity, which was very unpleasant to work with. Everything felt so fragile. Small changes can break tons of other things, with no easy way to undo the damage. Kind of like how in Microsoft Word adding a space can mess up your whole document's layout.

Godot has overall felt better than this, but it still has a similar, if reduced, fragility. I've felt discouraged to experiment with new ideas out of the fear that I will just break a bunch of existing code/scenes and have to manually fix everything. I've found that even just opening a scene file can alter its contents—not yet in a way that has caused me trouble, but it's still very different than other programming work I've done, where things really only change if you change them. It's like trying to build a house on moving ground. Version control is a bit of a safety blanket but its effectiveness depends on what changes I can revert to.

GDScript has been a surprisingly pleasant language. It still lacks many features I'd like like sets, first class functions, and iterators (all of which I believe are coming in Godot 4) but usually those haven't been an issue. What has been very frustrating is how Godot parses/compiles scripts. If you have a syntax error in one file it ends up breaking a bunch of other files that depend on it (which is to be expected) but it reports these issues as obscure errors that don't point to the originating error. I'll be inundated with messages like The class "YourClass" couldn't be fully loaded (script error or cyclic dependency). (it will not point you to what this error might be) or mysterious errors like Cannot get class '_'. repeating several times. Then it requires a painful process of trying to figure out where the syntax error actually is by opening scripts one-by-one until I stumble upon it.

This is less likely to happen if you're using Godot's built-in script editor because you're more likely to catch the syntax error before it causes too much trouble. However Godot's built-in editor is really lacking, mainly because you can only have one script open at a time and if you need to edit multiple files at once it requires a very tedious process of manually jumping between files one at a time. So I use an external editor, which does have a language server integration with Godot—so it does catch syntax errors, but sometimes I don't catch them in time, and then these dizzying cascading errors happen.

I've also noticed that sometimes there will be compile errors that are fixed by reloading the project. It feels like these happen because of an unusual (sometimes seemingly random) parse order for scripts, like classes are found as undeclared when in fact they are. I haven't looked into it too much.

That all being said, Godot has been wonderful to work with overall. These frustrating experiences are infrequent, and it sounds like many of them are being addressed in Godot 4. I've enjoyed it way more than Unity and it's an amazing privilege to have access to such a powerful open-source project!


Log: 7/16/2021

07.16.2021
log

This week: low-density ancient urbanism, an extraction-free Atacama Desert, AI and climate change, and Wakanda.

3d view of Tikal (PACUNAM/Marcello Canuto & Luke Auld-Thomas, via NPR)

The real urban jungle: how ancient societies reimagined what cities could be, Patrick Roberts

Most cities around the world, while still considerably varied, seem to have comparable density, layout, and land-use. The ancient tropical cities of the Khmer and Classic Maya empires were more sprawled and interspersed with agricultural plots and "forest gardens". In general they sound more integrated with the environment—perhaps easier because unlike the cities that would come later they were not yet inundated with toxic industry. Whether or not the impact of urban living shakes out to be an environmental net positive or negative is something I've meant to read more about but yet haven't gotten around to. But these examples of different forms of urban life are nice to think about, even if they occurred under tremendously different circumstances.

Lithium Landscapes: From Abstract Imaginaries to Deep Time and Multi-Scalar Topologies, Samir Bhowmik

A reflection on the vast timescales that give rise to lithium and the earthbound terraforming (human extraction of) lithium gives rise to. I especially like this painting:

Lithium Fields by Mafalda Paiva. (Image copyrights belong to Mafalda Paiva)

Portuguese artist Mafalda Paiva's painting Lithium Fields, which depicts the Atacama Desert reminds us of what could have been—a paradise instead of an extractive landscape. In the artist’s vision, “the salt flats hum with a preternatural vibrancy, an effect produced by the exaggerated density of species and radically foreshortened topography.”

These Are The Startups Applying AI To Tackle Climate Change, Rob Toews

I'm skeptical that AI can be applied to substantially help mitigate climate change. There are specific applications that seem to be useful, e.g. around power efficiency, the development of new materials, etc. It probably has a role to play but hard to say whether it will be much more than other technologies treated with far less fervor—this article breathlessly states: "Artificial intelligence is the most powerful tool that humanity has at its disposal in the twenty-first century."

I wonder if the wide proliferation of AI that many of its proponents either foretell or actively try to engineer through their own companies/investments will net out positive or negative in terms of carbon, given the intense energy requirements to train the largest, most sophisticated models. If AI is commodified and so as unnecessarily ubiquitous as microchips then perhaps it'll come out net positive emissions.

This list of companies claiming to use AI against climate change is interesting, especially because it reveals what it means to publications like Forbes to "tackle" climate change. Several of the companies are focused on identifying climate risks or managing climate insurance for businesses. A great deal of time is spent companies applying AI to carbon offsets, which looks more like companies bending over backwards to legitimize a completely ineffective/actively harmful way of "addressing" climate change rather than actually working to reduce their emissions. The "solution" to offsets sounds like more surveillance infrastructure.

Wakanda

I'm not a big fan of the MCU, but the creation of a cinematic universe opens up a lot of storytelling and character possibilities so I reluctantly follow along every so often to see what they're doing with that capacity. I wish it were some other more interesting, less indulgently militaristic fictional universe that had the resources to do something like that. Instead we get Marvel and soon the Mattel Cinematic Universe.

Ever since I found Wakanda listed as a US free trade partner I wondered how Wakanda might relate to other countries and how people outside perceive it. While reading Doomwar I came across this off-handed mention from Shuri:

I'm so curious about the terms of that loan. The first Black Panther movie wrestled a bit with Wakanda's responsibility towards its neighboring nations or developing nations (as it used to posture as) but if I recall it never really answered that question. I haven't watched Black Panther recently so forgive any misremembering, but I believe Killmonger was just defeated without any satisfying resolution to his analysis/proposals about spreading Wakanda's wealth. IIRC he proposed distributing vibranium for uprisings across the world—even if T'Challa disagreed with violent uprisings, maybe the spreading of that wealth is worth considering. Although given what Shuri says here, maybe that's exactly what they're doing. But again, I wonder on what terms?

I wonder if in some ways the now-opened Wakanda is perceived in similar ways to how China is perceived in our world. I don't know what it takes to qualify as a "superpower" but I imagine Wakanda checks off many of those boxes. Surely many people in the MCU pin their hopes on Wakanda to usurp the planetary hegemons...sadly, they'll probably be disappointed.



Log: 6/05/2021

06.05.2021
log

This week: Comfort with contradictions, anime and Gen Z

Dialetheism and Eastern Philosophy

We recently finished watching The Good Place, which was very sweet. Overall I enjoyed it, but there was one plot hole that I was disappointed to see left unaddressed, I'll leave it in the footnotes to avoid spoilers1.

The other disappointment is the show's heavy (maybe exclusive) reliance on Western philosophy2 I don't really blame the show for this because it's just an enormous problem in how philosophy is taught in general. Something else that would have been nice to include is a reckoning with the extraordinary racism of Kant (see the previous link for some examples).

That's all to say that after the show I wanted to read more on non-Western ethical systems. This interview introduced me to the idea of "paraconsistency" and I got sidetracked into reading about dialetheism, which is the view that statements can be both true and false (in orthodox logics statements can only be one or the other; such inconsistencies "explode", i.e. entail everything to be true). The simplest example is the Liar's Paradox, which in one sentence is "this statement is false". My understanding is that under dialetheism this statement is not a paradox and to be rejected but accepted as-is.

As the SEP entry on dialetheism explains, dialetheism shows up a lot in Eastern philosophies (as well as in Western philosophy: dialectics, for example). The Daodejing and Zhuangzi are riddled with them. "The Way of the Dialetheist: Contradictions in Buddhism" (Yasuo, Garfield, Priest) gives an overview of how dialetheism shows up in Buddhism, describe some interpretative possibilities: are they presented as literal/true, or are they used as rhetorical/pedagogical tools for insight (as in Zen)?

My own understanding is usually that these apparent contradictions are not actually the case—for example, a common form is to say that thing X has property Y and Z such that those simultaneously having two properties is inconsistent/impossible, which I often take to mean "thing X" refers to our term for X and not X itself; and that in fact that term refers to two things that are different. For example, "race is real and not real" could refer to how race is not "real" as in it is an immutable part of the universe but is still "real" as social reality—as something that feels total and inescapable in our lives.

But this interpretation doesn't work in many cases. When Buddha says "the ultimate truth is that there is no ultimate truth", that seems to be more of a straight-up contradiction.

Welcome to Planet Egirl, Cecilia D'Anastasio

I definitely feel old given how much more I've been reading about subcultures through publications like Wired rather than experiencing them. But I'm struck by how much anime has influenced Gen Z and how visible/trendy it is, whereas for my generation it was an almost clandestine activity. Ariel brought up a good question: is this a popularization of Japanophilic culture or is anime being separated out? Anime production is still more or less the exclusive domain of Japan as far as I'm aware.



  1. To get Michael to understand human ethics they have him confront his own mortality, which I take to mean that human ethics is grounded human mortality. But once you're in the afterlife, you're no longer mortal. So why would you still be judged according to an ethical standard that no longer applies to you? 

  2. I hoped that the afterlife-ending gateway would actually lead them to be reincarnated; it would have been a nice gesture at non-Western conceptions of the afterlife and set a stage for introducing different ethics systems. 


Log: 5/28/2021

05.28.2021
log

This week: The secularization/Westernization of Buddhism, IDEO, UFOs/UAPs, and #fixingfashion.

Questions on the origins of Buddhist concepts and Is secular Buddhism looked down upon in the Buddhist community?

Very interesting to read these threads on secularized/western Buddhism—which tries to "sanitize" Buddhism of its more fantastical elements. The western presentation often boils down to something like: "life is suffering, suffering is driven by desire, end desire to escape suffering". Maybe the notion of karma remains because it's in line with other western folk wisdom (e.g. "what goes around comes around"), but other elements like rebirth or that the Buddha had supernatural insight/powers are dismissed as nonsense. Even what it means to be "enlightened", as one commenter notes, is different under this secularized view: "Do you imagine that enlightenment just means feeling calm?". Maybe this kind of secularization or tampering down is a typical course for religions—thinking about secular Jews and most Christians I've met don't believe angels are real—but with Buddhism in particular it has strong colonialist overtones (usually from white people and with some implication that people who do believe in the supernatural elements are backwards/ignorant for doing so—unenlightened in the sense of "the Enlightenment").

I don't necessarily mind secular Buddhism as a concept (the problem is more the industry around it and its extractive/appropriative nature) but it's this attempt to re-write the historical image of the Buddha to conform to those beliefs—such that there exists an "authentic Buddhism" that does away with the elements you don't like—that is upsetting.

Surviving IDEO, George Aye

I worked at IDEO almost a decade ago—it was my first "real" job out of college, and so I didn't have any prior office experience to compare things to, but it was clear that there was a lot of kool-aid to drink and a lot of people drank it. I joined as part of a new team that was separate from the company's typical design consulting work (we were brought into help out with specific technical needs here and there) and so I was fortunate enough to be insulated from a lot of the broader office politics, pettiness, and discrimination outlined in this piece. Given the general lack of self-awareness the place has—e.g. speaking really highly of its practice as world-transformative but basically doing little but intensify capitalism's entrenchment in all aspects of our lives1 (I remember quite a bit of the work was basically creating new luxury offerings for financial institutions)—what's outlined here is sadly not very surprising.

Related to this topic: I recommend "It's Not You, It's the System" by Janani Balasubramanian. This piece was helpful for me in deciding whether or not to quit IDEO.

How the Pentagon Started Taking U.F.O.s Seriously, Gideon Lewis-Kraus

As a kid I liked the idea of extraterrestrial life and thought things like Fermi's Paradox and the Drake Equation were really fascinating (although the Drake Equation seemed almost arbitrary/impractical). A number of games I played growing up also built stories around aliens, like Dinosaur Safari (aliens going back in time to document dinosaurs) and The Journeyman Project 3: Legacy of Time (an "ancient aliens"-style game set in the mythical cities of Atlantis, El Dorado, and Shangri-La that, though the story was based around aliens, taught quite a bit about the actual ancient cultures these cities were inspired by). But aside from reading about these topics here and there I never got very deep into UFOs and the like. It felt like a cliff's edge into unsubstantiated and woo conspiracy theories. At the same time, it seemed reasonable that there would be some phenomena that is difficult to explain, and that in itself was interesting without needing to jump to the conclusion of aliens. This article explores that latter space, and also goes over a campaign meant to consign UFOs and an interest in them into the former conspiratorial category (read: "crazy"), effectively making the topic untouchable if you want to be considered legitimate. I'm skeptical that anything really earth-shattering will come out of June's UAP report but who knows, maybe something interesting will happen.

#fixingfashion videos

A really well-produced and comprehensive series on how to take care of your clothes, repair them, and modify them:

A bunch of my clothing recently got several rips, and repairing them has been a nice way to keep my hands busy on long meetings.

Here's the most recent repair I did—you can see the smaller yellow patches where I underestimated how large patches actually need to be relative to the size of the hole. The edges of those patches ended up tearing, leading to the substantially larger sashiko patch there now.

Repaired sweater



  1. You could maybe point to IDEO.org as a counter-example but I'm not really familiar with their work and I'd guess they have their own issues. 


Fugue Devlog 13: More World Modeling

05.14.2021

Very busy with some other things so not much progress as of late. I've mostly been modeling more assets for the world map, which has forced me to think more thoroughly on what each city might look like. I don't feel totally ready to commit to anything I've made yet though.

Modeling and texturing are very time consuming processes, even with the low-res look I'm going for. I'm convinced that 99% of the time spent working on the game will be modeling and texturing.

I find modeling very meditative and enjoyable, though for the map the things I've been modeling are much bigger (e.g. buildings and cities), and for some reason that's a lot more daunting. It might be because larger objects need more details to look convincing. Modeling smaller objects is a lot nicer.

One thing that hasn't helped is that Blender (2.92) constantly crashes. I'm not sure what the cause is because it doesn't save a crash log.

Texturing is the slowest part of the process. Building the textures can be time-consuming: collecting the images, processing them and then assembling them into a single texture, editing parts to be seamless, etc. Most if not all of this can't really be automated or streamlined much further than they already are. One thing I'm trying to keep in mind is that because of the low-res style I can usually get away with low-resolution textures, which makes searching for appropriate ones a lot quicker (in particular: stacking islands together—kind of baffling that this isn't a part of Blender).

I'm also still learning workflow tips for faster UV editing. Blender's built-in UV editing tools are also kind of lacking, but I learned of TexTools which has helped make some aspects of it a lot quicker.

I'm also experimenting with how much I want to rely on free 3d models from elsewhere. For the megaflora on the map (see below) I'm using this model of a borage flower (organic shapes are harder for me to do quickly) but processing and editing it to better fit into the game also takes a decent amount of time.

Megaflora on the map

This city, inspired by the Ganden Sumtsenling Monastery that I visited many years ago, was so tedious to texture, mostly because I was selecting and positioning faces in a really clumsy way:

Tiantai on the map

This pagoda was pretty quick to model, mostly because the UV editing is relatively simple, but also because I'd started using TexTools:

Dagu Pagoda

I'll spend some time watching videos on more UV editing tips to see if I can make the process less tedious.

I also wrote a bit about some of the thinking behind the game for the Are.na blog.

<< >>