Our Gui script is causing a good amount of Garbage Collection in it's Update (), but I'm not sure exactly how I would approach optimizing the script. I think that the garbage collection is being triggered because the constant update of the text displaying the amount of collectables, and the distance the player has traveled in every update cycle. We want these features, so need to optimize and not delete. Also, can the type of front being used affect performance ? Profiler: Gui Manager update: Code (CSharp): void Update() { //If the game is in play mode if (inPlayMode) { //Update the main UI's status texts coinText.text = AddDigitDisplay(collectedCoins, 4); distanceText.text = AddDigitDisplay(distanceTraveled, 5); } }
I think we'd need to see AddDigitDisplay to help you. Building strings is an extremely common source of GC cruft, especially if you use a lot of +'s.
Do you need to Update it every frame? Try using a coroutine to update it less frequently. Maybe every 0.5 or even 1 second or something. Or if the data is only changed due to a game event, you should use delegates to only fire the UI update when a value changes.
Oops sorry about that: Code (CSharp): private string AddDigitDisplay(int number, int digits) { string s = ""; for (int i = 0; i < digits - number.ToString().Length; i++) s += "0"; s += number.ToString(); return s; } I could try a coroutine, I'm wondering though would ether Late Update () or Fixed Update () work as well? Just brainstorming some ideas?
I had similar issues with string handling in my game too. I thought StringBuilder would fix it but whenever you convert it to a string, the version of Mono Unity uses generates garbage anyway so it doesn't help. I ended up with two solutions : My timers and distance things that need to be updated regularly have a couple of optimizations: Updated in a coroutine once a second - this might slow down the UI responsiveness but it really helps (generates garbage once a second not 60 times) it looks ok as well. Of course if the game ends or the player dies I quickly do one last UI update to show the actual final distance score. Players don't usually die on the exact second! This might not work for your game but I try and have semi intelligent updates - only update the distance if the distance actually changed by a reasonable amount. For other things like score, where the score only changes when something happens I have a simple event system. The UI listens for score changes and Updates the score text when something changes.
Your garbage collection issue has zero to do with where you're calling this code from, and everything to do with what this code is. This function could be a textbook example of how to generate as much GC as possible while putting together a string. Not only do you use += on strings as much as possible (each instance of which generates garbage), but in your for loop you use number.ToString() to calculate the length....and each of those calls will generate garbage. It's also really slow for what it is. (edit: I don't mean to have a scolding tone in this, even though I see that's how it came off.... apologies) If you want to avoid garbage collection and you have to build strings, it is vital to learn how to use string.Format and int.ToString("stuff") functions. These functions are efficiently coded to clean up after themselves and not leave behind anything for the GC. As long as you avoid any concatenation (string + string), and minimize your .ToString() calls as much as you can, you should be able to drastically reduce the amount of garbage you create. In this case, there's actually a int.ToString parameter you can use to replace this entire function! Here's a page showing how to use it.
No, worries I'm modifying code from the asset store. This was the way it was originally, so i guess I'm cleaning up after someone else. ( Also Note: I'm a part of a small indie team where we are all trained as artists and not programmers. I have the most experience with code, and i'm just a beginner. ) So here's my attempt: Code (CSharp): private string AddDigitDisplay(int number, int digits) { /*string s = ""; for (int i = 0; i < digits - number.ToString().Length; i++) s += "0"; s += number.ToString(); return s;*/ string s = ""; s.PadLeft (s.Length + 4, '0'); } How would I use int number and int digits, in a new string with the examples given? do I have too? and I'm getting this error:
Try to make to it return int instead of string, and then use string format, strings are arrays and expensive
You know what, I somehow linked to the wrong page (that was one that I saw but meant to not link, because PadLeft is still not the ideal solution). This is the one I meant to link to: http://stackoverflow.com/questions/4325267/c-sharp-convert-int-to-string-with-padding-zeros Basically, Code (csharp): coinText.text = collectedCoins.ToString("0000");
I did try to return int just as you suggested but I got this error: Current code: Code (CSharp): //Converts a number to a string, with a given digit number. For example, this turns 4 to "0004" private string AddDigitDisplay(int number, int digits) { /*string s = ""; for (int i = 0; i < digits - number.ToString().Length; i++) s += "0"; s += number.ToString(); return s;*/ return string.Format ("{0:d4}{1:d4}", number, digits); //s.PadLeft (s.Length + 4, '0'); } This did work but there was two problems with this: one, the distance was calculated as seconds instead of a measure of distance. Two, the garbage collection was even worse then before.
While I just tried this: Code (CSharp): void Update() { //If the game is in play mode if (inPlayMode) { //Update the main UI's status texts coinText.text = collectedCoins.ToString("0000"); distanceText.text = distanceTraveled.ToString("00000"); // coinText.text = AddDigitDisplay(collectedCoins, 4); // distanceText.text = AddDigitDisplay(distanceTraveled, 5); } } It did work, but the Garbage was way worse with the changes:
I meant something like this, Code (CSharp): private int AddDigitDisplay(int number, int digits) { int s = 0; for (int i = 0; i < digits - number; i++) s += number; return s; } Then use stringformat to show the numbers output in the format you prefer, followed by the text you want to add with that. Btw you don't need to show this numbers every frame, you should lower it with every second or every half second.
Still got an error: Code (CSharp): private string AddDigitDisplay(int number, int digits) { int MyStringInt = 0; for (int i = 0; i < digits - number; i++) MyStringInt += number; return MyStringInt; /*string s = ""; for (int i = 0; i < digits - number.ToString().Length; i++) s += "0"; s += number.ToString(); return s;*/ //return string.Format ("{0:d4}{1:d4}", number, digits); //s.PadLeft (s.Length + 4, '0'); }
Well, we fixed the problem by just starting fresh and commenting out the old code from the GUI manager. Edit: almost forget this. This unity video helped by giving a good template to start fresh from: https://unity3d.com/learn/tutorials/projects/space-shooter/counting-points
If you use IEnumerator for counting int, you get overhead overtime Code (CSharp): private int DigitDisplay(int number, int digits) { int s = 0; for (int i = 0; i < digits - number; i++) s += number; return s; } public void ScoreScreen() { coinText.text = string.Format ("{0:d4}", DigitDisplay(Inputnumber, Inputdigits)); } Then you do what BoredMoron recommended. I haven't tested the code, but it should work, and shows you what i mean is a good solution in your case.