40. Tool Improvements

After making the changes to the “dice face” puzzles which I described in a previous blog post, I ended up with a few edge case puzzles which didn’t work under the new mechanic, but were still within the boundary of the game’s subject matter. This meant that I would need to do some extra engineering to keep these puzzles working the same way. This caused me to confront some of the growing problems with my puzzle design tool.

Here’s a screenshot of the old interface:

oldpuzzleinteface

This is the tool that I use to design all of the puzzles in Taiji. Although it has been perfectly serviceable, it was starting to take up a bunch of vertical space, and there are additionally a bunch of very subtle details which were starting to make it icky to work with on a regular basis. Additionally, if I want to add more functionality (which I do), it was becoming very unclear how I was going to add it, both in the interface, and the underlying code.

So I have done a bunch of under-the-hood work, which although completely invisible to players, allows me to clean up the code andrevise the puzzle designer interface.

This is how it looks now:

newpuzzleinteface

Although also somewhat complex, it actually has more functionality than the interface shown above, while taking up a bit less space. (Admittedly, these aren’t the same puzzle, so it’s not a 1:1 comparison, but I don’t really want to take the extra time to grab a better screenshot right now.

There are still some more improvements that I’d like to make, including basic ones like making sure all the input boxes still line up when there are disabled tiles on the panel, but overall I am much happier with the interface and the underlying structure of the code going forward, and I think it will definitely be more amenable to adding new functionality.

38. Small Tweaks

colordiceSeems like I’m writing these things on Mondays most of the time now…

Didn’t get a whole lot done over the weekend, at least not visibly. Most of the work was under the hood or maintenance. I repaired the puzzles which mix the “dice” and “dot” mechanics, after having changed the way the dice mechanics work. The combined puzzle sequence stills need a lot of work to be enjoyable to solve, but at least the puzzles aren’t actively broken anymore.

I got them working again through a small change to how puzzle solutions are validated. Previously, with the dot mechanic, whenever the color of two dots needed to be checked, the code would use an arbitrary number which specified which color dot we were talking about. (i.e. 60 = blue dot, 61 = yellow dot, 62 = red dot, etc.) The change I decided to make is to have it actually directly compare the color values of the two symbols in question. (Technically I compare an integer hash of the color to avoid the == operator overhead of Unity’s built-in color class) Directly comparing colors has a couple benefits when it comes to simplifying the code and also makes future puzzle possibilities much easier.

I didn’t end up revamping the entire puzzle panel system, because after some further investigation, there are some good reasons that I architected it the way that I did, in spite of the fact that it’s unwieldy at times. The main reason is that I’m relying on the Unity serialization system to save the panel layouts, and certain data formats just serialize more straightforwardly and quickly. One dimensional data type arrays are the most easily serializable format. So, even though it would be more useful to have a single tile structure which stores all the relevant data, including references to spawned GameObjects at runtime, it is a bit more challenging to implement than it would immediately seem.

Furthermore, serialization can get real nasty when dealing with null references, as stated on this page in the Unity docs:

Consider how many allocations are made when deserializing a MonoBehaviour that uses the following script.

class Test : MonoBehaviour
{
    public Trouble t;
}
[Serializable]
class Trouble
{
   public Trouble t1;
   public Trouble t2;
   public Trouble t3;
}

It wouldn’t be strange to expect one allocation: That of the Test object. It also wouldn’t be strange to expect two allocations: One for the Test object and one for a Trouble object.

However, Unity actually makes more than a thousand allocations. The serializer does not support null. If it serializes an object, and a field is null, Unity instantiates a new object of that type, and serializes that. Obviously this could lead to infinite cycles, so there is a depth limit of seven levels. At that point Unity stops serializing fields that have types of custom classes, structs, lists, or arrays.

Since so many of Unity’s subsystems build on top of the serialization system, this unexpectedly large serialization stream for the Test MonoBehaviour causes all these subsystems to perform more slowly than necessary.

I may yet return to make some more of those changes, but you can see that the water is fraught with peril. A good approach would probably be to have two formats, one for all of the runtime code, and one that is used for serialization, but this would also create a bunch of potentially slow startup code every time the game was run in order to translate between the data formats (and there’s already more initialization code for the panels than I really want there to be)

On a humorous note, before some of the changes I made, I had this monstrosity of a line of code:

symbol = litSquares[p.x+width*p.y].GetComponent().transform.GetChild(1).gameObject.GetComponent();

And now, with some data restructuring and a few helper aliases, it becomes the much more manageable:

symbol = tiles[p.x+width*p.y].symbols[0]

36. Starting Area Improvements and Colorblind-Safe Colors

A bit late on this post, but hey! Better late than never.

This weekend, I streamed some work on improving the starting area. Managed to get in a few non-trivial puzzles to cap off the area a bit better and introduce the concept of locked tiles. Locked tiles are just tiles that you cannot toggle from their starting state. Here’s a screenshot of those new puzzles ( a bit low quality cause I snapped it from the stream video):

startingareaclimaxscreen

I also changed the game from an oblique renderer back to an orthographic one. This is a bit of a subtle technical detail, but suffice to say that the change simplifies some graphical things and makes some others more complex.

I had hoped to do the first full art pass on one of the game’s areas, but unfortunately I ran into a bug with Unity’s tile-mapping system. I upgraded to 2018.1 in an attempt to fix it, but I have since been told by Unity Support that the bug is not fixed until 2018.2b, so I will either have to upgrade to the latest beta version, or wait until it gets a full release to hopefully get started on that.

Colorblind Safety

In last week’s devlog post, I talked a bit about some of my thoughts relating to accessibility, particularly when it comes to deaf players. This week I’ve been thinking more about colorblindness.

Trying to come up with a set of color-blind friendly color options is quite difficult as there are several different forms of the condition. Some people have a hard time telling between red and green, and others between blue and green, and a rare few cannot distinguish colors at all.

I tried a few different variants, but many of them had problems:

colorblindsafe_no.jpg

The absolute best way to deal with colorblindness, of course, is to just use different symbols instead of different colors. This unfortunately is not a straightforward option for Taiji, as differently shaped symbols have different mechanical meanings. You can also use patterns instead of colors, but since the game uses pixel art, the detail possibilities are very limited.

Luckily, since most people can tell the difference between blue and yellow, those colors in combination with black and white provide a 4 color setup that will work for most people and most puzzles, at least where the only thing that matters is telling the colors apart.

safecolorcombos2
A mock-up panel with the latest color blind “safe” color palette.

However, this may still not be enough for some players, so I’ve decided to address this issue with a two pronged approach. For most puzzles in the game, I will just stick to the “safe” color palette, and the game should be accessible to many players by default. However I will have an additional assistance menu where the player can choose alternate colors if the defaults are not easily distinguished.

Additionally, there will be a set of completely color-free assistance symbols which can be enabled. These will be useful for puzzles where the player needs to know exactly which color they are looking at, or for when more than 4 colors are necessary.

Here’s my first pass at that:

colorblindcolormixingsymbols.png
Assistance symbols across top, corresponding full colors across bottom.. Colors from left to right: Black, Yellow, Magenta, Cyan, Red, Green, Blue.

Of course, the symbols themselves are subject to change, but the important thing is that the symbols combine and mix the same way that colored light does in the real world. In this case, the color model is subtractive.

For clarification on what I mean, here are the symbols again, now colored with their corresponding colors:

colormixingsymbols_colored.png

I’m not certain this will work for all the puzzles in the game, but it’s a start and it’s fun to think about.

29. Animation Nation

The past two weekends, I have been working on revising the design and animations of the main character. The old sprite has served prototyping fine, but it’s time to start working on actual art for some parts of the game, both so that I can start designing puzzles that use more subtle visual cues, as well as for the purposes of being able to promote the game at all. (Prototype grey-box environments can be fun to play around in, but don’t show very well)

Part of this process involved deciding on an approach for implementing the animations into the game. Unity already has a very robust and complex animation system built in to it, but it is much too complex for what I need for a simple 2D pixel art game. Unity’s animation system is built for handling complex motion blending and IK with 3D models. Also, it doesn’t really allow for easy control of animation switching from code. You have to establish all your animation parameters and transitions in the Animation FSM through the Animator panel.

So, I set about coming up with a quick and dirty replacement which would basically allow me to, in code, just say “play this animation now”. This took way longer than it should have, primarily because I couldn’t get a custom inspector for my new “Sprite Animation” component to display the information that I wanted correctly. Eventually I threw in the towel and just divided the system into two component types. One “Sprite Animation Strip” component is added for each individual animation, and there is a master “Sprite Animation” component which handles playing the animations and switching between strips.

animationsystem

It’s pretty messy, primarily because there’s no clear indication of which animation strip is which when you’re looking at the array under the Sprite Animation component. Because of this confusion, it’s not a particularly tenable system if you have dozens of animations, but for the time being it has served my purposes fine.

Here’s a gif of the current work-in-progress walking animation in action (the environment is still just grey boxes though:

firstpasswalkinganim.gif

There’s a lot of room for improvement. Most notably, I need to fix the hair so that it is always blowing in the same direction. To do this, I’ll probably make the hair a separate sprite which gets overlaid over the main one.  Also she shouldn’t suddenly get a haircut when she is walking, but it is a good start.

Oh, and here’s a bonus gif of just the standing animations on top of a more detailed background.

NewPlayer_Standing

25. Testing

So, as I mentioned in the previous post, I spent last weekend sending out a build of the game to several testers. Because the game is starting to get a bit large, I decided to cut out a couple of the areas which will be in the full game in order to focus the demo only on things that have changed.

What was left took most testers around 2 hours to play through, although some finished more puzzles than others. I’m uncertain how much additional playtime the removed areas would be, but I believe what was tested is a substantial portion of what’s in the game at the moment, so I wouldn’t expect it to add more than another half hour or so.

That’s obviously not really indicative of the final playtime of the game, as things will probably change and some areas will be expanded or reduced in certain ways. I’m a bit ambivalent about the length of the game, as the game is both intended to be “as long as possible” and “wasting as little time as possible.” I’m not entirely certain that it’s not entirely wasted time free, as there is still a lot of traversal time, especially for players who want to leave areas and return to them later. That’s certainly a problem that I hope to solve before shipping a final version of the game, probably by allowing players to warp in/out of each area.

Across all 5 testers, all puzzles were solved at least twice, so that’s some good evidence that the game is at least not totally off in cat hair moustache land. I’d like for people to have a hard time with at least some puzzles in the game, but at the moment there were really only two puzzles which totally stumped people. Not to say that the puzzles were easy, some players would easily spend 10 minutes on some panels. But I would like there to be quite a few more puzzles in the final game that cause people to pack their bags and go home without solving them, as long as they’re good puzzles.

For the most part, most of the things in the game are working the way they should be working. There weren’t many catastrophic failures, but I did have an issue crop up that I’m not entirely certain how to deal with.

Dice Conundrums

(The following could be considered to contain minor mechanics spoilers for puzzles in the game. I don’t describe how the mechanic works in detail or show any puzzle solutions, however.)

One of the issues which came up in this round of testing is one which I had already considered for some time, but have been unable to really come up with a proper solution to. And that’s for the puzzles in the “dice face” area.

For reference, the puzzles look like this, where they have tiles which are marked by black or white dots. The color of the dot indicates whether the tile should be on or off. As a player, which of the two answers on the right would you presume to be a correct way to interpret the symbols? Stop for a moment and think…

dicefacepuzzles

If you chose the one on the left, congratulations! You’re correct.

The issue, however, is that many players see the solution on the right as more intuitive. This is not particularly out of the question, as white meaning “turn it on” is quite a natural assumption, and I make use of that assumption elsewhere in the game. It makes sense, but there is an issue. Really, two issues.

Firstly, that when the player solves a puzzle, I light up the panel tiles which were highlighted very bright. In this case, white:

solveddicepanels

The issue should be immediately apparent here. If the correct answer is white on white, that means there is no contrast and we cannot even see the white dots anymore. It is difficult to see the black dots as well, but this could be remedied by choosing a brighter panel background color.

Alright, but I could still solve this issue in one obvious way, which is to make the solved panel color be something other than white, or make the white dot colors be not as bright, both of which are shown below.

solveddicepanelsnotwhite

This is fine a fine solution, apart from my other reason for choosing contrasting colors, which is simply for the aesthetics.

Where are the Dice?

There are puzzles later in this area which have more dots per each tile. The patterns of the dots are the same as those which are found on the faces of dice or dominoes.

domino

Notice something about how dice and dominoes are colored? Notably, they are colored for contrast. Black on white or white on black.

There is another aesthetic consideration when it comes to the coloration, which you will find at the top of this blog, but I’m reproducing below in case I change the blog design later on:

panel_title_img

If I take as a solution to change the solved color or the dot color, we would get the following:taijipanelvariations

Neither of which really look very good or imply what the original means to. This is a somewhat less important point than the previous one about the dice, but I believe it still stands.

Okay, so you may be thinking about one other possibility which I have not thus far entertained. Why not simply outline the white and black dots?

dicepaneloutliningissues

The issue here is, I think, quite apparent. I just don’t really have the pixels to go around to properly outline them. The five white dots on a white background is just a mess and doesn’t read properly as five dots.

Perhaps if I make the individual tiles bigger?

dicefaceoultinedbigger

This solves the readability issue, but my concern now is that it is not very apparent which of the two possibilities is correct simply based on the visual.

Anyway….

I have perhaps rambled about this one point for long enough, but suffice to say it is not a problem that is entirely simple to solve, and I wanted to be clear about how much I have thought about it. I think I have a bit of an idea on how to mitigate the issue with future players, however. As I think a big part of the confusion is the lack of awareness of why they are even that way in the first place. So, I will try priming players with the idea of dice before they enter the area and this may help them to make that connection.

Even if it doesn’t, I have not had a ton of testers complain about this issue, and I believe I have at least two other minor changes that can be easily made to reduce confusion in the area.

24. I’d Appreciate Input

I’ve been extra busy the past two weeks prepping a build for testing, so I unfortunately forgot last week to write a post about what I’ve been doing.

It’s been around 8 months since the last test build that I did, and just testing out the new interface would’ve perhaps been enough, but instead I decided to make some changes, both to the existing areas as well as putting in a first draft of an area for the dot mechanic.

I made a list of tasks that I wanted to accomplish for this specific test build, and set about doing those a bit more diligently. I’d say this is generally a good idea if you want to ship anything: to set out the bullet-points that you need to hit and focus your efforts there. Unfortunately, I still took longer than I expected and didn’t get all of the things on the list done, primarily because I kept subdividing and expanding the tasks.

One of those tasks was to provide a basic tutorial at the start of the game, essentially just a readout with the controls floating in the area near where the player first starts. The issue there is that in order to show the proper controls I need to know if the player is using the mouse/keyboard controls or a gamepad, and it was surprisingly difficult to get this type of information with the input system that I was using.

That system was what I think was a pretty standard system built with the default Unity input system. I had inputs with labels like “Run Button” and “Toggle” and those were mapped to different actions in the game, and different buttons and keys. Unity doesn’t really support automatically remapping these inputs to a bunch of different controller types however, so I had to make a system on top of that where I would have a “XB” and “PS4” version of each input label and then just use some string concatenation to build the proper input strings at runtime based on the name of the input device (which unity thankfully does let me access). But by the time the inputs got to my code, I couldn’t tell whether or not they were coming from a controller or not, as both the XB and PS4 versions of inputs were doubly mapped to keyboard controls as well.

So, I decided to rip out and replace the entire input system in order to get that functionality, as well as to simplify the whole thing for any future input complexities.

In Unity, there’s really only so much you can do without just writing an external dll and handling the input at the OS level (which I may still consider doing). It seemed like the simplest and most straightforward thing to do was to get all of the raw input data that I can out of Unity’s system and then handle the rest entirely in C# code.

The way this worked out in practice was pretty straightforward for the buttons, as unity will just let me poll the event system and has keycodes for all joystick button numbers. With the axes however, I needed to set up input types in the Unity editor just to be able to collect them. I named the inputs “joystick 1 axis 0” through “joystick 1 axis 9”, and set them each to get the axis that matched their name. Although it’s a bit janky, with some string concatenation I now can get all the input info pretty easily into the scripting layer of Unity.

So, once I have all this input data, I need to know what to do with it. In a similar way to the previous input system, I get the name of the controller from Unity and compare it against known strings for each controller type (Xbox 360 or PS4, at the moment, as that’s what I have to test). If I find a controller matching that type, then I set the button mapping for a virtual controller (sort of a platonic ideal of an xbox 360 gamepad) to be equivalent to some pre-mapped structures which simply store the relationship between say, the A button, and a numbered button for that actual controller according to the Unity input system.

I also store another virtual controller for the PC inputs, but here there’s not really an input map. I simply hard map certain keyboard keys to the equivalent buttons. The mouse is stored separately, as it doesn’t exactly correspond to a controller input.

Additionally, whenever I poll each input (whether it be a keyboard press or a button), I update a variable which says where the last input came from,. This is then used to update the final virtual controller state that the game sees. I can also use it later to tell which virtual controller the latest input came from.

Perhaps it’s a bit difficult to explain, but I’ll try to diagram it below:

inputsystemdiagram2.png

Overall, I am pretty happy with the results, and it solved the problem of knowing whether or not the player is currently using a controller or the PC controls. However, I still have some old virtual controller management code sitting on top of all of this that I would like to eliminate before I call this system completely rebuilt.

I plan on writing another post this week on some of my thoughts about the testing feedback, but for now I think I will leave it at that. 🙂

Oh, and here’s what the current controls readout looks like in game:03-20-17_20-10-10-1010.png

21. Dots, Recursion, Optimization, and More?

This week, I spent some more time designing puzzles for the “dot” mechanic that I mentioned in the previous blog post. I currently have about 60 puzzles sitting around in the world using this mechanic. Definitely take that number with a grain of salt as these are rough draft quality puzzles, and I will probably cut a bunch of them.

02-20-17_23-08-19-819
“The dot mechanic”: these are some intermediate puzzles.

Still, it’s been fun designing these puzzles and seeing how much I can wring out of just the baseline, without even including the other mechanics of the game. There is a lot of depth and subtlety, and I really think I probably have just scratched the surface what’s there.

In addition to building out this area, I created a functional prototype of an area that I’d been thinking about before I even started building the game (at least as far back as June 23, 2015, which is the modified date on an old Google Doc where I wrote the idea down). I wasn’t really sure how this area would work at all because the concept was a bit strange, but it actually seems to work well and I am happy with how that is going. Unfortunately, to tell you what the concept behind the area is would be spoilers, so I will just leave you with a mysterious screenshot.

02-20-17_23-14-24-1424.png
What could it mean?

Brute Force Puzzle-Solving, Optimization

So, another thing that I was thinking about for a while, and in particular with regards to designing the dot puzzles, is that it is sometimes difficult for me when designing puzzles to figure out if they have degenerate solutions. By which I mean, I usually am putting a puzzle in the game because I found that it has an interesting and unique solution, but many times I am unaware that there are alternative solutions which may not be nearly as interesting or require as clever thinking on the part of the player.

To that end, I felt that it would be useful to be able to see all the possible solutions for any given panel. This seemed like it would be fairly easy to implement, as it just means using the computer to go through all the possible states that a given panel could be in and checking to see if the panel is solved in each state and keeping a list of all the solved states. Sadly, it was not as simple as I dreamed.

First, even just the basic task of iterating through all possible states for a panel was difficult to figure out how to accomplish. Ultimately, the solution came via mokesmoe, one of the viewers in my twitch chat. It’s a fairly simple algorithm to implement, but it uses recursion and so is a bit hard to wrap ones brain around. But it works and it covers teh whole possibility space once, and only once.

Still, when it came time to test it out, it very quickly became apparent that it was not going to be practical past a very small panel size. Mathematically, this is pretty easy to figure out, as the number of possible states grows exponentially with the increase in panel size, doubling for each new tile that is added. Even a 5×5 panel was enough to lock up Unity completely to the point that after a few minutes, Unity’s built-in crash reporter killed the process and offered for me to report a bug to their developers.

I shouldn’t have been too surprised though. Even though a 5×5 panel seems small, there are 33,554,432 (2^(5*5)) possible configurations that it can be in. If you do anything 33.5 million times then it’s gonna take some time. For example, if each solution validation only took half a millisecond, covering everything would take 4 and a half hours of processing time. (Someone else can double-check my math on that)

So, I set out about trying to optimize the code, both in the coverage code, and in the solution validation code. Sadly, it was a bit difficult to profile what was happening because the Unity profiler and recursion don’t seem to mix very well. Lots of killing Unity.exe from task manager ensued.

Eventually, by pulling some variables out of inner loops and reducing the amount of dynamic memory allocations, I was able to get solution validation down to where it takes less than .05 milliseconds.

Still, although this makes the brute-force solver much more practical, this doesn’t prevent the possibility that some panels will just go into what is basically an infinite loop. So, as an additional precaution, I just added a timeout which will kill the solution search after a certain number of cycles and just consider it “un-brute-forceable.” This basically is just a cheat so that I don’t have to worry about Unity hanging. (Although I still seem to have a problem with some puzzles hanging anyway, so it’s perhaps possible that I’m not doing a thorough enough check (maybe I should just check recursion depth too?)).

Anyway, it was fun to do some optimization work there, but I think mostly I’m still being bitten by both the limits of current technology (we don’t have quantum desktop computers yet), and the limits of high level languages (I don’t really think it should be as slow as 0.05 ms per solution validation on a 5×5 grid, even with the fancy recursive solution validator I have for some of the mechanics)

 

19. Finalizing Up the New Interface

First, I’d like to notify anyone who is following the blog that I have recently been streaming development of the game over on twitch, so follow the channel there and ask to be notified when it goes live. If you missed the stream, you can find a complete archive of all the development streams on my YouTube channel.

So, at the time of the last entry, I was struck with the problem of resolving the ambiguity between the point-and-click type panels and the walk-around type panels, in that they looked pretty much the same. I was also considering abandoning the point-and-click interface as a solution.

This week, I did some more iteration on the artwork for the snake panels, and I’ve reached something that I’m pretty happy with, overall.

Primarily, It is clearly distinguishable from the point-and-click panels. But it also solves a lot of the other small issues that the panels had: The start tiles are clearly elevated compared to the other tiles, and for panels where the player can start on any tile, the startable tiles subtly depress and show a small highlight, encouraging the player to press a button to activate the panel.

newsnakepuzzledesign.gif

I did some other cool interface readability work, but I won’t post it here because spoilers!

The Nitty Gritty Stuff

Mostly though, this week has been technical work.

I did some general performance optimizations when it comes to the panels. They weren’t running terribly, but it seemed like a good time to clean up a lot of the code because I am close to finished with the new interface and know what I need to keep around. Also, there were just some dead wrong things I was doing with regards to solution validation on panels that were eating up CPU cycles. One of them was a bit of a “how did this ever work?” type issue.

Another nice to have feature, which really doesn’t impact the player’s experience much, is Unity’ live script reloading feature. I had broken it at some point for the puzzle panels, and I took the time to investigate why and fix the problem. It was relatively simple, with the only real issue being that I was storing some gameObject references using multi-dimensional arrays, and (amazingly) Unity does not serialize multi-dim arrays.. In order to fix that, I just replaced the multi-dimensional arrays with single dimensional ones and just use [x+width*y] every time I want to access them. I’m still not super happy with this solution, but it at least got the script reloading working.

There was a minor additional snag when trying to get the script reloading working. Which is that even though it was actually working, I couldn’t tell because part of my code didn’t think the panels were visible on-screen and was disabling them (premature optimization bites me again!) The issue here was again just serialization, although most of the panel was getting serialized properly, the bounding box structures that I use to determine visibility were still getting destroyed on script reloads, so all the panels would fail the visiblity check on script reload. Oops!

The rest of the work that I did this week was just about ensuring that all of the existing puzzles are still solvable using the new interface paradigm. There are currently 138 puzzles in the game, which may not seem like a lot, but it’s enough that it can be a bit hard to remember what features all of them do or didn’t use.

As of now, there are only two more small things on the list to implement and the game will be fully playable again, which is great.

Only major bummer is that I have a cold, and I have to go back to my day job in three days.

8. Optimizing Panels

This week I did some nice polishing work on the panels in order to make them look nicer. I also switched the game from an orthographic camera to oblique rendering. If you have no idea what that is, essentially it means that the game is in 3 dimensions, with the third dimension simply being represented as an offset on the first two. It’s the method that most 2D top-down games use to render their art, although usually it’s not actually computationally represented as 3D objects.

The nice thing about moving to oblique rendering is that you can put 3D objects in the scene and they “just work.” I really only switched because for the snake panels I wanted to do an effect which looked like this, where the individual tiles popped up and down:

snake_puzzle_protoanimbig

There is a problem with doing this in a completely 2D method, because then you need to worry about sorting of the individual tiles. Although this is not a particularly complicated problem, it just seemed easier for me to switch to an oblique rendering mode and make each tile literally pop up on the Z axis.

I may regress on this decision at some point, but really there’s no downside to rendering with this method, as if you keep everything on the same z plane, it’s exactly the same as 2D. The main issue that kept me from going to this method earlier was a weird sorting bug, which I eventually tracked down to the fact that my multi-pass rendering method (which I use to get smooth sub-pixel motion that preserves the sharpness of pixel art) was set up to use a render texture without a depth-buffer.

But as for the actual 3d objects part of it for this particular effect, I may change my mind, as I want to have tiles both on the floor and on walls, and due to the way the projection works, the tiles on the wall would need to be rotated along the Z axis to properly be drawn, which would require changing the way the panels work somewhat. Either way, it shouldn’t be too much work to switch it over.

Here’s a (poorly compressed) clip of the results. I think it’s pretty close to the above mock-up:

 

Optimization

The only downside to doing this polish work is that I ended up adding a lot of fancy interpolation and additional detail objects to the tiles on the panels, which resulted in some performance issues. The game got down to running around 20fps on my (reasonably good) desktop PC.

So, I decided to take some time to do an optimization pass on the game. Which was pretty fun. I relied quite heavily on Unity’s built-in profiler tools, which can be very helpful sometimes and not really helpful at all other times. In particular, I’m still having a NullReference issue on script reloads which I am not really sure what to do about yet. I’ll have to build a small test scene to really track that one down.

I won’t go too much into the details of the optimization, but I did want to point out a couple of fun things which I learned.

Color == Color is quite slow in Unity because under the hood it is doing a approximate equality test. So I gained a 10x speedup just by switching to a component-wise test on color equality. I know, I know, you’re not supposed to directly compare floating point values, but in this case I believe it was acceptable as I’m only trying to see if I already set a value or if just changed this frame. You might ask why I didn’t just use a has_changed flag and a setter function. And the answer is somewhat complicated, and mostly has to do with having a lot of state that is not being properly tracked in one place at the moment. Which means I probably need to redo a lot of the panel code to consolidate the state tracking and so something a bit more of a FSM per each tile than what I’m doing.

The other interesting thing was, there was a serious overhead just from the number of active GameObjects I had in the world. (Over 10,000) For active GameObjects, at least those with an attached script, Unity has to call the Update() function on each of them, even if it immediately returns. The optimization here was pretty simple, just disabling panels when they are not on the screen.

Another little bit there that was kinda wierd, I was using Unity’s built-in Bounds object to store the boundaries of both the screen and the panels. Unfortunately, again, accessing Bounds.min and Bounds.max was secretly under the hood doing some computations to figure out those values, as they are not actually stored. And since I was checking each panel each frame to see if it had become visible simply by comparing the bounds, and there are over 200 panels in the game, that was contributing a few milliseconds just by itself. A fairly simple fix again, just cache those values and compare the cached versions rather than using the Bounds object directly.

Perhaps the lesson I’ve learned here is to avoid using the built-in Unity types as much as I can, as they all seem to do unexpected and somewhat computationally expensive things under the hood when you are just attempting to access a value or compare equality. Also, the dangers of overrides.

Anyhoo, a bit of a technical week, as I continue implementation of the new interface system, but hopefully it’s been fun to read about some of those details for some of you. 🙂

 

 

3. Damn the Interface, Full Speed Ahead!

This week I didn’t really get a chance to work on the game very much. Was busy with some other things (podcasts, getting stuff done for Patreon backers), and I had a major depressive episode. However, I did work on the game a bit today and streamed some designing of a new mechanic. We’ll get to that in a bit, but first I wanted to talk about some of the things I’ve been thinking about through the week whilst not “actually working.”

Interface Options

The interface problem continues to haunt me, so I’ve been thinking about that a lot and I’ve really narrowed it down to three main options:

Option 1

Keep the current interface and just press onwards with all of its problems. I don’t really like this option for obvious reasons. The current interface is super modal and it just feels kinda bad to interact with a discrete tile-based movement system in 2016 (or whenever the game is done). However, all of the game’s design has been done so far using this interaction method, so it naturally requires the least amount of redesigning work to proceed with.

Option 2

Replace everything in the interface with a “player as cursor” type model, where you’re always walking around on the panels to solve them. The primary issue with this method is that it is a bit incongruous with the way some of the puzzles already work (some of which I rather like), and reconciling this problem either requires some kind of ghost player to walk around on panels that the player cannot access and/or requires introducing the ability for the player to walk up on walls. Or both. So, although this is a promising approach, it entails introduction of some new mechanics that I am not sure that I can really capitalize on in any other major ways besides just using it as an interaction method for panels. The walking on walls thing is certainly cool, and plays off the ambiguity of a top-down perspective in a very Escherian way, but again: I’m not really sure I know how to capitalize on that in a good way. I feel like I’m likely to fall into the pit of bad level design that early-era FEZ did. On the other hand, it is an interesting and somewhat potentially mind-bending mechanic, if I can solve those problems.

Option 3

Giving the player a pointer type cursor which can be used at any time. This is a somewhat nice solution because it can probably be done without any sort of modality, just mapping the cursor to the mouse or to the right stick. However, it again is pretty weird in that it feels like you’re controlling two things and you need to mentally switch modes. But it doesn’t have the problems that the always walking on panels method has, in that you don’t always have to be walking on panels, and you don’t have a player shaped cursor that doesn’t really act like the cursor. The cursor looks like a cursor and the player looks like a player. It also has some interesting gameplay implications in that the cursor can be used on any panel that the player can see, even if they cannot get to it. It does however beg the question of the layer 2 type puzzles, as the player will probably expect to be able to interact with tile looking things in the environment. (Admittedly a problem with the other methods as well, but perhaps to a lesser extent?)

So, I’m not sure which of these approaches I really want to choose right now, as I haven’t totally fallen into that sweet spot where everything just clicks and it’s obvious which is the most elegant way to proceed. It may just be that I have to adopt some sort of hybrid approach. In fact, let’s call it:

Option 4

Take the pointer type cursor aspect of Option 3 (We can maybe implement it as a fairy?), and combine it with the walking around aspect of Option 2, so that the player can solve panels that they are walking around on just by walking around and pressing the buttons, without using the cursor. But they do have the option to move the cursor around and activate a panel which they cannot reach. Perhaps the fairy is the thing that bonks its head on the panels to make them do things? Fairies are kinda magical, so maybe this also ties into the storyline aspect of the protagonist having some sort of magical ability to interact with the panels. Also the “oh you have a fairy” sort of calls back to Zelda 64, which is maybe cool. STEAL IT!

Orthogowhatnow?

So, I decided to put together a bit of a prioritized todo list (well, actually I already had one, but I finally took a look at it and struck some of the completed tasks off the list and added more new ones). Although I think that the interface problem is really the most pressing thing, since it affects so many other decisions, I decided to forgo doing any actual work on that and instead implement a new mechanic idea that I had a couple days ago when I was driving into work.

Jonathan Blow and Marc Ten Bosch gave a talk together at IndieCade several years ago called Designing to Reveal the Nature of the Universe (excellent talk, I recommend checking it out), in which they set out a list of aesthetics for game design. I won’t recount the whole list here, but the one that I was thinking about that led me to think of a new mechanic was “Orthogonality.”

If you don’t know what orthogonality even means (which why should you, it’s a long word and ugh math), it technically refers to the general property of two lines forming a right angle, across 2 or more dimensions. However, for the purposes of this discussion, it basically means design concepts which do not overlap with eachother.

A Tale of Two Mechanics

Some mechanical spoilers below.

So, I was trying to think about some other types of symbols to put on panels that might introduce constraints and create more puzzles and interact well with the existing symbols (just the dice faces at the moment). Earlier, I had thought about odd and even, but the issue there I realized is that there is significant overlap with the dice face puzzles. They are both about the total area of a shape. As an example, if you were to have a panel which had 4 symbols on it, each on different tiles: a 4 dice face, a 3 dice face, an odd symbol, and an even symbol. The solution would probably be: oh I need to put the odd symbol with the odd dice face and the even symbol with the even dice face. This observation about the single solution quickly turns into a generality about the puzzles.

This might seem fine, but to further illustrate my point of why this is a bad choice of mechanic, I will posit the following question:

“Are there many situations in which this new mechanic (the odd and even tile constraints) could equivalently be expressed using an existing mechanic (the dice face constraints)?”

I would posit that the answer in this case is yes, which generally means “don’t do it.” I could go into a lot of specific examples of how they are equivalent mechanics, but I will just give one and move on.

If we were to take the following panel, wherein we say that the 0 is required to be part of a lowlit area which is odd and the 1 is required to be part of a lowlit area that is even:

image

The possible solutions would be as follows:

image

Although we cannot entirely duplicate the same panel with the same set of solutions, we can cover the bases and achieve very similar results across 3 different dice face panels:

image

Whose complete solutions are as follows (note that in addition to covering the solutions of the odd/even one, the leftmost panel has two additional solutions due to the way in which dice faces combine with eachother):

image

“But Matthew!” you say, “look at how many solutions there were for that one odd/even panel, and you’re trying to say that a mechanic which cannot duplicate that solutions space without three separate panels is BETTER?”

To which I would say, “yes.” And the reason being is that sometimes having a tighter solution space is actually a much better thing. And even if you were to disagree with me on that (a fair choice), the argument is really about whether or not to add the odd/even mechanic in addition to the dice faces.

Clearly, I would say, the answer is no.

The New Mechanic

So, while looking for orthogonal concepts, I happened across the idea of having a tile care about the state of its immediate neighbors. This is nice because it has nothing to do with area, and only has to do with the fact that the tiles are on a grid and each tile has up to four neighbors.

So my initial implementation of the mechanic was for each tile to care about how many neighbors it has that are lit up. This is perhaps fine, but it seemed to have two problems.

First, that it was too prescriptive. I tend to avoid puzzles and mechanics that basically feel like I’ve envisioned an exact solution and merely laid down some tiles to enforce that you draw that line or whatever. This has a lot to do with my desire for bottom-up puzzles and things that I have discovered rather than just pulled out of my ass.

Second, I felt like the “is it lit up or not” aspect was an additional point of overlap with the dice faces, which already care about being lit up. It may come to a point where I want to separate out that aspect of the dice faces themselves, but at this point, I’m letting them care about what’s lit up or not, so it seemed like the new mechanic shouldn’t care.

So, what I decided to change the mechanic to is instead an equality check, simply enough each tile cares about how many neighbors it has that are the same as itself. This has the nice property of opening up the solution space a bit more (even though sometimes it’s better to have a narrower solution space, I tend to feel like it is a sweet spot in the middle that I’m aiming for), as well as making the concept fully orthogonal to the dice faces.

Here’s an example of one of the puzzles that we discovered on stream which I particularly like. (I’ll leave the solution as an exercise for the reader. Keep in mind, yellow means “the same as me” and blue
means “not the same”.):

image