For Endless Elevator we wanted to do an Introduction Scene for the game. The gameplay, as the name suggests, consists of climbing endless elevators and escalators. The player navigates floor after floor in the bad guys luxury hotel and tries to climb as high as possible while defeating the bad guys. It’s a 2.5D top down scroll mechanism and clipped into the limits of the building. Just dumping the player into the start of the game in the levels of the building felt a little weird as there was no context to where you were in the story. Hence the need for an opening shot to set the scene and to literally drop the player into the game.
Our hero flies into the enemies’ oasis headquarters in a helicopter and storms into the foyer of their luxury hotel. We mocked up a scene and a helicopter in Blender and imported the assets into the main foyer scene of the game. I hadn’t used Unity’s Cinemachine before but wanted to try it out. Previously, in other projects, we had captured gameplay for cut-scenes using external software and video editing suites which was OK but the experience with Cinemachine and Unity Recorder was way smoother. It was much easier to work with and much better quality avi files. Plus we didn’t have to do custom scripts for switching cameras and panning. It was so easy it kind of made me excited about movie making with Unity but you know I don’t need another distraction.
To start working with Cinemachine and Unity Recorder you can download them using the Package Manager. Unity Recorder has only recently been added (it’s still also on the Asset Store) so you need to enable the “Preview Packages” selection from the Advanced menu in the Package Manager.
Below is a screen shot of my scene in Unity. You can see the main building in green and the surrounding buildings and water in the bad guys oasis HQ. The helicopter is just visible down where the camera sight lines join and on the left in the Hierarchy you can see my Timeline component and my two vcams (Virtual Cameras).
The Timeline is where all the magic happens and was very easy to set up.
First we did a few animations on the helicopter to fly it in to the building and make the rotor spin. Then we added an animation to move the character from the helicopter into the building (which looks terrible but remember this is a quick mock up)
We dragged this animation into a new Animation track on the Timeline object (right click and Add Animation Track). Then we created two Virtual Cameras in the scene. One Camera (vCam1) was set using the properties in the Inspector to automatically Loot At and Follow the helicopter. This means that where ever we flew the Helicopter the camera would follow it round from behind at a set distance and keep it in the frame automatically. This was really fun when we had it under manual control for testing and worked well when under the control of the Animator. We used a preset for a bit of camera jitter and shake to mimic a real camera man in a second helicopter.
The second Camera (vCam2) was stationary at the building site but set to Follow (ie. Look At) the Main Character. We timed the cut from one camera to the other so that once the helicopter landed it would pass control to the second camera and seamlessly start focusing on the Player. This was so easy it was ridiculous. The Camera objects were added to the Timeline and the split where we cut from one camera to the next is clearly visible in the screenshot below (two triangles). The first time I ran it and that view cut automatically from one vcam to the other gave me an enormous sense of satisfaction like I’d just been named a modern day Hitchcock.
To record what we had done as an AVI we opened the Recorder Window:
We used the default settings and triggered the Start of the Recording with the start of the animation by having it in the Timeline. The Capture target was the Game View (you can also get the other elements of the Editor if you need it). The Output Resolution is interesting as you can use the Size of the Editor Game window on your screen or set it to standard default movie formats.
That’s about it. We hit Play in the Editor and the Timeline starts the Recording of the AVI and synchronises the Animations and the Camera movement automatically. Once we are done we are left with a good quality moving image of our game screen that we will use as the cut-scene to drop the player into the start of our game. Obviously what we got here is just a “screen test” but I was really happy with what we could achieve in just a few hours and with so little complexity.
This is when we make the collider really big on the coin. If the player gets in range of the collider then the coin moves like a magnet towards him. Which is kinda fun when there is lots of coins around and you feel like a millionaire just by standing around.
First of all – sorry about the misleading title – this post is about getting the doors working in the Endless Elevator game that we are currently developing. I thought it was a good pun and that as this post is all about our development process that it wasn’t too bad. The only career advice I got is just to start making games…any games.
You’d think making a door that opens and closes would be a pretty simple thing to do but surprisingly it wasn’t.
I designed and built some 3D models of building components in MagicaVoxel and exported them as .obj files. I use MagicaVoxel because it’s free and really quick and simple to use. When I model components I can be sure that they are all exactly the same scale and that all the different bits (no matter when I made them) are going to fit together without any hassle. But the models are not optimised for game engines as they have a reasonably high poly count due to the modelling process within the program. Most of the models come out with heaps of unnecessary triangles that need to be managed first. In most cases I will import the object into Blender and use the “decimate” modifier on the planes (with an angle of about 20 if you are interested). In the case of the door object it was pretty simple, it is just a door after all, and I didn’t need to optimise it.
Here is what the door looks like in MagicaVoxel:
Notice that the door object is sitting just forward of the enclosing frame and that when exporting the object the center is at the middle bottom plane of that frame. The door is off center because it’s modelled to fit exactly in a doorway that sits exactly in that position within the frame. This saves me a huge amount of time lining everything up when it gets to Unity as the position of the door (or any other object for that matter) is already in the right spot. The problem is that the point of origin for the door is in the wrong spot. It exports a few units behind the door and on the floor! This becomes important when you try and rotate that object (like you would when opening and closing a door) and the pivot point is not where the hinges should be.
To fix this I had to import the .obj file into Blender and reposition the point of origin for the model.
This is what it looks like in Blender when I did this:
To do it I selected the edge that I wanted the door to pivot on when opened.
Then in Edit Mode:
Mesh -> Snap -> Curser to Selected
In Object Mode:
Object -> Transform -> Origin to 3D Curser
So that puts the curser onto the correct position in the middle of that edge where the hinges would be and resets the point of origin (which is where it will pivot when rotated in Unity) to the right spot.
Once we were all imported into Unity and looking good I set up a prefab for the “Doorway” object with the door as a child object. The doorway object has a bunch of colliders to stop the player walking through the walls and a big sphere collider where the door would be to trigger the open / close function when the player walks into it.
This is what the doorway looks like in Unity:
Next I scripted up a few options for opening the door. I’ll post the script at the end of this article but basically there were three options of opening the door that I wanted to test. (Actually I tried it about six ways but whittled it down to the most simple methods – and just as an aside there is an actual “hinge” object type in Unity if you ever need it).
This is how the script looks in the editor:
Notice the slider at the bottom to control how far I want the door to open. It’s really handy to have this when playing in the editor and getting your settings right. If you want to know more about using it see this post
The three tick boxes are for testing the three different ways of opening the door.
Snappy was a quick simple transform of the position from open to closed with no “in betweening”. It looks a bit unnatural as the door magically goes from closed to open but it’s not too bad and most people are pretty used to similar behaviour in video games.
The active line in the code is:
the_door.transform.Rotate(-Vector3.up * 90 * Time.deltaTime);
The next method works more like a door should. In that it swings open and closed the whole way in a steady fashion. But the big problem with this method was that it was OK when the character was going into the doorway and with the swing of the door but when it was time to come back out of the doorway the door was in the way. There was not enough room to trigger the door opening from the other side without being hit by the door as it opened. Plus if the player enters the collider from the wrong trajectory the character gets pushed through a wall by the swinging door which is sub-optimal. I called this method InTheWay!
The active line here is:
the_door.transform.rotation = Quaternion.Euler(targetPositionOpen);
In an effort to combat this I chose to do a hybrid method that opened the door to a point that wouldn’t hit the player and then do the magic transform to get all the way open. I call this one aBitBoth. It looks a little weird too. Like there is an angry fairy pulling the door closed with a snap after the character enters.
Here are all three to compare.
In The Way
A Bit of Both
I’m not too sure which one I’m going to use at this stage as the Snappy method works best for now but I like the In The Way method better. I looks more normal and I like that you have to wait just a few milliseconds for the door to swing (adds tension when you are in a hurry to escape a bullet in the back). I could do something like halt the player movement from the rear of the door when it triggers to open from the closed side or maybe play around with the radius of the sphere. Neither solutions seem like great ideas to me right now but something like that will need to be done if I’m going to use that method. Maybe I could just have the door swing both ways and open to the outside when he is behind it but that’s probably a bit weird for a hotel door.
The Dog Run is an Endless Runner for Android that supports animal welfare!
It’s a free game. There is the option to watch ads but instead of in game rewards all profits from the advertising goes to support animal welfare and animal hospitals.
The game is about taking your fun lovin’ pooch for a run. But watch out! There is a bunch of obstacles in your path. It’s a good thing your dog is a natural jumper and can run all day in all sorts of weather.
We have been Beta Testing our soon to be released game The Dog Run and it’s been mostly OK but we had a number of issues with memory on smaller or older devices. We made some gains with modifying our audio files (See this post) but were still running into niggling crashes on start up and longer than normal load times.
We were getting feedback like:
“Hey, I installed the game and couldn’t run it. When I started it there was a black screen for about 15s and then it went back to the launcher. Then each time I went back to the game there was unity and game logo fading out and again the app crashed/hanged and I was sent back to the launcher.”
(Thanks slomoian and the_blanker for all your help testing)
Obviously feedback like this is a little disheartening and far from ideal. The game was running fine on every device and emulator I had access to but it’s only when you send something into the wild that you realise the full breadth of the spectrum that is the Android platform. I guess this is another lesson in the importance of proper Beta testing. One we hadn’t learned last time we released an app (see this old post on the perils and difficulty of finding Beta Testers).
We were using adb logcat to monitor our start up problems but not finding a “smoking gun” that solved every case. It seemed to be a memory problem and often with the graphics cache so again we went back to the Unity Editor build log to investigate our image files. The game uses multiple large files to ensure that our animated sprites were always in the right spot. The game is dependent on the titular Dog hitting the ground line accurately on every frame to achieve the look we wanted when he runs and the paw breaks the ground line and appears as a gap. We used a “flip-book” old fashioned style of animation where each frame sits exactly on top of the old frame and everything lines up on a transparency like in classic animated movies.
By using this schema we had to keep to a certain scale that fit within the constraints of a typical Android device format. This meant that when the images were imported the POT was not going to be something we could play with easily to get performance gains. (Image files that have a width and breadth that is a power of 2 are faster and easier for the compression functions to work with – so 2, 4, 8, 16, 32, 64, 128, etc). If I had the chance to do this again this is something I would probably start doing right from the beginning of development. When going through the Editor Logs we did find something interesting (get to the Editor Logs by right clicking on the arrow or tab near the Console and selecting it).
We found that some of our image files were 10 MB and a few were 2 MB. Which was a little weird as they were all exported as layers from the same Gimp file so I must have done something in the import settings or the editor to change them.
This is a comparison of two files of the same dimensions and basically the same content but with two very different file sizes:
10.6 mb 0.8% Assets/artwork/RunOnSpot6.png
2.0 mb 0.1% Assets/artwork/DogSitHeadWag.png
The difference that I found was MIP Maps. I’d selected to use MIP Maps fairly early on as it made the art work look smoother in the Editor. MIP Maps are generated in the engine to make smaller more compressed versions of your artwork that can be used at longer distances from the camera where the detail is less visible. My game is 2D and has everything running at pretty much the same distance from the screen so really MIP Maps should not be required. My art did look a bit better in the editor with them turned on but on a smaller device like a phone I couldn’t really tell the difference. See below the difference in a file with MIP Maps selected and a file without.
With MIP Maps turned on (see the file size at the bottom and that the type is RGBA 32 bit):
The same file with MIP Maps removed (down to 2 MB and using ECT2 compression):
This is the difference that generating those MIP Maps makes. Your file is converted from the Android default compression to a larger (harder to process) 32 bit compression format.
So by turning off MIP Maps across the three hundred plus image files in my game reduced my application start up time to under a few seconds and reduced the APK file size by over one thousand MB.
This is the Build Report from the Editor Logs that shows the larger texture sizes and final build size:
It’s a considerable difference with little or no quality loss on most devices. When I say most devices there were a few cases where the running dog did look a little tatty. On very small emulated devices (3.5″ screens and low memory) the images were being scaled down quite a lot and the results were a lot less enjoyable but still an acceptable compromise considering previously the game would not run on these devices at all.
The next thing I started playing with was the different texture compression variables available for Android. I tried all of the settings (see screenshot below) in a different build and tested them against at least ten different devices with various architectures and screen dimensions and Android versions.
In each of the cases but one there was at least one test device that failed to start the game. Once again exposing the issues of working with so many platform variables on Android. Even when I built the APK with the (default) ETC selected one device failed the start up test. So in the end the final build used the “Don’t override” setting which seemed to work on all devices.
Hopefully this is helpful to someone else out there and if it is try hitting the “Like” button below or sharing the link (the feedback keeps me going).
I found these references useful when troubleshooting my start up issues and learning more about compression on Android:
Let me say straight off that your first port of call for any Unity debugging should be the Unity Console.
Though sometimes you need more low level operating system logging for Android. This is where ADB (in lower case) comes in.
On Windows this is a command line tool to view the logs from a connected Android device.
The command line is not the only way to use the tool sometimes it’s better to use the Android Studio interface (a bit more graphical).
You will need to have your Android device connected to your workstation and USB debugging turned on (Google that if you need to). You could also use an Android emulator on your desktop.
I use Leapdroid or KoPlayer. (Leapdroid have now joined Google and no longer support the emulator but it’s still available to download on the internet). I guess you could also use the emulator that comes with Android Studio.
When your game is installed and running on your device go to the directory in your workstation (PC) where the Android SDK Tools are.
Should Google Manage Your Keys for Games built with Unity?
We recently had a problem that caused weeks of pain and struggle and it had nothing to do with coding. It was the damn java keystore signing process that we signed up for on the Google Play Store.
The basics are that the Google Play Store requires that all APKs be digitally signed with a certificate before they can be installed. Apps must use the same certificate in order for users to be able to install new versions or updates. This is a good and secure system. No issues here.
If you lose your key you cannot distribute any updates to your app/game. This would be really bad for some companies so Google offers to keep your keys safe so that you if you did lose them you can ask to have the key sent to you which gives you authority distribute again. Yay for Google!
But our problems start here in Unity when you build your game for Android the keystore is defined on the Player Settings tab of the Build Setting (CTRL+SHIFT+B).
In the first case when running your project from Unity the package (APK) is automatically signed with a debug certificate generated by the Android SDK tools. The debug keystore and certificate are in $HOME/.android/debug.keystore.
This debug certificate is insecure by design and can’t be used on the Google Play Store for publishing an Alpha release but you can upload it for Beta releases. I think this is where we started going wrong.
When you upload an APK to the Play Store you can opt in to app signing by Google Play. They recommend it but it’s optional. If you prefer, you can continue managing your own keys.
The advantages of opting in to the Google Play Store App Signing program is that 1. You ensure that the app signing key is not lost. 2. If your app signing key is compromised only a user with an account linked to your app can manage an upload key which makes it harder to do something malicious. (If you sign in your apps are signed with an upload key proving your credentials – Google then manages your APK and assigns it the correct and valid signing key).
To quote their documentation: “When using Google Play App Signing, you will use two keys: the app signing key and the upload key. Google manages and protects the app signing key for you, and you keep the upload key and use it to sign your apps for upload to the Google Play Store.
When you use Google Play App Signing, if you lose your upload key, or if it is compromised, you can contact Google to revoke your old upload key and generate a new one. Because your app signing key is secured by Google, you can continue to upload new versions of your app as updates to the original app, even if you change upload keys.
If you lose your keystore or think it may be compromised, app signing by Google Play makes it possible to request a reset to your upload key. If you’re not enrolled in app signing by Google Play and lose your keystore, you’ll need to publish a new app with a new package name.”
Alright. Read that last bit again. It’s important and why app signing might be a really good idea. If you manage your key yourself and you lose it and want to make an update to your app then you have to publish your whole app again under a different name. Again just to drum that home … If you lose your keystore, the only solution is to upload a new instance of the app to the Google Play Store with a new key, a whole new store listing like it’s a different product, as it will not accept an APK signed with a different key.
I was a little lost so I started looking for the help of my peers and of course from Unity.
I found a post from one poor soul who was in the same boat as me and the response from Unity Support was: “What do you want to be supported from Unity side? I see this unrelated to our build process.” So someone needs to have a little talk to that chap.
Look – and this is really the bottom line – it all got too frustrating and annoying trying to work out what the hell was going on and since I was only in my third release cycle I just opened up a new App on the Play Store and ditched the old one. But that’s just not possible for anyone who has an App out there and has no other option. So this is the process to getting that pesky key back.
In the Google Play Store you can see your App Signing Keys here:
You got your App signing certificate – this is the one that actually signs your app.
SHA-1 certificate fingerprint (above)
And your Upload certificate – this is the one that you use to upload with your APK so that Google knows it’s you.
Your upload key is only registered with Google and is used to authenticate the identity of the app creator.
Your upload key is removed from any uploaded APKs before being sent to users.
C:\Program Files\Java\jdk1.8.0_111\bin>keytool -genkey -v -keystore D:\ZuluOneZero\Demo-Unity-Android-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias Demo4Unity
Enter keystore password:
Re-enter new password:
What is your first and last name?
What is the name of your organizational unit?
What is the name of your organization?
What is the name of your City or Locality?
What is the name of your State or Province?
What is the two-letter country code for this unit?
Is CN=ZuluOneZero, OU=TheDogRun, O=ZuluOneZero, L=Melbourne, ST=Victoria, C=AU correct?
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=ZuluOneZero, OU=TheDogRun, O=ZuluOneZero, L=Melbourne, ST=Victoria, C=AU
Enter key password for <Demo4Unity>
(RETURN if same as keystore password):
Re-enter new password:
Note: keytool is located in the bin/ directory in your JDK. To locate your JDK from Android Studio, select File > Project Structure, and then click SDK Location and you will see the JDK location
(I used this one but you will have a keytool for every JDK and JRE on your machine – doesn’t matter which one you use)
Then, export the certificate for the new key to PEM format:
This is a quick demo of the basic play mechanics from our new game in development Endless Elevator. We got the basic movement working a while ago (see our Smooth Moves post) and now that The Dog Run is in BetaTesting we can spend some more time working on this game.
The Good Guy Cop Character movement (oh yeah he goes left and right)
Firing his awesomely powerful dumb dumb gun
Using (the eponymous) Elevator (see if you can spot the camera tracking bug!)
Traversing (the namesake) Escalators
Finally entering a doorway with a Power Cube (I’m not sure what it will look like in the final game yet). When he goes into a doorway with the special block the game flips and he goes into a Super Spy Store (not shown) where new fun weapons and power-ups are available! Cool.