86. The Game’s Not Dead!~

Very short update, but I wanted to keep things alive around here. Things are still coming along well and the list of music that needs to be written is getting very short now.

I have taken a job full time through the week, mostly because I already had the job lined up for after Taiji’s release and even though the job starting itself was delayed, Taiji’s release was delayed more. I chose to take the job anyway because I didn’t want to miss the opportunity and I really don’t have much I still need to be doing day-to-day personally leading up to the initial release. I’m mostly just directing Gregory on the music and doing occasional tech stuff for the music. Gregory has been fantastic to work with, he has a deep understanding of the game, and has the remaining music writing well under control.

I have still been trying to use the time to polish more and contribute to the soundtrack where I can, but after a rough couple weeks of trying to squeeze in Taiji stuff during the week, I’ve moved to just working weekends on Taiji, at least until after release.

Speaking of release, I know I keep saying I’ll have something to announce on that front soon, but I really do mean it now. Soon is even sooner than it’s ever been before. In fact, I can announce that I will have something to announce on August 12.

Practically SOON I say!

As for the switch port, it was always the plan to focus on the PC release first, and then the serious work on porting will start after I’ve fixed up any unforeseen bugs that happen when the game gets in the hands of you all.

Look forward to the announcement on August 12 and thanks again for your patience!

85. Delays, New Music, and Parsing

Today I finally finished up the ending related stuff I’ve been talking about for months. This was the last major task before I could ship the game. Except that I’ve just decided to add a bunch more tasks to the list.

It’s a bit of a long story, but one of my testers, Gregory Bednorz, has gone from writing a bit of guest music for the ending to being heavily involved in helping me improve and expand the rest of the music in the game. You can see a bit more about that and hear some samples of the new music (and the old!) in the latest video devlog:

I don’t want to rehash everything that I discussed in the above video, although I will say that I am still weighing different options as far as whether the game should release in some way before the new music is finished. There are reasons to release early and reasons to wait, and I am not 100% decided yet.

I was hoping to be a little less “all tech deep dives all day erry day”, but with that said, I think it could be enlightening to some to show how simple it was for me to implement a composer-editable configuration file format for the new music system.

I felt that the results would be better if Gregory was not only composing music tracks, but was also involved in the implementation of the tracks into the game. But since I didn’t want to send the whole Unity project back and forth or attempt to institute some type of version control system this late in development, I felt it would be good to have a configuration file system and dynamic asset importing.

The dynamic asset importing was actually more of a challenge than the parsing, so perhaps I will come back to that another time. Suffice to say that the development version of the game pulls in .wav files and generates a set of configurable audio layers based on the filenames. Then these filenames can be referenced and set up in a configuration file as follows:

zone Orchard1
{
    osc_frequency_low 0.03
    osc_frequency_high 0.07
    osc_transition_interval 10
    osc_transition_duration 3
    
    add WindLow
    add Orchard_FlutePadsLow
    add Orchard_MatthewFluteSolo
    
    tweak Orchard_MatthewFluteSolo offset_volume 0.5
    tweak WindLow osc_low_volume 0.1
    tweak WindLow osc_high_volume 0.4
}

layer WindLow
{
    osc_low_volume 0.03
    osc_high_volume 0.25
    offset_volume 0
    wind_edge_influence 0.5
}

layer Orchard_MatthewFluteSolo
{
    osc_low_volume 0
    osc_high_volume 0.1
    offset_volume 0.4
    wind_edge_influence 0.2
}

layer Orchard_FlutePadsLow
{
    osc_low_volume 0.31
    osc_high_volume 0.44
    offset_volume 0
}

The way that this works, is that you set either a target zone or layer and then you configure settings for the target. Zones are areas in the world that contain only certain layers of the music and oscillate the volume of those layers up and down over time. Layers are just looping music tracks that have a volume that is tied to the high and low points of the current zone’s oscillator. The oscillator itself is just a sine wave which periodically blends into a new random frequency. This allows the music to change dynamically over time in a somewhat unpredictable way.

So, now let’s talk about parsing.

The main way that I kept parsing simple was that I decided that all state would be confined to individual lines, with only two exceptions: the current zone and the current layer. The brackets and indentation are purely for readability purposes and are ignored by the parser.

Because the inline code viewer on wordpress is horrible, and the pastebin one is slightly less horrible, here is a link to the entire relevant bit of code on pastebin.

