The Finish Line

This post is a little late but…

I FINISHED MY GAME!!! The Game is done and Published on the Google Play Store. I actually published my game a few months ago, just before the New Year, but life kept happening and I didn’t think to make this update here.

The last steps of publishing were simultaneously more and less frustrating than I thought they would be. It was more frustrating because the interface Google provided didn’t do a good job of explaining some of the steps I needed to do. Example: It would tell me I did something wrong in one section of disclosures. But not tell me what I did wrong or what I should have done. Thankfully this was fixed by simple searches online to find the steps I needed to take.

Paradoxically the ease of some of the steps made me uneasy. I kept expecting something to go wrong. Something to become a brick wall. For the other shoe to drop. And it never did. The stress and relief cycle was a roller coaster that left me exhausted some days. And all of that is not to mention my programmer/IT instincts screaming that if “everything just works” that I have overlooked something critical.

But all of that is done now. So, what’s next? Right now I am doing some personal work so I don’t think I will be doing much on Sky Lights for a while. I might try to eventually get it on to the Apple App Store but I will see how that goes. As for my posts here, I will try and post more regularly. But the subject matter is going to be all over the place. We will just have to wait and see what I write about.

The Last Hoops

So, I am at the finish line for getting my first game available to the public. There shouldn’t have been any last minute hoops for me to jump through. But… of course… as I have learned, there are always more hoops to jump through. Here is a recounting of the last (crossing my fingers, knocking on wood, and throwing salt over my shoulder) hoop I had to jump through for this process. That way, if someone else encounters this hopefully they will find my recounting helpful.

What Happened?

I finally made my 1.0 build to upload and push my store listing to live. I uploaded the build, sent it for review… and got an error. The Google Play Console was telling me that it detected my app as collecting a type of data and I had told them my app didn’t collect data. I had only limited knowledge of what this could be.

My app has an In App Purchase (IAP) so that had to be it. But I had no idea of what, within the context of their system, they were looking for me to declare. And the automated system was no help whatsoever in identifying what I needed to declare.

What Did I Do?

Eventually I found a “submit for review anyway” option, letting me know I was bouncing off the basic automatic check system. (More specifically it was under the “If you think this judgment was made in error” section all the way at the bottom) So I did that, knowing one of two things would happen. Either it would go through or I would hopefully get a more helpful bit of feedback.

And I did get a more helpful bit of feedback. Apparently the data I used fell under the “Device Or Other IDs” description. My usage should be ephemeral (meaning stored only long enough to use it) and upon telling this to Google’s form I was able to submit for review without bouncing off or getting a quick rejection. Then, after a day of review, it was accepted. And I was able to go live.

Lights Out Progress Report

So, where am I in the development of my game? For a while it has always felt like I am almost there. Almost at the finish line. Then I find something that needs to be fixed, or can easily be improved upon, or was a placeholder that I just got used to. And it keeps getting extended. So where am I?

What I am Doing Now

Right now I am focusing on cleaning up the “level select” mechanic. Initially I had a simple level select as a menu that could be called up in the game scene itself. But I was never completely happy with it. It was small, no room for more buttons, going large jumps of levels took a while. Lots of problems, but a good proof of concept.

Now I have a level select in the main menu before you transition into the game scene. With buttons to go both small jumps and big jumps. Even text to tell you where the earliest uncompleted puzzles are so you can go back and do any you skipped.

Originally I was going to remove the level select from the game scene. But the longer I look at it, the more I think I can just polish it up a bit and keep it. But this might just be not wanting to discard work I have done.

So What is Next?

Next is three things. First is to finalize a design choice I have been fiddling with in the background for a while. Next up is to decide how this game will be distributed. The two main options are: free with ads or small upfront price with a free demo version to get people interested. Based on which of the two I go with I either need to design where the ads go, or figure out what I will strip out for the demo version.

And then I should be almost done… unless I find another thing to do.

Returning to Old Problems

As I started working on my game there were one or two things that I came across that I didn’t fully understand. Okay, there were a lot of those. But one or two I got to a “good enough” state and moved on. Well, that came to bite me in the ass recently. Specifically with the Canvas Scaler. Most of my game’s visual elements are UI objects, as such they scale to the camera to always be in a specified relative space on the screen. But how they scale is determined by a multitude of factors, starting with the Canvas Scaler.

I won’t get into the minutia of the Canvas Scaler here. But put simply you can choose to set a maximum size, minimum size, or a scaling style for the UI elements. Took me a while to decide what was best for my project, and I am liable to change it again. Before my recent dive into the Canvas Scaler, some objects would scale strangely and end up off screen. And then I figured out why… and it was dumb.

