Tagged with: [ games ] [ unity ] [ csharp ]
For a while now, I’m thinking about doing something with Unity to see how it works. And what a better way to figure things out is to try and develop a game with it.
The main idea was M.C. Escher’s lithography ‘Relativity’, the one with the stairs going in all directions.
I wanted to make a cube that can rotate in any direction and where you must collect stuff as a player inside the cube. So, when you are at the bottom of the cube and see a coin at the ceiling, rotating the cube 180 degrees will make the coin get to the floor where you can collect it. You would need to walk on a platform, and based on how the cube rotates, and you can walk at the top or bottom of the platform (think David Bowie in Labyrinth).
So, to start, I fired up Unity without knowing what it is and does. Fortunately, there are some really great tutorials on how to begin with Unity, and pretty soon, I had a simple floor with a texture and some initial blocks on the screen.
I found some fantastic prefabs on the Unity Asset store, lots of them that can be used for free (with some attribution), so I found a few that I like (and still have in the game):
- A low-poly astronaut with neat animations on it, which I currently have no idea how to use.
- Some items like flasks and coins, which nicely spin and bob around.
One tricky thing I couldn’t understand when first using Unity is how to get something like score, time, etc., on the screen. It turns out that you have a camera where you look through onto your game world, and you can “stick” a 2d transparent canvas in front of the camera. On this canvas, you can add images, text, your menu system, etc. There are probably other ways maybe, but in 3d-world, this seems the way to go.
So I’ve added a canvas, some counters like coins left and time left. And some buttons to control the cube in the X, Y, and Z direction (not working yet, though).
I also changed the camera position a bit, so it shows the field in an isometric way. It just looks more likable and gives the player a bit more overview of the puzzle.
The level editor
One thing I figured out that I needed was a level editor. It would be a simple setup to move in a cube and add elements like blocks, coins, etc. This data will be serialized (how?) into a JSON format (what format?) so we can load this into our level.
So from very soon on, I decided I didn’t have many scenes, where each scene was a single level, but one single “level”-scene, which automatically loads the level through a specified JSON file. Not the easiest thing to begin with, but no need to worry about that right now.
The level editor would be and stay simple:
Since there was still a lot to do before I could even consider loading and saving the data from the editor, I created a “playground” scene, which was a copy of the level scene, but where I manually made a level inside. This way, I could continue testing things like cube rotations and player movements without worrying much about all the other not-so-important stuff (in hindsight, I shouldn’t build a level-editor this soon, but it turns out that a lot of knowledge was harvested from creating the editor, which would have taken longer if I didn’t do it).
Slowly going forward
One of the hardest things to get right was the movement. Since we are inside a cube, movement is done grid-based too. This was not the best idea because we need to fixate our player on specific positions while movement should be fluent. For example, what happens when a user hits a key when the player moves from one block to another. What if we move forward into the abyss? How do we keep the player straight while still using the physics engine of Unity?
This turned out to be a big issue where I constantly switched from a character control (more control, no gravity stuff) to a rigid body system (less control, more done by the physics engine, nice gravity, etc.).
Either things would work, but jumping looked awful, and we had to do manually code gravity. Or we leave things to the physics engine, hoping we don’t slide of blocks and such.
It turns out that with tweaking of the rigid body component, I finally got something that worked: we could move (although not quite precise) from block to block. We had a scanner that checks if we can make a move forward (only if there is not a block in front of us) etc.
A friend of mine suggested using DOTween for the movement of the player. This turned out to be a great tip because now I could say: move my player from block (1,1,1) to block (2,1,1) and do this in a smooth movement. Also, jumping worked nicely without any hassle.
But there are other things to think about with the movement: how are we allowed to move? What happens when we jump? How can we jump onto a block, how can we jump over an abyss, etc.? Lots of these things seem obvious until you have to code them and then you have to think about it.
Rotating the cube/field
So next up is the cube rotation. Here is where things started to change: I didn’t have a cube (yet), but it turned out that just the blocks inside the cube would suffice as a game level. This way, I could fall into the abyss (or floor), so being inside a cube was unnecessary. Still, I wanted the cube sides to be part of some puzzles (inside a closed cube, you cannot fall into the abyss, for instance), so I kept this as an option later.
I also browsed through the Unity Asset store and found a cool (and free!) Aztec/jungle/temple theme that contained blocks. Immediately the whole level looked a lot nicer!
Also, I found a way to get the player’s animation going during movement, so when the player jumps up, you see the astronaut lifting its arms and landing on its feet back. I just needed to implement the running/walking animations on the block movements.
The main menu
Time for the main menu, the place where you enter the game. Here some real canvas magic happens, mostly done thanks to tutorials found on youtube. After actually understanding the canvas system much better, I took on to create the different panels like an options panel, credits panel, select-your-level panel, etc.
Even though I was proud enough to get it going, it took a lot (A LOT) of effort to work in different aspect ratios, resolutions, mobile formats, landscape, portrait,.. and even switching between them. Nowadays, it probably takes 10 minutes, but learning the different components and how the settings interact with each other takes a long time.
I wasn’t also pleased with the designs, so I got onto Fiverr and found Anneskhan721 who could create nice looking panels.
By this time, I started experimenting with localization. Even though it’s a preview package in Unity (but very close to a stable release), it seems to work nicely without too much effort.
I found in Unity itself that once you get the hang of like 10% of a system, the rest is easy to follow and understand.
Controls were tricky since I’ve moved halfway through the game from the default Input system to the new Unity input system. Although much more complex to set up correctly, it makes it easier to add all kinds of input devices, like game controllers.
I’ve implemented a system so I can use WASD-keys and/or arrow keys for movement, touch buttons on mobile, and even through game controllers (a Nintendo switch controller which I could connect through an Xbox controller plugin on windows).
You will see the buttons on mobile/touch screen enabled systems, and they disappear on non-touch platforms. Since my laptop has a touchscreen as well, I needed to add an option in the menu to hide the touch bars :)
Meanwhile, the editor could save levels into a JSON format, and the level scene could load the JSON, so we have a full working game in essence :)
Since the main idea would be to have a playfield inside a cube, I still wanted to have a cube experience (on some levels). So it’s possible to tell that we want to see a cube in our level-data JSON (actually, you can control each of the six sides).
It turns out that I couldn’t find any nice-looking cube sides. So it took a while to find some. Ultimately, I settled on a grid-like texture, which happens to scale nicely with the blocks inside the cube.
One idea I had was the use of portals. Not only can you rotate the cube to move to seemingly impossible positions, but with the help of portals, you can transport yourself to another part of the cube. This took a long time to finish, much longer than expected for a couple of reasons:
I wanted to have some ‘stargate’ block, where you walk into and come out of another block. This turned out to be a bit hard to do, so I settled on a ‘pool’ in the ground. Transporting the astronaut to the right other side isn’t hard, but the positioning was since the portal can be rotated another way. Not only was the astronaut’s rotation hard, but there are times we need to rotate the cube automatically to make sure the astronaut will ALWAYS turn up “upwards.”
It took some work in redesigning the level-data JSON (elements needed not only a position but also a direction) and took a lot of vector calculations which took a while to get right.
Another thing that took a while was creating the actual portal pool. For this, I used shader-graph and with the help of some tutorials, I got started with drag and dropping some shaders until I found something that looked nice enough.
Since pretty much the beginning of game development, I’ve opted for a theme-like system, so blocks, backgrounds, etc., could all be changed dynamically. I bought a pack containing all kinds of low-poly cubes from the Unity Asset store and implemented some themes.
Some look better than others, and I’m still not 100% convinced if we should do themes, but they are there in case I want to implement them in the final game.
Ads & Analytics
I wanted to have some analytics in the game to see what’s going on in the field once the game will be released. Unity makes this easy, and I got it up and running in no time.
I only target a few key points in the game: When a level starts. When a player dies (and how). When a level completes (and the time it took). This gives me a way to indicate how hard levels are, when players are quitting, etc.
Even though I’m not too fond of ads, I understand they are needed to get some income. So I opted for two ways to do this: have a free version of the game, containing ads, and a pro-version, paid, but with no ads and more levels.
The ads are displayed when a level starts, and there is a 33% chance that an ad is displayed when a player dies. This is to make sure people can continue their game without getting annoyed by ads all the time. I don’t know if this is an excellent way to do it, but I can constantly adjust the ratios if needed.
During debugging, I earned my first 2 cents :p
It’s nice to see that Unity makes these things simple to implement. There are a lot of settings that can be tweaked which I do not know anything about it. But I have to assume the default settings are ok enough.
Although we are almost done, many things still need to be taken care of. More levels have to be created, and tests should be done (maybe hire somebody from Fiverr for this again?). Get more feedback from people to tell me what can/needs to be improved.
I’m not a game developer. I stink when it comes to design, frontend, and an Indie developer I will never become, I’m afraid. But it’s nice to do something different than coding web APIs once in a while.