Search Unity

Questions about optimization tips for 2D games in Unity3D?

Discussion in 'Android' started by elmar1028, Feb 10, 2015.

  1. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    Hi guys,

    I don't know the best place to put it, so I decided to have a thread here:

    I am making a 2D game for mobile and noticed I have performance issues on older Android devices.
    I was searching for optimization tips and they didn't seem to have much of an impact.

    I have several questions:

    1) My game involves lots of gameobjects. At the beginning they're instantiated at random locations. There is some logic made in order to prevent them overlapping with each other. I thought would it benefit performance if I place them in the scene and then teleport each gameobject to random places.

    2) Is it better to have one spritesheet with all images on it, sliced and then accessed by individual gameobject, or having separate sprites for each gameobject?

    3) Is it better to have many scripts which carry out 2-3 functions each? Or is it better to have less scripts, which carry out more functions?

    4) Slightly off-topic: Is it just me, or UI buttons have a slight delay when pressed?

    5) Do you have any optimization tips of handling lots of objects in game? I am using Unity Free.

    Thanks in advance! :D
     
  2. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    I know you said you have Unity Free, but the, unfortunately, the best answer to all of your questions is to run your code through the profiler so you would know instead of just guess where the performance bottlenecks might be.

    That said, I'll try to help:

    If you mean that you're creating new game objects all the time, and you're considering creating them all ahead of time and then moving them into place as needed, then yes, that can actually help performance a lot.

    Even better (and probably easier) is use some form of object pooling. There are many assets in the store implement pooling with varying prices, capabilities, and quality.

    One large sprite sheet is better than many smaller ones in terms of optimizing use of texture memory. One sprite sheet shared between game objects that all share the same material is even better in terms of draw call optimization.

    In theory, one script monolithic script has less performance overhead than many smaller ones. But the difference will be negligible except for the most extreme cases. I'd say don't bother optimizing for script count. Do whatever feels more organized and/or more reusable.

    Have less objects :)

    If that's not possible, then implement pooling to reduce object instantiating overhead. It's also possible that you don't need to run all your scripts in every frame. For example, it could be feasible in your case to skip every other frame in the Update method of objects that are far from the camera and/or the player.

    Good luck.
     
    Ryiah and elmar1028 like this.
  3. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    I actually had objects constantly being destroyed and spawned. Then I made gameobjects teleport to random location instead of being destroyed (but giving same visual results). At that time I implement FPS counter into final build so I can't really say whether it had effect or not (probably did)

    Sadly, I can't because less objects would make game too easy. :(

    Thanks for answers :D I am going to optimize my game soon!

    Another question. When my game starts, it starts lagging a bit at the beginning because 500 objects are randomly instantiated in less than a second. Will performance increase (less lag at the beginning) If I place them in the scene and then teleport each gameobject to random places.
    To be more precise: Is transform.position (teleporting) faster than Instantiate()?
     
  4. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    It's definitely faster.
     
    elmar1028 and Deon-Cadme like this.
  5. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    If it's mobile then every initial touch has a slight delay, this is hardware (or os) based as far as I can tell.

    Shuriken with manual movement is awesome, it's really fast used as just a renderer. Then there's command buffers in 5, which I think are pretty wicked, and of course drawmesh. I've not done any performance comparisons between drawmesh / drawmeshnow / transform but I would think you'd get some speed boost from using it assuming you were seeing most if not all at the same time.
     
    Ryiah and elmar1028 like this.
  6. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    Shuriken is a particle, right? You mean if I have my game objects as particles but with restricted movement and rotation?

    I don't exactly understand about drawmesh(). Do I use it in order to "spawn" objects at the beginning?
     
  7. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Shuriken: you can assign your own array of Particle[] and update any element you like, and it's passed by ref (afaik) to the shuriken system to update, so you can use meshes, billboards and control them, they'll get batched.

    DrawMesh and DrawMeshNow: no transform overhead, you manage it's rotation, position, scale, materials yourself, and it doesn't exist in the scene. It is merely drawing whatever mesh you tell it to draw.
     
    Ryiah and elmar1028 like this.
  8. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    I am optimizing it right now. I want to make an array of those gameobjects and then teleport them one-by-one. Is using GameObject.FindGameObjectsWithTag() fast? If no, is there alternative?
     
  9. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    One of the slowest things you can do, that gets slower the more objects there are. Great for artists and setting up scenes in start though.

    Alternative is a list or array you have already.
     
    Last edited: Feb 10, 2015
  10. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    I thank everyone for their help! :D

    I was trying to implement new Optimization tip for mass spawning 500 gameobjects but apparently I need to build it from ground up :/

    I have some more questions:
    • Is Vector3.Distance() expensive?
    • Does using for loop for an array full of 500 gameobjects is a good idea?
    • If I use one big spritesheet instead of separate sprites, is that going to increase my performance a lot? Or just affect memory size?
    • Are there any books or articles about optimizations tips for Unity I can read so I won't bother with questions :p
    Thanks in advance :D
     
  11. R-Lindsay

    R-Lindsay

    Joined:
    Aug 9, 2014
    Posts:
    287
    Q. Is X number of Y operations expensive?

    A.
    Code (CSharp):
    1. using System.Diagnostics;
    ...
    Code (CSharp):
    1.             // Create new stopwatch
    2.             Stopwatch stopwatch = new Stopwatch();
    3.             stopwatch.Start();
    4.  
    5.             for (int i = 0; i < 1000; i++)
    6.             {
    7.                 // test some code here
    8.             }
    9.  
    10.             stopwatch.Stop();
    11.             UnityEngine.Debug.Log("Time elapsed: " + stopwatch.Elapsed);
     
    elmar1028 and Ryiah like this.
  12. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    Thanks! I will try it. :D
     
    R-Lindsay likes this.
  13. high-octane

    high-octane

    Joined:
    Oct 16, 2014
    Posts:
    84
    Iterating through 500 objects sounds like massive over-kill, especially in an update loop. What kind of filtering or culling, if any, are you using?

    The Unity manual itself has quite a number of pages on Optimization tips. One example: http://docs.unity3d.com/Manua/MobileOptimisation.html.

    Unfortunately, almost all of the Unity books that are sale are geared towards complete beginners or very specific genres. None of them appear to have any substantial sections on performance optimizations.
     
  14. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    I am using for loop it in a start function. Basically I want to teleport all 500 objects randomly and then it quits the loop and continues a game.
    I am just wondering, in general does iterating through 500 gameobjects takes lots of performance?

    Link is broken.

    But I found many more useful links:
    http://docs.unity3d.com/Manual/OptimizingGraphicsPerformance.html
    http://docs.unity3d.com/Manual/MobileOptimizationPracticalScriptingOptimizations.html
    http://docs.unity3d.com/Manual/MobileOptimisation.html
     
    Last edited: Feb 11, 2015
  15. Deon-Cadme

    Deon-Cadme

    Joined:
    Sep 10, 2013
    Posts:
    288
    @elmar1028 - Your description is really vague so it is hard to tell if 500 is much or little... it all depends on how much work each of those 500 updates does, what kind of functions they call, if they create variables and tons of other stuff...
    I can create a loop that does something a 100 times and it will lock-up the game for ages... at the same time, I can make a loop that does something over a 1000 times and it will only take the computer milliseconds to complete the whole loop.

    Do you got any pictures and videos that show these 500 things in the game?

    What are these 500 game objects?
    How often do you call this loop of 500 things? Once per level, once every second, once in the update function of each game object?
    What happens inside the for loop? (Can you share the code?)
    Do you call Random.Range each inside the loop?
     
  16. 0tacun

    0tacun

    Joined:
    Jun 23, 2013
    Posts:
    245
  17. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    • They're sprites with collider attached to them.
    • Those 500 gameobjects have a script to detect a player.
    • Inside of that script there is only one update function which checks a variable and then changes a layer of that gameobject
    As of right now, I don't have a loop function implemented inside of those gameobjects. I was only asking if that would have an impact.

    Before teleportation a gameobject would pick a random point and check the following:
    • The distance between chosen point and the closest object to it
    • The distance between chosen point and the player
    If those distances are "valid" then object is being spawned. If not it keeps looking for another location.
     
  18. Deon-Cadme

    Deon-Cadme

    Joined:
    Sep 10, 2013
    Posts:
    288
    Ok, you wanted older devices... some of them don't got much power, 500 objects with collision will be a strain no matter how much you attempt to optimize them. Not knowing the game itself makes it hard to give decent advice but adding functions that make calls often will not make the game work better.

    • I would definitely ask myself if a custom (home cooked) collision system might give better results?
    • Is it actually necessary for all 500 to detect the player? Can you find some logic that would allow you to simply ignore a chunk of these object? A radius or something? It is a 2D game, maybe creating a quad tree can allow you some approach like this?
    • 500 sprites on a mobile device sounds a bit crazy... makes me wonder if there isn't maybe a way to group those together... have one make the check and forward the results to the others?
    A "for" or "while" loop inside all of them isn't gonna help... instead, look at the behavior of the game and look if you can somehow avoid the check in some of these game objects.

    Are you calling random for this? It is typically an expensive function... Can you somehow find a location by partitioning the game space? Develop some kind of tree structure between the objects and players or simply reverse the logic? What if you pick an object that is reasonably close to fulfilling your requirements and then pick a location close to it? Maybe develop some kind of noise map? Simply create a texture that represents the game space, update it and look for spaces that look like a good spot to teleport the object to?

    As I said, not knowing the game makes it really difficult to give decent advice but I can't help the feeling that your best path for optimizing the game is at the moment to attack the base logic for the system... look at different approaches or systems that can minimize the number of calculations. Get them down to increase the games speed... then when that is done... then analyze every corner of code and make it as efficient as possible... the biggest reason why I get this feeling is because you got 500 objects... there is typically ways to ignore some game objects when you got so many.
     
  19. elmar1028

    elmar1028

    Joined:
    Nov 21, 2013
    Posts:
    2,359
    Hi,

    Sorry for a long reply, didn't see it. :(

    Thanks a lot. I think the best solution is to look at the logic itself. But right now I want to find the most optimal way to do this: which actions are expensive? which are cheap?

    When I upgraded my project to Unity 5 I realized that all my 500 objects are dynamically spawned so Occlusion Culling is not a solution for me :(

    Profiler was very useful, showing that finding distance between objects was one of most expensive functions.

    A few more questions:

    1) If I continuously enable/disable 2D colliders, is it going to affect my performance?
    2) Is there a cheaper method of finding a distance between game objects in Update()?

    Thanks in advance :)
     
    Krish-Vikram likes this.
  20. Mafutta

    Mafutta

    Joined:
    Sep 30, 2014
    Posts:
    45
    Last edited: Mar 25, 2017