A common way to organize Unity project game assets is to group them under “empty game objects”. These objects are 1 dimensional points in space with no physics, but are useful for grouping objects to make the scene more manageable. They can also be used to apply a single transform (movement, scaling, rotation) to an entire group. I was using these empty game objects for both purposes. Making my scenes easier to manage and to move objects as a group. Unfortunately, UI elements and normal game objects don’t play nice together. And by grouping UI elements under an empty game object I disconnected their scaling from the Canvas Scaler. I needed a new solution.

Thankfully the solution was staring me in the face. I had already been moving UI elements independent of an empty game object, so I just needed to find a UI element that could stand in for one. And I did. It has a few kinks to work out (mostly from adopting it so late), but it shows promise.

Setting up for More Playtests

Last time I talked about feedback from playtests. But that is actually putting the cart before the horse a bit. Because obviously before getting feedback you have to have a playtest. And before you have a playtest you need a test build. And… well let’s pop the stack and start at the beginning.

First step in getting my game ready for playtesting was to remove the development objects. In short I have an object that keeps track of a bunch of data between scenes. This object gets created when you start the game, never unloading. But when testing my game during development I don’t want to navigate all the way through my game just to test a minor fix. So during development I just put that data holder object in all the scenes. There are a few times I have to remove it in order to test some things, but they are few and far between.

The next step was shoring up the “in progress” items. This time it was the settings tab in the main menu. I ended up removing a part of settings that I had thought might be a good idea, but latter developments had rendered unneeded/clunky/over complicated. This left me with a slap dash UI design, but everything is functional so good enough for testing.

After a few more last minute fixes/finishes It was time to make a build. This part was easily the most straight forward. Just click the button labeled “Build Game”, give it a name, and wait for it to finish. Installing it on the target platform was a little more involved, but only marginally so.

The biggest hiccup I encountered was attempting to install the game on one of the target devices. It was an older phone no longer in active use (no sim card) and just getting it set up was a bit of an ordeal. But then the real problem showed up. It just refused to install the game. So, bad news: the main device I was going to let people test the game on won’t work. Good news: I could install it on my main phone, and might be able to find another device to use.

Out of Date Tutorials

One of the greatest strengths of my generation (and the following generations) is that, by and large, if we don’t know how to do something, we just look it up. The internet has put most skill sets a few searches and minutes or hours of research away. Don’t know how to format that file for your presentation? The internet can tell you. Don’t know how to make a resume? The internet has plenty of examples. Don’t know how to change the oil in your car? The internet has plenty of tutorial videos, probably even has one for your make and model.

So why do I bring this up? Because there are plenty of programming things that I have no idea how to do. And so I go look it up. And I usually find a way to do what I am trying to do. Or a way to do a similar thing that gets the job done. Along the way I usually find at least one thing I wasn’t looking for, I didn’t know, and could be very useful.

So, onto the point. I have been getting close to the finish of my game… and finding these last few steps the most annoying, mostly by virtue of going in blind. The step I am working on now is integrating adds into my game, so that I can hopefully make some money from this. But, as the title suggests, the first tutorial I found to do this was out of date. The tutorial was less than a year old, and at first it only looked like some cosmetic UI changes had been made in the process since the tutorial was made. But… once I got to the coding part of the process, everything started returning errors. That is when I knew something was wrong.

But As stated above, I just searched again. Quickly I learned that the tutorial I was using was for version 3 of the integration and the current version was 4.3. Understandably the process had changed significantly. But a new tutorial was quickly found, and the fundamentals were largely the same. It just used different tools to accomplish the same thing. Importantly the new version did allow for more control. However even the old tutorial was not a waste of time. As I learned a useful bit of programming to do something I didn’t know how to do (but which I knew must be possible). And, as with the old tutorial, the new also taught me something I didn’t know. But more importantly this new tutorial explained why it would be useful. After all, simply knowing something is no where near as useful as understanding it.

Reviving Discarded Ideas

In game design it is an all too common thing to get an element 80% working, and then decide it doesn’t fit. Or perhaps it doesn’t mesh with who you are doing something else. Or you go in an entirely different direction. The point is that you will have many ideas that get left in the dust. Many might even be fully functional before you discard them. But how you discard them is important.

One piece of writing advice that has always stuck with me is to write the first draft. Then delete that draft and write it again. This stuck with me because I can see the logic of it, but it is so antithetical to how I do things. The logic is that now that you have done the thing it will be easier to do it again, but better this time. And it actually makes a lot of sense. But, a part of me is violently opposed to destroying my old work. If I ever try this piece of advice, instead of destroying the old work I would seal it away out of my reach.

