What I learned from “Don’t Touch My Planet!”
Every new project is a good learning experience, especially if you are a game designer buffing up your programming skills. I will share with you what I have learned from building “Don’t Touch My Planet!” on Unity 3D. My Planet is an experimental twist on tower defense games, you can grab it from here.
Technical Stuff
Upgrades
Upgrades are a great way to make games more engaging, tactical and long lasting. They emphasize the sense of progression and give you a nice way to layer and filter your game experience. But for small games upgrades can be costly. They require save system that will track players progress in every item that can be upgraded. This increases task difficulty quite a bit. For game developers who have not invested in saving system before, this might seem scary.
The problem with saving many items is that you either have to directly save too many variables, or you have to write a system that can save custom classes and load them. You might also have to write code that will synch these saves between different cloud solutions on different platforms. The way I navigated around these issues is by basing all item progression on only one variable: items level! So this way you only have to save one variable per item.
Every stat of the item can be recreated from just the items level and there are many ways to do that. For example for players shield we needed simple liner progression so we have two variables.
One is starting health, another is how much health should be added each level. So with simple function shown bellow we can learn shields health for any level.
1 2 3 4 5 | public int GetHealthForLevel(int _level) { return statsBase.health+statsIncreasePerLevel.health*_level;' //base health + increase * item level } |
public int GetHealthForLevel(int _level)
{
return statsBase.health+statsIncreasePerLevel.health*_level;'
//base health + increase * item level
}Any time you need to learn base health for an item, you can call the function “GetHealthForLevel()” with current level passed as an argument. For example at the start of the game we could set items currentHealth variable to baseHealth. So we start with full HP. We can do it like this:
1 | currentHealth = GetHealthForLevel(SaveManager.shieldLevel); |
currentHealth = GetHealthForLevel(SaveManager.shieldLevel);
You could also use arrays to store what value an item should have on each level
1 2 3 4 5 6 | int[] healthPerLevel; public int GetHealthForLevel(int _level) { return healthPerLevel[_level]; } |
int[] healthPerLevel;
public int GetHealthForLevel(int _level)
{
return healthPerLevel[_level];
}or even better use curves to define balance (more on this below). Basically as long as you don’t have randomized stat increase on levels this should work for you. The scenario where this would not work is for example: in DnD your character rolls a dice each level up to see how much health it should give you, with min/max health increases. But this is kind of a dick move so
Time based upgrades
Another cool feature popular on mobile games is time based upgrades. Basically when you upgrade something you have to wait X minutes before upgrade is ready. Trick is you need to save time, so that when player shuts down your game and returns later he should receive all the upgrades that should have been ready by that time. So tracking only time during playtime is not enough, as that data will be lost when the game is closed.
To implement this feature, you need to make an important decision first. Do you rely on device clock to check against time or do you use your server clock for this.
Device clock is easy to access and works offline, but player can cheat by changing the actual time on his device. Server clock is impossible to cheat but requires active internet connection and you also need to have a server. Some games allow you to play offline, but only give you access to time based mechanics if you are online.
For “Don’t Touch My Planet!” I went with offline approach. I didn’t want to force internet connection on purely offline game. Though for online or highly competitive games you will need to use server time.
You can implement timed upgrades using DateTime and TimeSpan constructs. You will need to add “using System;” at the top of your script to use this functions.
DateTime - Represents an instant in time, typically expressed as a date and time of day.
TimeSpan - Represents a time interval.
During upgrade we must get current time from the device system clock and save it as a string. We can get it by using “DateTime.UtcNow.ToString()”. UtcNow will give you time that is independent of the time zone, so you don’t have to worry about players going back in time when they fly to different countries. Your save code could look like this:
1 | PlayerPrefs.SetString("shieldUpgradeTimer", DateTime.UtcNow.ToString()); |
PlayerPrefs.SetString("shieldUpgradeTimer", DateTime.UtcNow.ToString());“PlayerPrefs” is the easiest saving option in Unity.
Next time when you need to check if an item has been upgraded, you need to load saved time string and process it:
1 2 3 4 5 6 7 8 9 | //load saved time string string time = PlayerPrefs.GetString("shieldUpgradeTimer"); //variable to store saved time DateTime savedTime; //try parse method will check if string is correct and load it into datetime Variable, it will return false if parsing failed if (DateTime.TryParse(time, out savedTime) == false) { //saved time is corrupted, implement failsafe } |
//load saved time string
string time = PlayerPrefs.GetString("shieldUpgradeTimer");
//variable to store saved time
DateTime savedTime;
//try parse method will check if string is correct and load it into datetime Variable, it will return false if parsing failed
if (DateTime.TryParse(time, out savedTime) == false)
{
//saved time is corrupted, implement failsafe
}Then we need to check how many seconds have passed since we ordered an upgrade:
1 2 3 4 5 6 7 8 9 10 | //lets get current time DateTime timeNow = DateTime.UtcNow; //time span can help us to calculate how much time has passed after an upgrade has started TimeSpan timePassed; //substract saved time from current time to get interval inbetween timePassed = timeNow.Subtract (savedTime); if (timePassed.TotalSeconds < 0) { //player changed his clock to previous date, he is now BACK IN THE PAST!!! implement the failsafe } |
//lets get current time
DateTime timeNow = DateTime.UtcNow;
//time span can help us to calculate how much time has passed after an upgrade has started
TimeSpan timePassed;
//substract saved time from current time to get interval inbetween
timePassed = timeNow.Subtract (savedTime);
if (timePassed.TotalSeconds < 0)
{
//player changed his clock to previous date, he is now BACK IN THE PAST!!! implement the failsafe
}After that lets check if enough time has passed to warrant an upgrade
1 2 3 4 5 6 | //we need variable to know how many seconds are required to upgrade an item double secondsNeededToUpgradeItem = 300; if (timePassed.TotalSeconds >= secondsNeededToUpgradeItem) { //Enough time has passed, upgrade an item } |
//we need variable to know how many seconds are required to upgrade an item
double secondsNeededToUpgradeItem = 300;
if (timePassed.TotalSeconds >= secondsNeededToUpgradeItem)
{
//Enough time has passed, upgrade an item
}BOOM HEADSHOT! You can now laugh from the shadows as players stare at the timer and wait impatiently for upgrades to finish. Speaking of timer, here is a bonus code for you to display the timer.
1 2 3 4 | //lets check how many seconds are left until upgrade is ready TimeSpan timeLeft = TimeSpan.FromSeconds(secondsNeededToUpgradeItem-timePassed.TotalSeconds) ; //We can use string format to convert timespan into a time string string timeToDisplay = string.Format("{0:00}:{1:00}:{2:00}", timeLeft.Hours, timeLeft.Minutes, timeLeft.Seconds); |
//lets check how many seconds are left until upgrade is ready
TimeSpan timeLeft = TimeSpan.FromSeconds(secondsNeededToUpgradeItem-timePassed.TotalSeconds) ;
//We can use string format to convert timespan into a time string
string timeToDisplay = string.Format("{0:00}:{1:00}:{2:00}", timeLeft.Hours, timeLeft.Minutes, timeLeft.Seconds);Don’t forget that you will need to add “using System;” at the top of your script to use DateTime and TimeSpan functions.
Animation curves for balance
To get most out of the only one variable based upgrade system, we can use Unity’s animation curves to have more control over how item stats will change over levels. Curves represent value over time, looking at image below should give you an idea of what the AnimationCurves are.
You can use them to visually see how stat will change over levels. Vertical coordinate would be the stat value, horizontal coordinate would be the level. I used this to control enemy stats. The value of the curve on certain level directly represents stat value.
You can define Animation curve as public variable:
1 | public AnimationCurve Rocket_L_Health; |
public AnimationCurve Rocket_L_Health;

The curve will represent how stat will increase over certain amount of levels. For example this one curve shows how stat will increase every 10 levels. after 10 levels we need to repeat the curve, so that it can show us the stat values for the next ten levels. We do this by looping the curve. but if we let unity do that we get something like this:
Not very useful. On wave 11, when we repeat the curve stat would be back to the value of 0. What we are looking for is looping like this:
So the form of the curve is repeated, but new curve starts on the value the previous curve has ended. And that’s exactly how we accomplish this. When we repeat curve, we add last value of the previous curve to it.
We can use this to have controlled progression of the items value over levels, and we can do that by one simple function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // this function returns item value on provided level, it needs 3 variables // _curve is AnimationCurve that has Item's balance on it //_level is current level of the item //_stepping is basically, how many levels should we calculate from one curve, before repeating it public float GetCurveValueForLevel(AnimationCurve _curve, int _level, int _stepping) { //we calculate how many times has the curve repeated itself //for example if one curve represents 10 levels and //current level is 25, stepping multiplier is 2 int _steppingMP = Mathf.FloorToInt(_level/_stepping); //now we need to determine on which step we are in current curve //so if curve represents 10 levels and current level is 25 //we need value of 5, that is where we are on current curve(20 to 30) //20 just means, we have looped through our curve twice //check image above to understand this int _currentStep = _level - _steppingMP*_stepping; //the curves give us value over time. By default time length of the curve is 1 second //so we need to determine what percent of 1 second _currentStep represents //first we get what percent of stepping the currentStep is float percent = _currentStep*100f/_stepping; //now we get x Percent of 1 second float _time = 1f*percent/100f; //now we get what value the curve has on given time //then we add stepping multiplier, to create looping like on image above //basically the last value of the curve multiplied by the number of times curve was repeated float _value = _curve.Evaluate(1f)*_steppingMP + _curve.Evaluate(_time); //because it's easier to edit curve at very small values, lets multiply them so we get normal value numbers int _multiplier = 100; //return value return _value*_multiplier; } |
// this function returns item value on provided level, it needs 3 variables
// _curve is AnimationCurve that has Item's balance on it
//_level is current level of the item
//_stepping is basically, how many levels should we calculate from one curve, before repeating it
public float GetCurveValueForLevel(AnimationCurve _curve, int _level, int _stepping)
{
//we calculate how many times has the curve repeated itself
//for example if one curve represents 10 levels and
//current level is 25, stepping multiplier is 2
int _steppingMP = Mathf.FloorToInt(_level/_stepping);
//now we need to determine on which step we are in current curve
//so if curve represents 10 levels and current level is 25
//we need value of 5, that is where we are on current curve(20 to 30)
//20 just means, we have looped through our curve twice
//check image above to understand this
int _currentStep = _level - _steppingMP*_stepping;
//the curves give us value over time. By default time length of the curve is 1 second
//so we need to determine what percent of 1 second _currentStep represents
//first we get what percent of stepping the currentStep is
float percent = _currentStep*100f/_stepping;
//now we get x Percent of 1 second
float _time = 1f*percent/100f;
//now we get what value the curve has on given time
//then we add stepping multiplier, to create looping like on image above
//basically the last value of the curve multiplied by the number of times curve was repeated
float _value = _curve.Evaluate(1f)*_steppingMP + _curve.Evaluate(_time);
//because it's easier to edit curve at very small values, lets multiply them so we get normal value numbers
int _multiplier = 100;
//return value
return _value*_multiplier;
}This might seem complicated at first, but it’s really simple. We use the curve to represent the value of a stat over certain amount of levels, which I called stepping. If our level is larger than stepping, we repeat the curve but now with higher values. Each time we finish the curve, steppingMP is increased.
But we always evaluate curve withing current stepping. So we determine where we are in current curve loop. Then we translate our position into curves time variable. After which we get what is the value at current time. It is really worthwhile thing to understand. Because if you have your balance with visually representable curves, you can overlay different curves on top of each other and you can pretty much visually create perfect balance.
If you have cooler way to track your balance, please let me know ^^
Non Technical
Plugins
Whether to write all your features yourself or speed up development with 3rd party tools is a topic of great debate. On one hand it is easier to use and build upon your own tools, on other hand reinventing the wheel.. well the expression is self explanatory. But while there are pretty standard and safe external solutions like physics libraries or game engines. Sometimes you have to deal with more questionable products like for example plugins on unity asset store. These are often developed by one person who might see his submissions as a hobby and side income, thus they might not have the dedication to deliver quality that a company fully dependent on their products success would have.
You will have to analyze this situations and weight several factors. Is the feature you have generic or very specific and unique? If you are building a revolutionary physics based puzzle game, reinventing the wheel might just be the best thing you can do as you will most likely need more control than standard solutions can give you.
But if standard thing is fine with you, then you need to think really hard if spending your own time to develop this feature is really worth it when there are perfectly usable solutions out there. Chances are you are not doing anything revolutionary with your hud (please don’t), so it might be a safe bet that your valuable time is better spent making better gameplay than slaving over annoying and tiresome task like making user interface that can work on all platforms and all resolutions. ( I spent less than 10 minutes doing that with Ngui.)
Another good reason to use plugins is that you might not want to face every possible challenge with your first game. Even if you want to fully rely on your own tech, you might want to get to that point step by step. Remove extra noise like hud or touch controls from your first game. Build solid gameplay mechanics and on your second game you can focus replacing external tools with your own. Having a long term vision about tech of your company really helps.
Now I’ll get to more specific cases on this subject by giving you a small review of the plugins I used.
NGUI - this plugin is so amazing that Unity actually hired the guy behind it and in update 4.6 you will see this replacing Unity’s existing GUI system. If you can’t wait for 4.6, definitely buy this plugin.
Master Audio – I love it. I picked this up for 10$ on sale and I got pretty powerful, simple to use audio system. It has events for default behaviors like disabled/enabled and you can write custom events. You can easily create random sound groups, music track mixing etc.
IOS Native – This allowed me to do everything I wanted to do on IOS, like leaderboards, InApp, iCloud. But I would not rely on third party plugins when it comes to porting to mobile devices. You should use plugins like this to let you publish your first few games, but eventually you will need to be able to use native SDKs and commands. Mobile platforms are tricky, they update often and in way that might break your functionality and when that happens, your amazing google skills won’t always be enough to effectively resolve the issue. So definitively plan to invest in in-depth knowledge of native SDKs and don’t put off this task for too long.
Official Facebook SDK - It works, kind of. But it really does not fill like solid solution and makes you worry about beta status. In xCode it gave me a lot of minor warnings when I built my project. They didn’t break anything but it just does not feel “clean” and stable.
New Services We Tested
There are tons of services built around games, especially mobile games. Some of them let you use common functionality like displaying ads or tracking your games performance. Some offer bizarre new ways to allow your players to interact with your app in innovative but often questionable forms. In this section I will review the services we tested with current game.
I serve ads in “Don’t Touch My Planet!” and I used Chartboost to do so. I don’t have enough data yet to see how well it performs income-wise but I have good feedback from people who use Chartboost. I used unity plugin to serve ads and it was very easy to implement, worked within few minutes. Make sure to use custom locations to get better feedback from analytics.
To track analytics I used GameAnalytics. It’s a great start and you should definitely consider implementing it if you have not used analytics in your games before. With just few steps you will be able to track all the important KPIs without writing a single line of code. It tracks all the retention, user and session length data you might need.
Tracking custom events requires just one line of code. I would recommend that you at least track every step of the tutorial and whether or not players have interacted with all your features to see if players are understanding your game. For example send event first time player opens a store.
A lot of people drop games on their tutorials, so compare how many hits you have on each tutorial step and you can see where you are loosing your first time users. Fix those places in your next update.
You can also use game analytics to generate heat maps if your game is level based. Send custom events when snipers kills a target for example to determine what map points are being exploited by them. You can then preview heat map directly in unity, it will overlay your scene. This is just super awesome.
Well I guess that’s it
I hope you found this useful and reach out if want to ask anything.
Cheers!


































