It’s hard to be sure exactly what to write about, since most of the work lately has been going into painting over each of the areas in the game. But this past month I’ve finished drafts of art for two major areas in the game, so I guess I’ll post up some screenshots!
(You can click any of the screenshots to view them full-size)
This area is styled after a Japanese shrine and centered within a large lake.
This area is an ancient ruin seated atop a narrow plateau. Some parts of the ruins have seen better days.
You may recognize this area from an earlier iteration of the art. Some parts of this area are still unfinished, art wise, and I need to add in the shadows. (I paint in all the shadows by hand!)
Here’s a bonus screenshot of another area in the game.
This past month, I’ve been both working on Taiji and crunching on promotional materials for Manifold Garden. (Which is out now on Apple Arcade and the Epic Games Store, by the way! You should check it out if you like puzzle games. I get no extra money if the game does well, so I am just recommending it personally.)
Seeing off Manifold Garden has been exciting. But turning back around to work on my own thing has been a bit depressing. It still has so much further to go before it will be done! I’ve been trying to keep my head on straight but it’s been a bit of a damper on my spirits.
The Breaking Point
Some technical aspects about the visuals in Taiji started to come unraveled earlier this month. One of the decisions I made early on was how to sort all of the individual graphical elements in the game. Although for 3D games, sorting is just handled as part of the perspective (except for translucent objects), in 2D games you usually set up an explicit sorting order.
In Unity, there are actually two systems you can use to handle sorting, the first is a sorting axis, which is equivalent to the Painter’s Algorithm: objects that are further away from the camera are drawn first and closer ones are drawn last.
The other system is Sorting Layers. These are just buckets you can put different objects into and you can set the order in which the buckets draw. My initial idea was to only use 3 sorting layers for the entire game: a layer below the player, the player layer, and a layer above the player. This seemed like it would work, because you are additionally allowed to specify a numerical sorting order for the objects within each layer.
The primary benefit of this approach is that it is player-centric. This means that I know that all objects in the “Below Player” layer will always be drawn below the player, and vice-versa for the “Above Player” layer.
But what happens if I want to have objects that are above the player at one point, and then below the player at another?
There are two types of scenarios where this problem might happen.
One is “vertical” objects that the player can walk around, such as trees. If we place them below the player, the player will be walking above the branches, and if we place them above, then the trunk will float over the players head. This problem is easy to solve by simply placing those objects on the player layer. In this case, Unity will fall back to the sorting axis and sort by distance. However, we can tell Unity to sort using the Y-axis, instead of the Z-axis. This means that objects that are higher on the screen than the player will draw behind them, and those that are lower, draw in front.
The other slippery sorting situation is when the player is underneath an area which they can climb up into. A basic example of this is a bridge over a canyon. The player might be in the canyon, walking underneath the bridge, but they can also climb out of the canyon and end up above the bridge, walking across it.
This scenario is challenging to achieve under a simple 3 layer (Below Player, Player, Above Player) setup. The only real way to do this is to either shuffle all the objects between the above and below layers, or have copies of the objects on both layers, and only enable whichever is appropriate depending on where the player is.
I was using a mixture of both of these systems up until recently. It worked, although it was quite cumbersome. You’re moving around of dozens of objects from layer to layer all the time, and you can’t even see any of the visual issues until you run around the game. But eventually you run into scenarios where there need to be more than two layers, and it all falls apart.
So I made the difficult decision to change the entire sorting system used by the game. Under the new setup, each area in the game has a sorting layer, and the player is moved from layer to layer as they walk around the world, always staying at order 0 in whichever layer they are in. Objects with negative sort values will be below the player in that sorting layer, and those with positive values will sort above the player.
This setup makes so much more sense. Since only the player ever moves around, I never have to worry about the environment looking any different than it does in the editor.
In fact, I feel like I should have changed things over much sooner than I did.
I think this particular type of mistake was misguided optimization, which is even worse than premature optimization. Instead of optimizing for my sanity, and the simplicity of building the game over the long haul, I tried to optimize for the number of layers without being sure that it would ever be an issue. It wasn’t a performance concern, more just an aesthetic one.
I think it’s important to accept that your game is going to be a big icky mess at some point anyway, so you just should just leave the cleanup until you can actually see what you’re dealing with.
In any case, things haven’t been perfectly rosy with the new setup, but I’ll leave that story for next month perhaps. See you soon.
Proof Of Work
Perhaps you’d like to see the work I did related to Manifold Garden? If so, you can check out the following links:
So, I’ve been continuing to bang away on the visuals for the game, which means I could just post up some more screenshots like I did last month, but I thought it might be more fun to do a bit of a technical breakdown of the waterfall effect in the game.
You can see what the finished effect looks like below:
So, there are obviously lots of references I can go to for waterfalls. Photo references, other games. I happen to live near quite a few streams and rivers, many of which have waterfalls.
A few of the bigger influences on this effect are the waterfalls in the Zelda games Breath of the Wild and The Wind Waker. You can see examples of both of those below:
I’m actually not a huge fan of the look of the waterfalls in Breath of the Wild, but the way in which the effect is technically achieved is fairly obvious there, and so I consider it somewhat of an influence on my approach. Really, both of the above waterfall effects, as well as the waterfalls in Taiji are essentially a variant on a basic scrolling texture effect.
Below on the left, you can see the source texture I use for the bulk of the waterfall effect. And on the right you can see and what it looks like when scrolled across a distorted UV map. ( A UV map is what tells the graphics card which part of the 2D texture to draw on each part of a 3D model. In this case, the UVs are stretched in the shader, with the underlying geometry just being a flat rectangle)
So the basis of the effect is that I overlay two copies of this texture, with different offsets and slightly different scrolling speeds. These form the white foam layer.
After that, I make two more layers, only these scroll much faster and are partially transparent. This forms a second layer to go beneath the white layer.
Both these layers are composited together and then overlaid (at a lower alpha and with a fade towards the top) onto a screen-space gradient that acts as the water’s base color. The gradient is subtle but resembles the reflection of a blue sky.
Alright, so we now have the base of our effect, and can add the edges. The edges are just another scrolling texture using the same distorted UVs as before. The left and the right edges are just mirror images of eachother, offset a bit along the direction of scrolling. The UVs for the edge texture are also pinched in a bit at the top of the waterfall. Below, the original edge texture is on the left and how it gets distorted and scrolled is on the right
The black area of the edge texture is used to mask off the effect so that it can be composited into the rest of our effect and blended in. We add a slight fade to transparency at the top of the waterfall and we’ve completed the base effect.
At this point, we add a churn effect to the bottom of the waterfall, using particle systems. One system is emitting large circles which shrink and fade out, the other system emits smaller circles which fly up and then are killed off when they cross the bottom edge of the waterfall. You can see the two particle effects separately below.
When we put it all together, we get our full waterfall effect:
Thanks for reading, hopefully this was an interesting dive into some of the technical art that I’ve been doing lately for the game. 🙂
So, the gameplay is getting close to something resembling an overall rough draft. Most of the areas that I want to put in are playable in a rough form. This is great, but unfortunately hides the fact that I’m still way behind on the art and the music.
The past month has therefore been focused on trying to “art up” as much of the game as possible. I’ve still been quite busy with the “part-time” contract job I mentioned last month, so I’ve gotten less of that done than I would’ve liked to. But in any case, progress has been made.
Here are some screenshots of areas as they’ve come along so far.
Obviously, everything is still very WIP, and these screenshots should not be considered indicative of the look of the final game. There’s still a lot to be done, but I’m pretty happy with how these areas are coming along and the overall aesthetic.
So, the next question is: “What about the music?”
There are currently only two tracks of real music in the game, which is (needless to say) quite a bit less than I think a complete game should have. However, I have found it somewhat difficult to get a handle on the musical style for the game.
I think there’s two main reasons for this. The first is that it’s just plain hard to come up with themes that are strong, dramatic, and not too grating to listen to for a long time. Essentially the same challenges as any game.
The additional problem that I think Taiji has is that I have to be a bit careful about the types of music that I choose, to not accidentally draw too much attention away from the puzzles, or introduce any red herrings.
I presently find myself quite stymied by the music, but this is not the only time in the history of this project that I’ve found myself stuck on one problem for quite some time. Progress can stall for a while until I get a sudden breakthrough and then things start progressing very fast.
So, I will either end up finding a good way forward soon, or I’ll have to look into hiring a musician. I’m not opposed to seeking more experienced help here. Music, to me, is the heart and soul of a great game, and great music can carry much of the weight of a game’s tone and atmosphere.
In any case, don’t submit your resumes just yet. I may perhaps find my way.
See you soon with another post (ideally before the end of the month, as I need to make up for the fact that I’m a month behind!)
So, this past week I spent a few days polishing up the character movement and animation, primarily focusing on adding running animations. The results are as follows (Recommend watching at 60fps):
I’m pretty happy with the running animations, although they do make the walking animations look a bit cheap by comparison. I figure most players will just toggle running on and play the game always running everywhere, so it’s probably fine if the walk animation is not as developed.
This week, I’ve also been trying to think a bit more concretely about the big picture ideas for the game, including story and world design.
Right now the world design of the game is pretty much non-existent. Everything in the game is just laid out in the way that was most convenient to fit everything together without overlaps. However, I’d like to do something that has a much more overlapping and interconnected feel.
My ultimate inspiration for world design is Dark Souls (wait wait don’t close the browser tab). I don’t necessarily want to attempt that game’s scale, but one of my favorite things about the game’s world is how you head off in a long winding direction that you think you will never come back from, only to find an elevator that takes you straight back down to the central hub area, unlocking a massive shortcut in the process. This creates a wonderful sense of surprise and is a real tangible reward for exploration. And the best thing about it is that there’s almost no cheating involved in the 3D space of the entire game world.
If you’ve played the game, you probably already know all about this. But if you haven’t, here’s a good look at the world of Dark Souls using a map viewer tool:
Now, obviously this is a very high bar to attempt to reach, especially in a 2D game, but it has at least got me thinking about what types of tools I will need to accomplish anything even remotely close to that. (More on that perhaps later)
Secondarily, I’ve been thinking a bit more about what I want to do about story. What store do I want to tell with the game, and what methods of storytelling are appropriate, both to the style of the game, as well as my limited resources (I am the only one making the game, after all).
I’ve been pretty stumped on this, as I don’t want to resort to JRPG style characters who simply stand around and bark repetitive lines if they’re not involved in a cut-scene. Nor do I really want to put text in the game at all, if I can help it. Luckily, inspiration struck this week when I was watching my girlfriend play through Journey. I had played the game years earlier, but the way in which the game communicates a clear story through entirely non-verbal means struck me.
As with my inspiration from Dark Souls, I don’t necessarily want to emulate Journey’s scope, and I don’t plan on putting cut-scenes in the game. (Or, at the very least, they would be extremely minimal at the start and the end of the game.) In particular though, I’m interested in how the game uses murals hidden throughout the world to communicate a backstory element. So, you may see a similar approach in Taiji, as it’s a good cost-effective and unobtrusive approach.
It took a bit longer than I anticipated, but I’ve completed converting all of the puzzles in the game over to the new puzzle panel system I described in the last blog post. I probably could have made this a bit easier on myself if I had more deeply integrated the new system within the old one, but I wanted to keep things as cross-compatible as possible so I more or less have both systems working in parallel.
There’s a couple reasons for doing things this way, one is that I didn’t know how well it was going to work, and so I might want to abort the whole thing partway through. This is much easier if I didn’t break any of the existing stuff in the process. The other reason is that it’s just still easier to design new puzzles using the old system. I can just duplicate a panel and I don’t have to wire it up to anything for it to work. The new system, at minimum, requires wiring up each panel to it’s starting tile.
Going forward, I may choose to more deeply integrate the starting tiles, so that puzzle panels will automatically generate them as needed, and I don’t have to do any particular wiring. But going forward, it shouldn’t ever be as much of a hassle as converting everything was in the first place.
I also took this opportunity to heavily revise a couple areas in the game, in order to test out approaches to the art, make something that is a closer approximation of what the game might be like when finished, and encounter issues which I might not encounter otherwise.
Here are a couple screenshots of the “arted up” areas.
Overall, I’d say I’m fairly happy with how the artwork has been coming along. The game seems like it might actually not look terrible, and might have something approaching a unified art style. It is admittedly a bit time-consuming to get this level of fidelity, but I think the results speak for themselves.
The other thing that I’m doing this week, is another round of playtesting. I’m pretty sure the next development steps are going to involve cutting a bunch of puzzles. However, I want to get a more broad base of feedback so I can make more informed decisions about where I should let certain things stay in the game and what areas might feel too tedious or drawn out.
Apologies if you’ve been on the testing waiting list for a long time. Feel free to hit me up in the comments, or on twitter, if you’re interested in testing sometime soon. (Or if you expressed your interest a long time ago and are becoming irate)
I have to admit, I’ve been feeling a bit wore out lately. I haven’t worked full time on a game for many years, and it can be exhausting. No matter how much you love a project, it will always go through ups and downs.
I guess I would say that I’ve reached a new plateau. There’s a certain amount of satisfaction mixed with depression that hits whenever I hit one of these new plateaus. In one sense, the game is clearly better than it’s ever been, but it’s also clear how much I could still improve things. Reaching one plateau means I now have to plan the route to the next plateau.
I’ve already taken some of those first steps though. One of the biggest ones was making this overhaul to the panel interaction method. I had been putting that one off for a long time, as there were still so many easy wins in sight on the puzzle design. Now I have migrated everything over, and the puzzle design challenges seem daunting in comparison. I don’t lack for ideas, but I do lack somewhat for the energy.
In the diagram of flow state, I’d say I’m more in the frustration section than the fiero section. I feel a bit overwhelmed and stymied. I’m sure I’ll get back into the zone soon enough though.
Mostly been revising puzzles the past couple weeks, so not much I can show that’s not spoilery. However, I did do a bit of concept art to figure out how water will be represented in the game. Obviously it’s all very placeholder, but I’m happy with the direction things are going.
This week, I’ve been working on implementing a feature that I have wanted to have for a long time: puzzles which feature tiles of non-uniform size.
Thus far, all of the puzzles in the game have been built around fixed-size tiles. It’s a bit hard to explain the difference in words, so here’s a visual example:
The left image is how all the puzzles in the game currently operate, as a grid of uniform tiles of all the same size. The panel on the right is a mock-up of what I want to do. Essentially, I want the capability to make puzzles where tiles can be “connected” together into larger groups, or meta-tiles. Doing this requires a bit of ingenuity, both within the tech and from a graphic design perspective.
Since I’m still keeping the grid-based setup, the problem is much simpler than it could be.
As far as the artwork is concerned, we can cover all of the shapes we might want by subdividing each panel tile into 4 smaller sub-tiles, each of which can be one of three different graphics:
This is the most economical choice from an asset design perspective, because although there are more variations required than the 3 sub-tiles, they can all be expressed simply by rotating the tile images.
As simple as the art is, the code is kind of complex, both in determining how to rotate the sub-tiles, and because there is an additional “corner” case (Get it?).
For example, with the basic approach, in which you just check the neighboring tile and see which ones are connected, if you were to have a large connected block of four tiles, you’d end up with something like the left-hand image below:
Notice that each tile is drawn as a single-width corner, and so we end up with a hole in the middle of the area. This might be desirable in some cases, but here it’s really just an accident.
Luckily, this isn’t too difficult to resolve. You simply check, for each tile, if it is connected so as to form a corner, and then you additionally check if the tile diagonally opposite that corner is also connected to form a corner, and if it is, you just change the inner corner graphic. This technically requires a fourth sub-tile for the inner corner, which is just a solid color.
One of the other challenges was deciding upon a data format to express these meta-tiles, and additionally, how I would interface with that format in the code.
There are two approaches that initially came to mind, both of which have their costs and benefits.
Add four booleans (true/false values) to each tile, for each of the four cardinal directions, to indicate whether or not the tile is connected to its neighbor along that direction. The benefit here is that checking for connections is simply a matter of checking a value stored alongside the tile. However, it is rather wasteful of memory, with four additional entries per tile. And furthermore, for each connection, there are two values, leaving the possibility that the connection values could end up out of sync. (This can be resolved with reference types though, as I’ll explain later)
Create an array which stores the connections between tiles as booleans. This is memory efficient, as there is no data duplication. However, it is somewhat cumbersome to work with in the code, without doing some additional engineering. (The panel is made up of one 2D array, and the connections are an additional 2D array, but it is somewhat hard to make direct comparisons between the two arrays.)
I decided to go with the second option to begin with. Both options have their upsides and downsides, but the memory efficiency of the second option seemed most appealing to me for whatever reason.
Notice that both approaches are thinking about properties of the individual tiles which make up the meta-tile. Each tile has connections to its neighbors. This approach has some flaws which will come back to bite me in a bit, but this is what I chose to go with first, and I think it’s important to document my process as it happens.
My general strategy when doing any engineering work (and sometimes design as well), is to do the simplest dumbest thing that seems like it will work, and clean it up later. This means I may just implement the first solution that comes to my head. This is a good approach because, most of the time, unless a problem is utterly trivial (or you have implemented a similar solution many times before), you don’t really understand the problem well enough before you begin. The likelihood of anything you think of before you start coding being the right solution is pretty close to zero.
So get your ego out of the way and just start coding!
It’s a bit difficult to explain the way that I structured the data, but since I went through the trouble of creating an editor interface for the connections, I’ll simply show you what that looks like, as it’s a useful way to visualize the data structure of the panel in terms of how it relates to the connections.
In the editor interface shown above, the actual tiles of the panel are represented by the ☐’s. The connections between the tiles are represented by the checkbox buttons.
In terms of the data layout, the panel state is stored as a 3×3 array of booleans, and the connections are stored as a 3×5 array. I need the additional rows. as each tile has vertical as well as horizontal connections.
Fun fact: For any particular panel of dimensions W¹×H¹, the formula to determine the size of the array necessary for storing the connections between tiles is
Second Fun Fact: Every other row, I don’t use the last horizontal entry in the row, so I technically do waste a bit of memory.
As I mentioned earlier, because of the unusual data layout, it is not exactly obvious, for any given tile (x, y) on the panel, which (x, y) to look at in the connections array. This is one of the flaws of the tile-centric approach.
This function gets called a lot, and is pretty computationally inefficient. One solution would be to cache the results of these calculations and store the results alongside each tile. This is equivalent to option #1 from earlier, however if the stored values were only references to the values in the connections array, this would avoid the problem of the data getting out of sync.
The next thing we have to resolve is toggling the whole connected piece when the player clicks on it, and handling the highlights when the player hovers over the piece.
Since the code that deals with the player clicking on tiles still works with individual tiles, rather than the whole connected group, when the player clicks on any given tile, we have to do a search to determine all the tiles connected to that tile. From a technical standpoint this is somewhat non-trivial, but it is analogous enough to the issue of finding all the tiles within a colored area, that it was a problem which I’d already solved. The only difference here is the criteria by which the tiles are considered “connected.”
So, we do the exhaustive search for all connected tiles when the player clicks to toggle. Although this works well enough when we’re toggling, we also need to highlight the tile when the player mouses over it. (Notice in the above GIF that the tile highlight is still isolated to the individual tiles, and doesn’t cover the whole connected group)
We could do the same search that we were doing when toggling a tile, it would technically work, but doing it every frame seems a bit wasteful. Of course, we could do some basic optimization and only do the search when we really need to, when the player has moused over a new tile.
This is all fine, but something started to smell funny to me. I didn’t like how wasteful things were getting computationally. After thinking about it for a bit, I came to a more optimal solution.
Until I got fairly deep into the implementation, I had been thinking about this whole problem from the bottom up. I was thinking only about the same uniform tiles I always had, rather than the meta-tiles. A meta-tile, as far as I was concerned was just an emergent result of a system which allowed tiles to be connected to each other.
But what if we think of a meta-tile as it’s own entity? If we do, then our problem of finding all the tiles that make up a meta-tile suddenly becomes trivial.
Additionally, because the layout of the panels in the game never changes in real-time (thus far), I have the luxury of baking down any complex calculations that have to do with the panel layout. In this case, I can just bake-down the meta tile groups at startup.
In the baking process, I iterate across all the tiles on the panel and store an integer for each tile, denoting which meta-tile group it is part of. For example, if the first tile I check is connected to form a meta-tile, I will mark all of those tiles with a meta-tile number of 1. The next meta-tile I find, will have a meta-tile number of 2. And so on.
The numbers don’t really matter as long as they are the same for all tiles within the same meta-tile group.
This means I only have to do the exhaustive search at startup, and from then on, whenever I need to find all tiles that are connected to a current tile, I can simply compare the current tile’s meta-tile number to all the other tiles on the panel, and if the numbers match, the tiles are connected.
(This is actually a simple enough way to handle connected tiles that I may choose to do away with the connections array. Additionally, opening up the ability for overriding the meta-tile group manually would allow for some additional things, such as having tiles that are not physically connected, but can only be toggled in unison.)
Fixing the Mechanics
Getting the gameplay mechanics working again is somewhat more complicated, as I have to combine the idea of areas connected by color with the idea of multiple “tiles” being connected together into one big tile. This shouldn’t be too difficult though, as we just have to add meta-tile awareness to our normal area search. Still, I didn’t get to it this week.
So…to be continued.
In the process of doing all of this, I ran into some performance problems. This is somewhat to be expected. Previously, each puzzle panel tile required 3 sprites, but under the new system, there are 9 sprites per tile. (I have the four corner sprites both for the fill part of the tile and the outline part, as they can be colored/enabled separately. Additionally, there is a background color sprite for each tile.)
One of the obvious issues was a huge uptick in the time spent on start-up. This has been a bit of an issue for some time already, but it really just skyrocketed. I try to keep the startup time down to less than 5 seconds (Ideally it would be much faster than that, but there seems to be a certain amount of overhead in Unity that is simply unavoidable), but after making the changes to allow for the increased graphical flexibility, the start-up time ballooned past 10 seconds.
This may not seem like a lot, but I like to keep my iteration times as fast as I can. This desire for instant feedback (or as close to it as possible) is why I took the time to get a live updating feature for the puzzle panels.
The overhead came because I was initializing every single puzzle panel in the game at startup. This involves not just spawning objects for each panel, but for every single tile on every single panel. As many of you who are familiar with Unity may know, spawning new GameObjects is one of the more expensive things you can do. Unfortunately, with all the additional GameObjects involved in the new sub-tiles, there were just too many objects being created at start-up for it to happen in a reasonable timeframe.
So in order to reduce the start-up time significantly, the thing that made the most sense was to avoid initializing anything that wasn’t completely necessary. I could have chosen to go right to an object pool system, where I reuse tiles from panels as needed and only spawn a few at a time. But instead, I just chose to go for the simpler method, which is just to check which panels are visible to the player when the game starts, and only initialize those.
Apart from the startup time, there were some other issues with how I was handling control of the colors and images on the sprites. I made the initial mistake of delegating all of that work down to the individual 8x8px corner tiles, but it really made more sense to cluster the work up at a higher abstraction level in the 16x16px tiles. There is a decent overhead to each individual MonoBehaviour component in Unity, so the less you can have of them, the better.
As time goes on, it may make more sense to bring that tile management work all the way up to the level the entire panel itself, but for now this is a good balance between locus-of-control and performance.
There were some additional minor performance issues unrelated to the new panel changes that I nevertheless took the time to clear up. I won’t really go into those here, but it always feels nice when you get things running better.
I’ll be back next week to talk about getting the puzzle mechanics working again. I also need to repair the walking puzzles, cause I seem to have broken the graphics for them.
You may have noticed that I haven’t been posting updates for the past few weeks. My computer hasn’t been hooked up and so I couldn’t work on the game. Instead I’ve been finishing off a major move.
The house we’ve moved into really should have been cleaned before we moved into it, so it’s been a bit of a challenge to clean thoroughly with all our stuff in the house. So a lot of that has been happening, as well as repairs and general moving stuff. Still hard to relax as most things are not really “in their right place.”
I did finish setting up my computer and desk and did a short test stream earlier this week to see if the internet here was decent enough to use for streaming (in short: it isn’t). So, barring a miracle, if I do any work streams going forward, they will be more of the Starbucks variety that they were a few years ago.
Unfortunately, I didn’t really find the gumption to sit down and work on the game any more than just that short test stream. On the stream, I added a little bit of a color difference for the puzzle panel backgrounds depending on whether or not there are active tiles.
It’s a pretty small change, but it should make panels a bit less confusing for new players. I’m still not 100% happy with the look, but it’s a step in the right direction.
I’m hoping to get some more done on the game in this next week. Still lots to do around the house though, so we’ll see.