Back to game design, I am a strong believer in making multiple “save states” of my work. These save states are snapshots of different points in development. Often when I make these I need to duplicate all the scripts and prefabs I use so that I can leave the old version alone and largely functional. But what does this have to do with reviving discarded ideas? Simply put, when I discard a piece of code I have written I very rarely delete it. Perhaps I comment it out. Or I leave it in an old version. Or I simply remove the script without changing it at all, just leaving it in a file somewhere for latter. What this means is that if I discard something. Then decide I need it after all later on. It’s always there, ready to be revived.

Eventually, I’m going to have a hell of a time cutting out all the extra files I don’t need in the final build. But in the mean time, I have the entire history of my design process at my fingertips. And that means that while an idea might be discarded, it isn’t gone.

Navigating the Web of Scripts

When I need to add a new feature to my game I need to code it in (Duh). But it isn’t always as simple as that makes it sound. Each scene is it’s own world and what I do in one scene does not always translate to another scene. No, if I want something to carry over I need to set it up special. Thankfully I long ago created an object that carries over between scenes, its entire purpose is to carry variables between scenes. But interacting with this object can get a bit weird at times.

One of the main reasons for this is that each time I load a scene my scripts have to go and find that object (Named dataHolder). And you might think this would be simple: “On start find thing” and it is… until it isn’t. You see I discovered something about the Start part of scripts. If you have more than one in a scene they all try to run at the same time. Doesn’t sound too bad, until Script B needs Script A to have set something up, but Script A hasn’t gotten there yet.

My solution? Have only one Start section in my “controller” script and have it access functions of the other scripts that run what their Start sections would have run. But how does this relate back to my dataHolder?

I needed a new variable for volume control, so obviously I would shove that in the dataHolder. But what would access it? Now the solution should be obvious to you, after all I just spent two paragraphs telling you why it is the solution. But my first instincts where to have the script that needed that variable go looking for it. But when that one variable turned into 2 or 3 variables and one needed to be translated from one form to another… not a viable solution. So shove it in the controller.

And I went to do that. And everything just seemed to work. Nice and simple, barely any programming involved. Makes me suspicious any time the solution is so easy. But this time I think it really was that easy. Because I put it in the right part of the interconnected web of scripts.

Simplicity in Brute Force Solution

In my game I have a hint system, standard in puzzle games. But my system always gave the hints for a given puzzle in the same order, top down, left to right. I felt this was stale and uninteresting. So I decided to add a random element to the order in which the hints were given. So I tried a method I thought of, involving a nested while loop, several variables, and a random number generator. Everything looked fine… until I tried it out.

It would work for a few presses of the hint button, and then the entire application would freeze. Most frustrating of all however was that when it froze it would not display any of the debug commands I had put into the code. So it was very hard to figure out what was going on. Then I had a brain wave. My first method was selecting one of the hints to display at random, then finding that hint to see if it had already been chosen. In the new method, I chose a random square and checked if it had a hint to display. Basically getting the same result by doing the process “backwards”. In fact this new function was half the length of the failure attempt.

All that to say. Sometimes I get stuck on a solution that I assume must be “the best” and refuse to see other solutions. And often times I see this solution as “the best” because “It is so complex it must give a good result. When I really need to remember an anecdote I learned in High School. The K.I.S.S. principle: Keep It Simple, Stupid.

So much to check and so many fiddly bits to bop

I have “finished” pruning the levels for my game. In truth I could spend a great deal more time fine tuning what levels I include, but what I have will suffice. And now I move onto the next step. Now I am going through each scene and checking for any scripts I left in place “just in case” but are now unneeded or redundant. In addition I am checking to see that everything is connected properly. While some scripts can find the objects they need themselves, other scripts need to be pointed at the objects they are dealing with. And now I am in the tedious process of ensuring all those links are correct. On top of that a few scripts need to have these lists updated to account for new or changed objects… Which is even more tedious than simply checking that they are correct.

Next up is an effects review. First I will be checking the scene transition animations to ensure all are acting correctly. Then check the various settings for speed and placement to ensure I am happy with it. With that done, I will move onto the question of if I will be keeping a particle effect on button press for the play area. The central question being if it should remain and be updated to a more theme appropriate design. Or if it should be removed entirely.

And the final short term goal: If I should rework the hint system. Currently, hints are given out in a grid pattern starting from the top left and working across each row. Each press of the hint button gives the next hint in line. This makes the hints fairly predictable. Which can be good. But with a certain method makes the puzzles very easy to solve with minimal hints. The solution? I am not sure if it needs one. But if I was going to change the system I would make the hints come out at random. But… that will take a fair bit of tinkering with systems to make it possible. And I am not even sure if it is needed. So for now I just need to think about it while I work on other things.
And even writing this I think I worked out a solution for the “how to make them random” problem. So progress I guess.