The first thing that we do in terms of parsing is to point the C# standard StreamReader class at the file. I’m definitely not claiming this is the best or the most efficient way to parse a text file, but it’s what I’m familiar with from the save system, so I chose to reuse it here:

StreamReader sr = new StreamReader(file);
string line = "";
int active_line_index = 1;
while(sr.EndOfStream == false)
{

Once we get past this, we are now in the main loop, which is repeated for each line. First we create a cleaned version of the line by trimming any leading or trailing tabs and spaces.

stored_identifier = "";
line = sr.ReadLine();
line = line.TrimStart(' ', '\t'); //trim tabs and spaces
line = line.TrimEnd(' ', '\t');
int remainingChars = line.Length;
bool already_added_tweak = false;

Now we begin parsing through the line itself and breaking it down into tokens. A token is essentially just any single “word” in the file, so its just the next bit of text until there is a space. So we take the subset of the line until the next space and store that in a token string so we can interpret it later.

while(remainingChars > 0)
{
    string token;
    int tokenEnd = line.IndexOf(' ');
    if(tokenEnd == -1) 
    {
        token = line;
        tokenEnd = line.Length;
    }
    else token = line.Remove(line.IndexOf(' '));
    remainingChars -= token.Length;
    if(tokenEnd+1 < line.Length)
    {
        line = line.Substring(tokenEnd+1);
        remainingChars = line.Length;
    }
    else remainingChars = 0;

Now, we match the string against a set of keywords: #, zone, layer, add, tweak. The # is just a comment marker and is set to discard the rest of the line past it. The others all manipulate a line-level state variable which will be used in order to interpret the next token. If the token matches one of these keywords then we set the line-level state and parse out the next token on the line based on that state.

switch(token)
{
    case "#":
        remainingChars = 0;
    break;
    case "zone":
        state = states.SET_ZONE;
    break;
    case "layer":
        state = states.SET_LAYER;
    break;
    case "add":
        state = states.ADD_LAYER;
    break;
    case "tweak":
        state = states.TWEAK;
    break;
    default: //identifier, action depends on current state

When the token doesn’t match any of the keywords, this means it must be parsed differently depending on the current state. If we’ve already parsed a token on this line, and for example, that first token was zone, then the state will be SET_ZONE and we will parse the next token as though it was the identifier of a music zone that we want to set to be the target for future modification. This target, c_ActiveMusicZone, along with c_ActiveMusicLayer are the only state that is allowed to persist across multiple lines.

switch(state)
{
    case states.SET_ZONE:
        MusicZone targetZone = FindMusicZone(token);
        bool created_new_music_zone = false;
        if(targetZone == null) 
        {
            targetZone = new MusicZone();
            targetZone.name = token;
            created_new_music_zone = true;
        }
        if(created_new_music_zone) musicZones.Add(targetZone);
        else
        {
            targetZone.tweaks = new List<Tweak>();
            targetZone.layers = new List<MusicLayer>();
        }
        c_ActiveMusicZone = targetZone;
    break;

And we do the same if the first token was layer or add, setting the active music layer or adding a music layer to the active music zone, respectively.

case states.SET_LAYER:
    MusicLayer targetLayer = FindMusicLayer(token);
    if(targetLayer == null) 
    {
        Debug.LogError("File: "+file+" Line: "+active_line_index+" Attempted to set a Music Layer active that does not exist! Please verify that the names match.");
    }
    else c_ActiveMusicLayer = targetLayer;
break;
case states.ADD_LAYER:
    MusicLayer targetLayer2 = FindMusicLayer(token);
    if(targetLayer2 == null) 
    {
        Debug.LogError("File: "+file+" Line: "+active_line_index+" Attempted to add a music layer that does not exist! Please verify that the names match.");
    }
    if(c_ActiveMusicZone != null) c_ActiveMusicZone.layers.Add(targetLayer2);
break;

The next possible keyword and state would be tweak, which is a way for a zone to override the settings of a specific layer. This makes things a bit complex, because we have to parse out an identifier for tweaking as well as a value, which somewhat duplicates the default path when the token doesn’t match any keywords. I’ll confine the explanation of identifiers to that path, but here’s the tweak-related code anyhow:

case states.TWEAK:
    if(already_added_tweak == false)
    {
        c_ActiveTweak = new Tweak();
        c_ActiveTweak.target = FindMusicLayer(token);
        if(c_ActiveTweak.target == null)
        {
            Debug.Log("File: "+file+" Line: "+active_line_index+" Unable to find target for tweaking \""+token+"\", perhaps it is misspelled?");
        }
        already_added_tweak = true;
    }
    else
    {
        if(c_ActiveTweak != null) //we only parse the rest of the line if we successfully found a tweak target
        {
                
            float value1;
            if(float.TryParse(token, out value1))
            {
                c_ActiveTweak.value = value1;
                switch(stored_identifier)
                {
                    case "osc_high_volume":
                        c_ActiveTweak.type = tweakType.OSC_HIGH_VOLUME;
                    break;
                    case "osc_low_volume":
                        c_ActiveTweak.type = tweakType.OSC_LOW_VOLUME;;
                    break;
                    case "offset_volume":
                        c_ActiveTweak.type = tweakType.OFFSET_VOLUME;
                    break;
                    case "blend_duration":
                        c_ActiveTweak.type = tweakType.BLEND_DURATION;
                    break;
                    case "wind_edge_influence":
                        c_ActiveTweak.type = tweakType.WIND_EDGE_INFLUENCE;
                    break;
                }
                if(c_ActiveMusicZone != null) c_ActiveMusicZone.tweaks.Add(c_ActiveTweak);
            }
            else stored_identifier = token;
        }
    }
break;

Next we have the general case, which is when we didn’t match a keyword like layer, tweak, or add. In this case, it’s assumed that the token is an identifier for a variable or the value that we want to set a variable to. So first we attempt to parse the token as a value, and if that fails then we store the token as the identifier of a variable which we will set after we parse the next token on the line. There is no overlap between layers and zones when it comes to the names of variables, so as long as there is a current active zone or active layer, we can set the appropriate values just based on the identifier.

default:
    //we must assume that the token is intended to identify a variable or a value, so we will check against a list of known variable names
    float value;
    if(float.TryParse(token, out value))
    {
        switch(stored_identifier)
        {
            case "osc_frequency_low":
                if (c_ActiveMusicZone != null) c_ActiveMusicZone.osc_frequency_low = value;
            break;
            case "osc_frequency_high":
                if (c_ActiveMusicZone != null) c_ActiveMusicZone.osc_frequency_high = value;
            break;
            case "osc_transition_interval":
                if (c_ActiveMusicZone != null) c_ActiveMusicZone.osc_transition_interval = value;
            break;
            case "osc_transition_duration":
                if (c_ActiveMusicZone != null) c_ActiveMusicZone.osc_transition_duration = value;
            break;
            case "osc_low_volume":
                if(c_ActiveMusicLayer != null) c_ActiveMusicLayer.osc_low_volume = value;
            break;
            case "osc_high_volume":
                if(c_ActiveMusicLayer != null) c_ActiveMusicLayer.osc_high_volume = value;
            break;
            case "offset_volume":
                if(c_ActiveMusicLayer != null) c_ActiveMusicLayer.offset_volume = value;
            break;
            case "blend_duration":
                if(c_ActiveMusicLayer != null) c_ActiveMusicLayer.blend_duration = value;
            break;
            case "wind_edge_influence":
                if(c_ActiveMusicLayer != null) c_ActiveMusicLayer.wind_edge_influence = value;
            break;
            default:
                Debug.LogError("File: "+file+" Line: "+active_line_index+" Attempting to modify an unknown variable, please verify the name!");
            break;
        }
    }
    else stored_identifier = token;
break;

And that pretty much covers the parser, apart from that we reset the state between lines and increment the line counter so we can report errors a bit more helpfully.

Is it even remotely bulletproof? No. But for something quick and dirty that was mostly written in a day, I think it gets the job done, and hopefully can serve as somewhat of an inspiration against the idea that one should always “just use JSON” or that “parsing is hard”, or whatever other nonsense excuse you might have to not just write your own format.

If I were to think of some things that definitely could be improved, the main would be making sure that all error cases are handled better. For the most part, the format is simple enough that even if there is a major error, the file should still parse for the most part and just report the error without putting the game into a broken state. However, there may be some error states which I am not reporting, which could bite us in the butt on down the line.

Another avenue for improvement would be to have a file version marker. Since I expected these files to be human edited, I didn’t want to mark up all of the variables with some type of version information, but at least a file level version marker could be useful if there are some changes to the format that I want to make. This could facilitate automatic conversions of older files to a new format. With that said, this is a relatively minor concern, since there’s really only Gregory and myself working with these files, and I can easily just convert the files and pass them back to Gregory.

84. How I Design Puzzles

This post was adapted from an answer to one of my playtesters questions:

What methods do you usually use to design this game’s puzzles, and which of those methods do you think lead to the best (most enjoyable?) result?

There are three main approaches to designing puzzles in this type of game that I’m aware of.

1.Top-Down Method

This approach starts with the solution state and works backwards to constrain the puzzle so that this is the only solution.

This is an approach which I very rarely, if ever, have used in Taiji. There can be some valid reasons to choose it–if one is in a tight spot and needs to solve another design problem perhaps–but generally you don’t have much luck making good puzzles with this approach.

As a caveat, all design approaches include at least some “top down” elements. For example, one has to pick an idea that seems interesting in the first place. Though it should be easy to see the difference between “this point is connected to this other point” as a top down imposition, and “this is the exact path that you take to get there”. So the problems of this approach often come with the extent to which it is applied. Keeping things in balance I think is a theme that will be clear through this discussion.

Also, if I move to include the observational puzzles in the game, you could argue that those are fully top down designs. But since those puzzles are more about observation or abstracting something in the environment than they are about logic within a grid, the design approach is different. This discussion will be long enough just focusing on the logic puzzles, so I’m going to have to leave the topic of environmentally-clued puzzles undiscussed for now.

Moving on to the next approach.

2. Experimental Method

In this approach you basically just plop down some random things and see what happens.

This sometimes produces good puzzles, but it’s difficult to make larger puzzles that have good solution paths through them. Getting good puzzles this way is mostly down to luck, and with smaller puzzles you just tend to have better luck. Regardless, this approach is the only one you can take early on, since when you are still adding new mechanics to the game, you still have a lot to learn about how your own game functions.

Another downside to this approach that perhaps just affects me personally, is that when just plopping things down randomly, I tend to draw symmetrical shapes because they “look nicer.” Unfortunately this also tends to create symmetrical solutions in Taiji. This is still in the game often enough that players can notice the pattern, but I’ve worked hard to make sure that it is not a universally applicable tactic. It’s okay to have symmetry show up sometimes, as it is thematically appropriate, but too many times and the game falls flat.

And the final design method.

3. Forwards Method

This is the trickiest to explain. Here is a link to a long form explanation and example, but the basic gist is that you start with some deducible situation and place that into the puzzle. You can then add more deductive moves into the panel, creating as much specificity as you want.

This method is useful because it gives you the most control over the players path through the puzzle. You are designing the moves that they will make in the order they will make them.

With that said, it is a tool that must be used with care. Just because you can fully specify every tile in the solution doesn’t mean that you must. Sometimes leaving a little play in the puzzle is more interesting. In a pen-and-paper puzzle, you don’t want multiple solutions because the solver needs to check against a canonical solution in the back of the book, but in a video game you can be more flexible and you should.

Use your discretion as a designer and prune alternate solutions if they allow the player to miss the main idea of the puzzle, but there’s more than one way to skin an electric eel and part of the magic of video games is that they are a bit different for every player. Try to embrace that whenever your design goals allow it.

In the best case, the forwards design technique can allow you to focus your puzzle designs around strong core ideas. But in the worst case, it can lead to a flat feeling, where all puzzles become a sort of paint by numbers.

Still, it is the most powerful technique that I have learned over the course of designing Taiji, and even through it is dangerous, I think it is a requirement to have this tool in your toolbox. It’s just important to remember that you are designing puzzles to serve the overall game design and not to serve the tool.

My Approach

So I mostly use a combo of methods 2 and 3; the experimental and forwards methods. But I think the best puzzles tend to come from a mixture of forwards design and some happy accidents. There are also meta aspects that I could get into which can really take puzzles to another level, but I’ve gone on long enough so that will have to wait for another time.

In any case, over time I have leaned more towards judging puzzles by their content instead of by their enjoyability. I think this is a more stable approach once one becomes more sure of themselves as a designer. However, this does sometimes lead to situations like one I had the other day. There is a particular puzzle in the game that I always loved, but which I have come to realize many players find annoying. I was so convinced that the idea for the puzzle was good, that I didn’t worry too much about its enjoyability. Sometimes this is a good approach, however in this case, my disregard for the enjoyability of the puzzle led me to overlook its failure to communicate any appreciation for that core idea. Players found the way in which I was presenting the idea so repulsive that they came away finding the idea itself repulsive.

I knew the idea was good though, so yesterday I went back to the drawing board and designed a new introduction to the idea.

So, as with all game design, be sure to test your design theories against reality and see if you’re getting an acceptable response. Not everyone has to enjoy every puzzle, but if most people hate a puzzle that you’re in love with, then perhaps there is something about the way you presented that idea that could be improved.

As an aside, I want to mention the two biggest mistakes that I see other designers make. The first is not listening enough to others early on in their careers, and the second is listening too much to others once one becomes more established. When you’re starting out, you don’t even know what you don’t know, and it’s more likely than not if someone has a criticism of your game, that you probably should change something. However, as you develop skill and experience as a designer, it is important to learn what your own tastes and values are, and accept that sometimes these will conflict with those of other people who play your game. Accepting feedback and having a guiding vision are both important forces to keep in balance.

Conclusion

In summary, I think the best puzzles are the ones that have a strong idea at the core of them. Something that can be verbalized like “this puzzle shows you that when X and Y are the case that Z occurs” or “this puzzle is about carefully interweaving 4 things while maintaining symmetry” or “this puzzle introduces this new mechanic, but requires the player to deduce its meaning by virtue of it being the only possible explanation”.

I haven’t always lived up to this standard with every single puzzle in the game, but when I haven’t, I have at least made sure that the puzzles serve a pacing reason or form a sequence or meta-structural element that has some unique interest to it.

And well…sequences and meta-structure can add immensely to the enjoyment of a puzzle game, but that’s a whole additional discussion which will have to come at a later time.

Elyot Grant’s 30 Puzzle Design Lessons, Extended Director’s Cut – This is a fantastic resource, and although lengthy, is an extremely enjoyable watch as well.

83. In The Final Stretch

I recently finished one of the two biggest remaining tasks on the to-do list and I’ve been celebrating a bit by working on some less important polish related things. Sometimes I find it difficult to immediately jump from one big challenging task into the next, and it can be good to take a break while still being productive on other things.

Early on, I figured out much of the art direction for Taiji, and most of those decisions I have stuck with until the end. But there were a few things that I changed as I went through the project. A big one of those was how to handle interior lighting.

I always knew that I wanted to have seamless transitions from the outside world into the inside world. Most top-down 2D games have separate maps that you load into when you go inside, and I wanted to avoid that. You can see an example of a typical building exterior and interior below (notice that the building is bigger on the inside!)

Although this example is nearly 30 years old, this is still the approach used in most top-down 2D games today. At the time of Link to the Past’s release, I imagine the choice mostly came from system limitations, but there are still a few good reasons to choose this approach today. One of those is that it’s just much more time consuming to keep everything seamless.

So if we don’t go into a separate screen, what happens when you go into an interior? We can’t just keep the roof of the building visible or we won’t be able to see what we’re doing once we’re inside. So instead I decided that parts of the building would be cut away to reveal the interior. Sort of like a diorama of the interior with a removable set of walls and ceilings. A big inspiration for this approach for me was the interiors of Final Fantasy 9, although the Sims games also use a similar approach and I’m sure someone will be able to name a more recent example.

You can see how this approach has turned out in Taiji below:

Although I nailed down the transitions relatively early, it took some time before I settled on a lighting approach. Initially I chose to do the interiors using the same method I use for exterior shadows. This had some downsides of course, in that things were either fully in shadow or fully lit, and trying to do smooth falloffs required dithering. There’s nothing fundamentally wrong with this approach, but it does have some drawbacks that will become more apparent.

When it came time to do some interiors without windows, such as caves, I felt that having the entire area be in shadow looked too flat. So I chose to have the cutaway also allow sunlight into the interior. Unfortunately this created an inconsistency between different interiors, but it at least allowed for some better definition and readability in these areas.

This was the approach I went with until it came time to do the Gallery area, where the interior was expansive enough that even this approach began to look strange. So I thought of a third approach that would allow me to have all of the features that I wanted.

I have briefly covered this approach before in this video devlog, but I will attempt to summarize here as I know not everyone wants to dig through a video.

So, the basic approach is that I have 3 separate “light maps” for the interior. One for the direct lighting coming from the sun, one for some rear bounce lighting, so that windows facing away from the camera can have some light come in, and a third that is for ambient or interior light sources, such as light fixtures or torches.

Each of these three maps is then assigned to the Red, Green, and Blue channels of a single image, with the alpha channel being used to mask off the effect completely. So the final lighting map would look like the following, alongside how it gets composited with the rest of the art in-game:

This is a very effective approach, and although it could perhaps be extended further to allow for darker shadows and brighter highlights, it is what I have settled on for the final game and I’m happy enough with it. The only problem is all those pesky old interiors which I did before I developed this approach.

They’ve been sitting around for a year or more at this point, but this week I’ve been going back through and updating them finally. It’s a more subtle difference in some cases, but I am glad to have things be more consistent. You can look at some comparisons below:

Notice in this case I needed to add some interior light sources, as well as change some other details of the art. Also the approach for “inside of rock” has changed since the old art was done and I updated the art to match that as well.

In this scenario, the difference is much more subtle, although you can notice that the dithering in the earlier lighting makes some of the symbols on the puzzle difficult to read. I also seem to have accidentally flipped some symbols since the earlier builds, so I guess that gives me something to fix real quick.

So, I have been mentioning that the game is close to complete and to expect a release date announcement soon, and I’ve been saying this for a few months now. However, the game has suffered a bit of an internal delay, and “soon” has turned into “not as soon”. With that said, I will once again reiterate that the game is close to complete and to expect a release date announcement soon!

82. Happy New Year!

Well, I didn’t get a trailer done before the new year, but things are still chugging along. I did want to remind everyone once again that I have a more-frequently-updated video devlog over on YouTube, if you’re not subscribed. Maybe I should have always been cross-posting those here, but I always found it a bit nice to keep the two devlogs separate, especially since some people prefer to just read or skim rather than sit down and watch a video. Here’s the latest episode of that if you do want to watch:

I’ve been continuing testing and polishing the game. There are still a couple major things that need to be done, but there are also dozens of minor problems that I’ve been clearing up.

One of those minor problems is readability issues in the environment. Sometimes it’s hard to tell where you can or cannot walk. For example, below is a before/after comparison of the cliff overlooking the Mine area. The player is standing at the edge of a several hundred foot drop-off, but due to a lack of contrast, it was often misread by players as being level with everything else. The added darkness creates a good contrast and foreground/background separation, and it also fades away when you enter into the area, keeping things readable from a gameplay perspective.

One of my art weaknesses is that I often don’t use enough contrast. Perhaps one excuse for my fear of contrast in doing the art for Taiji is that I wanted to avoid distracting noise. But this desire to avoid noise has unfortunately led much of the artwork to look very flat. I still think the art for the game is “good enough.” There’s no way I can go through and try to fix every single thing in the game at this point, but I’m trying to fix the worst spots. And moving forward it’s something that I’ll try to improve upon in future projects.

Hopefully I’ll have that release date announcement trailer to show you sooner rather than later, but I don’t want to put it out until I feel solid about a release date.

Thanks for reading!

81. Bonus Area

Over the course of making Taiji, I’ve designed many more puzzles than what have survived into the game as it exists today. Most were cut because they just weren’t very good. But there were some decent puzzles that had to be removed because there was no good way to fit them into the existing areas; they took up too much physical space or dragged out the pacing too much.

So for the past couple months I’ve curated those puzzles into a hidden bonus area. There are also a few puzzles that were custom built for this area to round out some of the missing spots in the overall design.

Finishing this area is a major milestone, and means that the game is basically gameplay complete. With that said there are still several major things that I need to do before the game can be shipped. And one of those is to playtest the game a decent amount. I sent out beta invites to several long-suffering volunteers over the past week and have been getting a lot of good feedback so far, and fixing a lot of bugs.

This next week, if the bugfixes become more manageable, then I will start working on an announcement. So look forward to that in a couple weeks, hopefully. In the meantime enjoy these screenshots of the new area.

80. A Trip Down Memory Lane

This post is adapted from something I wrote in the Taiji Discord, but I thought it might be interesting to share it here. By the way, you should totally join our Discord if you haven’t already.

Discord user GingerBread asked: “is there a specific reason why you chose tile shading as a basis for your puzzles instead of line drawing for instance? Was it mainly not to be too close mechanically with the Witness, or did you have other motivations?”

My Answer

The puzzle mechanic came about a bit differently, in that the game didn’t start as a Witness-like game.

Initially Taiji started out in April or May of 2015 as a sort of reimagining of a what a Zelda game could be. I was working with a very talented artist and musician named Martin Cohen and we were just calling the game ZG (for Zelda Game) back then. This was before Breath of the Wild was ever revealed in detail and I was sort of thinking about what a more modern Zelda game might be like: open world, non-linear, hard combat, and one of the things I thought would be good was to have some sort of core puzzle gameplay. (This obviously all ended up being done by Nintendo in their forthcoming game but anyway it was the headspace I was in at the time)

I had initially started work on combat design and some world design ideas, but I realized that I didn’t have any experience with combat design and was having a hard time making progress there at something interesting in a prototype form. So, I decided that I would switch focus and try to come up with something for the puzzles. I had many years of puzzle game design experience already so I thought it would be easier to make headway there.

I was not setting out to do something explicitly similar to the Witness, although I was inspired somewhat by Jonathan Blow talking The Witness having “core puzzle gameplay.” For example, a first person shooter has the core gameplay that you shoot enemies and dodge their attacks. This core gameplay gets repeated over and over across the game, but because of the depth and variation within that core gameplay the game doesn’t get boring just because you’re “doing the same thing over and over”.

Most Zelda games do not have core puzzle gameplay. Although they are not as bad about this as point and click adventure games, they do tend to have disconnected puzzle designs that at best maintain a theme across a single dungeon, and at worst are complete one-offs.

So I knew that I wanted to have some sort of core puzzle mechanic that the player would engage in across the whole game, but that would still have enough depth to stay interesting. The concept for the puzzles being about toggling things into some sort of pattern really just came to me, so unfortunately there’s not a cool story for why I thought of that. But the initial idea was a little different than what it eventually became and was more like the Mattel game Lights Out (a game which I had never heard of at the time). So you would toggle a tile and it would also toggle its neighbors.

So I made a little prototype of that and it seemed interesting. However because I imagined that the goal would always be to just light up the whole grid of tiles, I didn’t think there was tons of depth in that mechanic alone. Instead I imagined that the game would have variety through different input methods. So I also implemented some “snake” type puzzles where you would be forced to fill the grid by drawing out a path (this type of mechanic is still in the game in a few spots).

This still wasn’t that interesting, so I instead started thinking about how I might clue the player into different things to put on the grids. I came up with a couple puzzle sets that I thought were itneresting (both of which are in the game still in a somewhat evolved form), and I felt like I was really getting somewhere.

Unfortunately, I still had not figured out anything about the combat, and I also felt like the puzzle design would really take some time to flesh out (I didn’t imagine it would take 5 years). But because I knew I was onto something really interesting, I wanted to spend as much time as possible prototyping the gameplay before really committing to anything. So I suggested that Martin take a break from doing art and music concepts at least until I had developed this part of the gameplay further. (Ultimately I decided that I would pursue the project solo, though this in no way discounts Martin as an artist and musician, and I enjoyed working with him immensely. It had much more to do with my fear of relying on anyone else, but that’s a story for another time perhaps)

So I shelved the combat and focused on puzzle design for a while. I designed a set of puzzles that let the player just toggle things in a free form way with no particular constraints (this was just going to be another one of the interaction methods at this point). Suddenly it was nearing the end of 2015, I had a growing document full of puzzle ideas, and soon a game that I had been anticipating for nearly 7 years would be released.

That game was The Witness, and my hype level for the game was somewhere above what was reasonable for a jaded 26 year old man. I thought that the game might (just maybe) turn out better than Braid.

I just happened to be laid off of work when The Witness released and I played it all day every day for a week until I had seen everything it had to offer me. I was blown away. Not only did I find it better than Braid. Not only was it the best game I had ever played. I thought perhaps it was the best puzzle game possible.

I was elated, but I was also devastated. Much to my surprise, almost all of those exciting gameplay ideas in that document I mentioned earlier were also in The Witness in stunning fully developed forms that were much better than anything I could have done.

…what was I going to do now…?

I felt for a time like there might be no point in what I was making. It felt both too similar and and also lesser. I recall an email chat I had with Brian Moriarty around this time where he commiserated with my feelings of burgeoning irrelevance, and opined that Jon had “made Salieris of us all”. (Don’t know who Salieri is? Feel free to google it, but honestly that’s kind of the point)

However, I picked myself up off the ground and resolved to continue forward. Although The Witness had well mapped the territory ahead, I felt I could use it as a guidebook on what types of things would work in this kind of game and when there was overlap between the ideas, look for different forms of those ideas to the form they took in The Witness. I set out to make Taiji into a game that was both similar to, and different from, The Witness.

If The Witness was a telescope with which one could peer out at the universe and see certain ideas, I began to see Taiji as a different telescope with a different vantage point with which to look at some similar ideas. There was value in the different perspective even if sometimes the subjects were similar

With that said, one of the big things I chose to copy from The Witness was the symbols on the puzzles that you slowly discover the meaning of through experimentation. This ended up forming the bulk of the gameplay depth of the game, and I have been relatively happy with the degree of overlap and separation between the two games puzzle ideas.

Eventually as the game developed further, I felt like the alternate puzzle interaction methods were the least interesting things in the game. Also because those puzzles were just about space filling with no symbols or environmental cues it was casting this doubt on all the other puzzles that “oh maybe I just fill it all in?”

So the “lights out” type puzzles and the space filling stuff in general was cut from the game. And I also gave up on combat. (The Witness + Combat could still be interesting, but Taiji is not it) So the final game now focuses on puzzles where you can freely toggle tiles, and there are a few snake type puzzles that use a different interaction method where you’re walking on the puzzle in order to toggle the tiles.

I don’t know if that answers the question about how I chose tile shading, but hopefully it was a fun story!

P.S. The Mill area is done now, I did a video devlog about this, and here’s a screenshot:

79. Assemblage

Since the prior post, the pixel art for the Mill area has been fully completed and I’ve been chopping everything into assets that can be assembled in game. Below, you can see the finished pixel art as well as the current state of integrating it into the game:

You may notice the colors are a bit different in the in-game version (particularly red). This is because the game uses a color grading setup that is not optimized to any particular area in the game. Ideally before release I’ll go through and tweak the color grading a bit for each subarea to lock in a more unique look. If I can’t afford to do that though, I don’t think it looks too bad as it is.

Either way, there is clearly an empty space on the right hand side of the area that needs to be filled in!

The reason the finished art has that empty space is because I will be assembling that section using existing assets from the Shrine area, as it is a mechanical mix-in with the puzzles from that area, and the art for that area was created very modularly.

So, baseline art implementation is around 80% done or so. I still have to implement the exteriors, add some moving parts and add the entrance path below the plateau area to the left. After that I’ll have to add in all the collision and triggers, which is another whole bucket-load of work, but at least everything seems to be proceeding straightforwardly.

I will be very happy to be finished with this area and be focused on tying up the last little loose ends so this game will be ready for release. That’s not to say that I have a firm idea of when the game will be done. Although I think it could still possibly ship before the end of the year, it’s likely to slip somewhat into next year. Thanks for your patience on that front, I’m trying to get things done as quickly as I can.

I know some folks are probably following the written devlog and not the video devlogs, and I’ve been a bit more diligent about putting out those than I have been over here. I apologize for that. I often am remiss to simply post the same information over here that’s in the videos, as it feels redundant, but I think having some updates is better than going a whole month (or two!) without any sign of life.

If you’re not following the video devlog, you can find it on YouTube over here.

78. Milling About

I’ve finished up both the the sketch from the previous dev log post as well as a more detailed pass on the concept art for the Mill area. With that out of the way, I have been moving onto doing the actual in-game pixel art. In order to save some time, I’ve combined both the pixeling and the “decay” pass on the art into the same phase.

You can look at all 3 passes as they currently exist (including the incomplete pixel-art pass) below:

Doing the pixel art is taking some time because there are a lot of small details which I want to get right with this area. As I mentioned in the latest video dev log, there is an important balance to strike between things having enough rust, dust, and decay, and things remaining within the overall “flat” aesthetic of the game’s art style. With that said, I think the hardest part is now out of the way and I’m onto the more straightforward implementation phase.

I enjoy detailing the pixel art much more than I enjoyed planning everything out. I think this probably comes down to me being a generally detail-oriented person, ever since I was a small child. Probably something to do with being a bit autistic. I don’t know for sure, but that’s how it is.

Looking at the big picture, this is the final major area that needs to be finished. After that, there is a bonus area that I want to add as well, although it will be less visually detailed and hopefully can be completed in short order.

I’m getting closer than ever to actually having the game finished to a baseline degree. Ideally I’d like to go back over everything and add in more details and clean up stuff that I’m not happy with. But we’ll see how much I can actually afford to do. The main obstacle at this point is how little money I have left. Although I have managed to reduce my burn-rate rather significantly for the time being, I’m about one small disaster away from being totally broke.

Anyway, not trying to complain, just trying to air out some of my thoughts here.

I feel like I should cover something a bit more in-depth here on the blog soon. If anyone has any suggestions for something to dive deeper into about the game, feel free to leave them in the comments below!