I wanted to build a game for a while, when I found that unity supported cross platform builds I was intrigued enough to explore it and create a small game. Little did I know I would be running into all kinds of things not really relating to development, but more just configuration. The result of this coding adventure is Hail Bounce. The app has been removed from the play store because I did not feel it was worth keeping up with the fairly unforseen frequently required updates via the play store as a result of unity's horrible app policies. Perhaps in the future I will decide I don't completely despise unity and may build the game for the web, but for now you can download the apk and install it for yourself if you own an android device.
Hopefully this post will explain all of the steps to build a game with unity and launch it on the android play store. I will be looking into an iOS release in the future but I do not have a developer profile setup with them so publishing there would be a bit more lengthy unfortunately. I also did not have an account for developing android apps but the process to apply there is basically just paying $25 as I will explain later.
A computer with maybe 2 cores and 4 gb of ram, seriously the requirements are pretty low for game development depending on what you're doing it really won't matter what your specs are as long as you are willing to wait a bit for compilations. For more details specs on what unity actually requires check them out here.
OnePlus 6T running Android 9
CPU: i5-6400 RAM: 16 GB GPU: gtx 1060 6GB
Download the unity hub here. Once the download and install is complete, there is a section for installs. Be sure to select the appropriate version. The first one in the list is not the one you want, make sure you select a version with the letter f for final in it. The a version is alpha, and the b version is beta which are somewhat unstable. The most recent final release at the time of writing is .
Make sure you select Android Build Support and the nested Android SDK and NDK Tools which we will go into later. Feel free to select any other platforms you might be interested in building your game for, I won't go into those in this post since I haven't gotten there yet.
This is one of the largest mistakes that I made with this project unfortunately. I downloaded the alpha version of unity and was using that to create this game. I still do not have the stable version working, the versions are unfortunately not backwards compatible and when attempting to import the project into a lower version, the scene would not import so I am basically stuck on the newest version waiting for them to resolve a few issues. This was a reminder to always use version control when updating unity versions since you can't downgrade easily.
Unity has some pretty great resources available free of charge for actually learning how to use their products. I found this one for creating a clone of flappy bird that I thought would be fairly simple to implement and it did not take me more than a day to complete everything for this tutorial and all of the modifications for adapting what I learned in the tutorial for creating the game that I made. If you are curious which one I used, feel free to check it out here.
In general for me, I come up with ideas while I am working on something so normally it just works out if I start following a tutorial or get something basic started. I started playing around with the assets and made them have collisions for getting points instead of going through the area, this is what sparked my idea for the current game.
While following the tutorial I thought it would be interesting to create a variant with a hail ball that had to go through clouds to grow and ultimately you could watch the giant ball go plummeting to the ground and smash a car or something. I started with a more simple version of just having the ball collide with the clouds and give the user points to get a high score.
If you follow the tutorial then this section would most likely make a bit more sense.
I wanted to make it different than just flying through some zone to score, so I made it collision based and created clouds instead of flying through the pipes.
Clouds needed some collision, I created a new object and added this simple script on a new cloud object.
1void OnCollisionEnter2D(Collision2D other) 2{ 3 this.gameObject.SetActive(false); 4} 5
I removed the bird flapping animations it looked a bit plain so I also made the object rotate on impact.
1void OnCollisionEnter2D(Collision2D other) 2{ 3 if (other.collider.GetComponent<Cloud>() != null) 4 { 5 GameControl.instance.HailScored(); 6 rb2d.MoveRotation(10); 7 return; 8 } 9 10 this.OnDeath(); 11} 12
I thought it would be a bit more difficult if the game sped up over time. The scroll speed is the speed of the background and the clouds which is moving to the left (negative). I changed that by subtracting a set amount when the user scored:
1public void HailScored() 2{ 3 ... 4 scrollSpeed -= scrollSpeedIncreaseOnImpact; 5 ... 6} 7
I used the same spawning pool pattern that was used for the pipes in the tutorial, I added some extra parameters to make the clouds a bit more interesting. I added a rate for spawning the clouds, and also had to make it inactive if the user interacted with it so I needed to re-activate it when it spawned again. I also needed to add a rate for spawning the clouds since the rate of speed increases while the user plays the game.
This was the code from the tutorial for spawning the pipes:
1using UnityEngine; 2using System.Collections; 3 4public class ColumnPool : MonoBehaviour 5{ 6 public GameObject columnPrefab; //The column game object. 7 public int columnPoolSize = 5; //How many columns to keep on standby. 8 public float spawnRate = 3f; //How quickly columns spawn. 9 public float columnMin = -1f; //Minimum y value of the column position. 10 public float columnMax = 3.5f; //Maximum y value of the column position. 11 12 private GameObject[] columns; //Collection of pooled columns. 13 private int currentColumn = 0; //Index of the current column in the collection. 14 15 private Vector2 objectPoolPosition = new Vector2 (-15,-25); //A holding position for our unused columns offscreen. 16 private float spawnXPosition = 10f; 17 18 private float timeSinceLastSpawned; 19 20 21 void Start() 22 { 23 timeSinceLastSpawned = 0f; 24 25 //Initialize the columns collection. 26 columns = new GameObject[columnPoolSize]; 27 //Loop through the collection... 28 for(int i = 0; i < columnPoolSize; i++) 29 { 30 //...and create the individual columns. 31 columns[i] = (GameObject)Instantiate(columnPrefab, objectPoolPosition, Quaternion.identity); 32 } 33 } 34 35 36 //This spawns columns as long as the game is not over. 37 void Update() 38 { 39 timeSinceLastSpawned += Time.deltaTime; 40 41 if (GameControl.instance.gameOver == false && timeSinceLastSpawned >= spawnRate) 42 { 43 timeSinceLastSpawned = 0f; 44 45 //Set a random y position for the column 46 float spawnYPosition = Random.Range(columnMin, columnMax); 47 48 //...then set the current column to that position. 49 columns[currentColumn].transform.position = new Vector2(spawnXPosition, spawnYPosition); 50 51 //Increase the value of currentColumn. If the new size is too big, set it back to zero 52 currentColumn ++; 53 54 if (currentColumn >= columnPoolSize) 55 { 56 currentColumn = 0; 57 } 58 } 59 } 60} 61
This is the code that I ended up with after my modifications for the cloud pool:
1using UnityEngine; 2using System.Collections; 3 4public class CloudPool : MonoBehaviour 5{ 6 public GameObject cloudPrefab; //The cloud game object. 7 public int cloudPoolSize = 5; //How many clouds to keep on standby. 8 public float initialCloudSpawnRate = 3f; //How quickly clouds spawn. 9 public float cloudSpawnRate; 10 public float cloudMin = -1f; //Minimum y value of the cloud position. 11 public float cloudMax = 3.5f; //Maximum y value of the cloud position. 12 public float spawnXPosMax = 8f; 13 public float spawnXPosMin = -4f; 14 private GameObject[] clouds; //Collection of pooled clouds. 15 private int currentCloud = 0; //Index of the current cloud in the collection. 16 private Vector2 objectPoolPosition = new Vector2(-15, -25); //A holding position for our unused clouds offscreen. 17 private float spawnXPosition = 10f; 18 private float timeSinceLastSpawned; 19 20 void Start() 21 { 22 cloudSpawnRate = initialCloudSpawnRate; 23 timeSinceLastSpawned = cloudSpawnRate; 24 25 //Initialize the clouds collection. 26 clouds = new GameObject[cloudPoolSize]; 27 28 //Loop through the collection 29 for (int i = 0; i < cloudPoolSize; i++) 30 { 31 //and create the individual clouds. 32 clouds[i] = (GameObject)Instantiate(cloudPrefab, objectPoolPosition, Quaternion.identity); 33 } 34 35 Update(); 36 } 37 38 //This spawns clouds as long as the game is not over. 39 void Update() 40 { 41 timeSinceLastSpawned += Time.deltaTime; 42 43 if (GameControl.instance.gameOver == false && timeSinceLastSpawned >= cloudSpawnRate) 44 { 45 cloudSpawnRate = initialCloudSpawnRate / System.Math.Abs(GameControl.instance.scrollSpeed); 46 timeSinceLastSpawned = 0f; 47 48 //Set a random y position for the cloud 49 float spawnYPosition = Random.Range(cloudMin, cloudMax); 50 spawnXPosition = Random.Range(spawnXPosMin, spawnXPosMax); 51 52 //then set the current cloud to that position. 53 clouds[currentCloud].gameObject.SetActive(true); 54 clouds[currentCloud].transform.position = new Vector2(spawnXPosition, spawnYPosition); 55 56 //Increase the value of currentCloud. If the new size is too big, set it back to zero 57 currentCloud++; 58 if (currentCloud >= cloudPoolSize) 59 { 60 currentCloud = 0; 61 } 62 } 63 } 64} 65
The unity asset store is a great place to publish your own content to have others use it and/or pay you for it, but it is also a great resource for inspiration or saving you from spending time making tons of assets.
I found this one for the hail ball.
This is the one I used for the background and the clouds.
In the android section, if the checkmark for "Android SDK Tools Installed with Unity (recommended)" is selected, then your SDK will be located somewhere similar to time:
With unity the process here is pretty easy fortunately. Most of this is not required unless you actually want to publish your game on the android play store, which I will get into later. Here is what you need to do for setting up the android build:
.
and go through all of the items on the right. At a minimum, fill in the Company Name, Product name, and the package name under
.
, to the right of
, select your device, if you do not see it immediately then click refresh.The build will output a file with the extension. This is useful later when we will publish it to the play store. If you want to extract the
manually you can do that.
This portion is not necessary, but you can have some friends try it out if they know how to manually install .apk files on their device, they will need to allow installs from outside sources on their device before attempting to install it though.
file from the previous build
bundle which contains the apk you can install on other devices. Open the .apks archive with some archive explorer, I prefer 7zip. You will find the apk in the standalones folder named
.Sign up for an AdMob account through google. If you do not have an account already setup it could take several weeks for the ads to actually show up. You can follow this guide for setting up unity to use the AdMob SDK. And follow this guide for adding the banner.
Make sure to add your device as a test device. Follow this guide so you don't get banned from AdMob.
Attach the Ads script to the Main Camera object in unity, this is the script I am using for ads:
1 2using UnityEngine; 3using GoogleMobileAds.Api; 4 5public class Ads : MonoBehaviour 6{ 7 private BannerView bannerView; 8 public void Start() 9 { 10 this.InitializeBanner(); 11 this.RequestBanner(); 12 } 13 14 private void InitializeBanner() 15 { 16#if UNITY_ANDROID 17 string appId = "ca-app-pub-XXXXXXXXXXXX~XXXXXXXXXXXX"; 18#elif UNITY_IPHONE 19 string appId = "ca-app-pub-XXXXXXXXXXXX~XXXXXXXXXXXX"; 20#else 21 string appId = "unexpected_platform"; 22#endif 23 24 // Initialize the Google Mobile Ads SDK. 25 MobileAds.Initialize(appId); 26 } 27 28 private void RequestBanner() 29 { 30 // Prod Ads 31#if UNITY_ANDROID 32 string adUnitId = "ca-app-pub-XXXXXXXXXXXX/XXXXXXXXXXXX"; 33#elif UNITY_IPHONE 34 string adUnitId = "ca-app-pub-XXXXXXXXXXXX/XXXXXXXXXXXX"; 35#else 36 string adUnitId = "unexpected_platform"; 37#endif 38 39 // Test Ads 40 // test device XXXXXXXXXXXX 41 // #if UNITY_ANDROID 42 // string adUnitId = "ca-app-pub-XXXXXXXXXXXX/XXXXXXXXXXXX"; 43 // #elif UNITY_IPHONE 44 // string adUnitId = "ca-app-pub-XXXXXXXXXXXX/XXXXXXXXXXXX"; 45 // #else 46 // string adUnitId = "unexpected_platform"; 47 // #endif 48 49 // Clean up banner ad before creating a new one. 50 if (this.bannerView != null) 51 { 52 this.bannerView.Destroy(); 53 } 54 55 this.bannerView = new BannerView(adUnitId, AdSize.Banner, AdPosition.Bottom); 56 57 // Create an empty ad request. 58 AdRequest request = new AdRequest.Builder() 59 // .AddTestDevice("XXXXXXXXXXXX") 60 .Build(); 61 62 // Load the banner with the request. 63 this.bannerView.LoadAd(request); 64 this.bannerView.Show(); 65 } 66} 67 68
I watched this video for an overview of adding firebase analytics to the game. This guide was pretty good for getting started with logging different events.
The only thing which was somewhat terrifying was the privacy policy since I am not a lawyer. I do not take any responsibility for these actions, your actions are your own, please cross reference stuff and be sure to investigate this on your own. I am not liable for any actions you take based what I have done in this tutorial. That said, I found a website that I used to create a privacy policy for the app which seems pretty good, you can create your own here.
Sign up for the google play developer console to publish your app here. The process is fairly straight forward, you basically just pay $25 and then fill out the application. After your account is created then create a new application.
There are a lot of things on the list for the future if I decide to implement them later: