Search Unity

Optimization tips

Discussion in 'Editor & General Support' started by lothlorientos, Sep 28, 2014.

  1. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    Hi! I'm looking for Unity optimization tips for when porting to phones.

    I already tried compressing my assets (sprites, music, etc.) but the game will either be laggy or will crash on startup depending on the phone specs.

    What could be the reason for this? My code looks fine with no exceptions.
     
  2. Berans

    Berans

    Joined:
    Sep 28, 2014
    Posts:
    9
    What's your draw call count? How many tris are you drawing each frame?...Are you doing any string lookups like Gameobject.Find etc. in an update loop? So many possibilities.

    Those are the things I'd look at first - see if you can reduce your draw calls if they're high, since most phones aren't able to deal with very many (I seem to recall the iPhone 4S can only handle something like 50-60 per frame at most before you won't be able to make 60fps)

    If your draw calls are fine the next big thing is your update loops. Things like string lookups can compound to be quite expensive if called every update. Any kind of reflection feature also tends to be relatively slow. (Things like GetComponent<type> or GetObjectOfType).

    If your update loops are all dandy have a look at your physics. Try increasing the fixed timestep to get fewer physics updates if you can get away with it, since physics can put quite a strain on the processor.

    If you have access to unity pro you should have a look in the profiler for clues as to what you should be looking at first (keep in mind the relative specs of the platform you're running the editor on versus a phone). Otherwise the suggestions I just gave you should give you a decent starting point
     
    lothlorientos likes this.
  3. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    Draw Calls=10
    tris start from 16-20
    verts= 32
    vram 3.9-9
    used textures 8-3.1 mb

    I use some:
    IEnumerator
    OnTriggerEnter2D
    OnTriggerExit2D
    some Inputs in update
    OnMouseDown
    OnMouseDrag
    OnMouseUp
    I have a list that I spawn objects in
    I have an IEnumarator with a
    while{
    foreach
    {
    //code
    yield
    //code
    }
    //code
    }
     
  4. Berans

    Berans

    Joined:
    Sep 28, 2014
    Posts:
    9
    How about your texture sizes (dimensions, that is)?
    Phones tend to have quite a limited max texture size which can certainly cause crashes if it is exceeded (although that shouldn't be a lag problem)
    do you have a lot of physics in your game?
     
    lothlorientos likes this.
  5. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    I debugged again and I got this exception:

    System.InvalidOperationException was unhandled by user code
    Message: An exception of type 'System.InvalidOperationException' occurred in mscorlib.ni.dll but was not handled in user code
    Additional information: Collection was modified; enumeration operation may not execute.

    and it was on the line where I use the foreach inside the IEnumarator
     
  6. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    Yes I have a lot of physics but not when it starts. But in some phones it crashes on startup.
     
  7. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    Dimensions are not very big. 1000X1000 184x1024
    but size is very small, only some kb
     
  8. Berans

    Berans

    Joined:
    Sep 28, 2014
    Posts:
    9
    Could you show me a snippet of what you're doing inside the foreach loop? It's possible that you're invalidating the collection you're looping over which could potentially cause a crash

    Edit: To clarify - When you're using a foreach loop, you can't change what's inside the container you're looping over. Adding or removing anything from the container breaks the way foreach works so it won't let you do that.
     
    Last edited: Sep 28, 2014
    lothlorientos likes this.
  9. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    1. IEnumerator CheckMoving()
    2. {
    3. while (objmoving != objs.Count) {
    4. objmoving = 0;
    5. foreach (GameObject obj in objs)
    6. if (obj.tag == "BlockPlaced") {
    7. Vector3 startPos = obj.transform.position;
    8. yield return new WaitForSeconds (0.1F);
    9. Vector3 finalPos = obj.transform.position;
    10. if( startPos.x != finalPos.x || startPos.y != finalPos.y || startPos.z != finalPos.z)
    11. {
    12. objsOnTheMove = true;
    13. Debug.Log ("ISMOVING");
    14. objmoving=0;
    15. }
    16. else {
    17. Debug.Log ("ISNOTMOVING");
    18. objmoving ++;
    19. }
    20. } else {
    21. objmoving ++;
    22. Debug.Log ("ERROR");
    23. }
    24. }
    25. scorecounter.SendMessage ("goenable", 0, SendMessageOptions.DontRequireReceiver);
    26. Debug.Log ("DONE");
    27. }
    28. }

      the exception here would hit on line 5 I think
     
  10. Berans

    Berans

    Joined:
    Sep 28, 2014
    Posts:
    9
    Almost certainly one of the objects in objs is being removed, added or reassigned at some point, asynchronously. Which means your loop is no longer valid.
    Why not give your objects a rigidbody so they have a velocity, that way you don't have to check their position twice and can instead just check against a > 0 velocity.

    I'm not entirely sure what you're trying to achieve here, but it seems to me that you might need to rethink how you're doing that particular bit of code. I can think of a number of ways in which that might become problematic
     
    lothlorientos likes this.
  11. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    By the time I run that bit of code there is no way that it will spawn or remove any obj untill it's done.

    But thanks I'll try the velocity check and I'll update you ;)
     
  12. Berans

    Berans

    Joined:
    Sep 28, 2014
    Posts:
    9
    Also, is there any reason why you can't just check for moving objects once per, say, FixedUpdate?
    i.e. just run a single foreach loop each FixedUpdate to check the velocity or movement states of each of your objects. if nothing's moving, send your message, if something's moving, just keep chugging.
    If you don't care how many objects are moving you can also save yourself a LOT of potential cycles by simply breaking out of the loop early.

    i.e. as soon as you've found a moving object:
    Code (CSharp):
    1. if (object is moving)
    2. {
    3.     objsOnTheMove = true;
    4.     break;
    5. }
    that way you're not checking all the other objects when you already know you have a moving one.

    Just some considerations for you. I'm not sure exactly what you're doing so I'm only offering suggestions based on my best guess

    EDIT: obviously replace "object is moving" with an actual check. That was just psuedocode for my sanity :p
     
    lothlorientos likes this.
  13. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    1. void checkmove()
    2. {
    3. objsnotmoving = 0;
    4. while (objsnotmoving != objs.Count) {
    5. objsnotmoving = 0;
    6. foreach (GameObject obj in objs) {
    7. if (obj.tag == "ObjPlaced") {
    8. if ((int)obj.rigidbody2D.velocity>0) {
    9. Debug.Log ("ISMOVING");
    10. objsnotmoving = 0;
    11. } else {
    12. Debug.Log ("ISNOTMOVING");
    13. objsnotmoving ++;
    14. }
    15. } else {
    16. objsnotmoving ++;
    17. Debug.Log ("ERROR");
    18. }
    19. }
    20. }
    21. scorecounter.SendMessage ("goenable", 0, SendMessageOptions.DontRequireReceiver);
    22. Debug.Log ("DONE");
    23. }
    I know it's noob question but when I use this code I get:
    Cannot convert type `UnityEngine.Vector2' to `int' (line 8)
    so I put (int) in front of it but nothing changed. How do I convert to int? XD

    Thanks for the thought but I think it would be more painfull in the update because I don't need to check all the time, only on certain points of the game. but it would be cool if I used break I guess... It would save a lot of computing.
     
  14. Berans

    Berans

    Joined:
    Sep 28, 2014
    Posts:
    9
    Why convert that to an int?
    You're probably looking for:
    obj.rigidbody2D.velocity.sqrMagnitude > 0
    You can still explicitly cast that to an int but you don't need to.
    sqrMagnitude will give you the cheapest way to check whether the objects velocity is greater than 0 (avoids a square root)

    you can't cast velocity to an int because velocity is a vector consisting of an x and y component

    As for not checking all the time, a simple bool would do the trick. i.e. run the check each frame while a bool is true (and turn it off when you're done checking)
     
    lothlorientos likes this.
  15. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    ok for some reason Unity freezes when I run that bit of code. I don';t know why... and then I have to End task it and reopen Unity.
     
  16. Berans

    Berans

    Joined:
    Sep 28, 2014
    Posts:
    9
    That would be because your loop is infinite - remember that you're no longer yielding (that's a good thing, yields aren't fantastic) so your objects aren't getting updates. That's why I suggested just running it in the fixed update with a bool to indicate that you need to check for moving objects
     
    lothlorientos likes this.
  17. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    1. void FixedUpdate()
    2. {
    3. if (ckecking==true) {
    4. Objsnotmoving=0;
    5. foreach (GameObject Obj in Objs) {
    6. if (Obj.tag == "ObjPlaced") {
    7. if (Obj.rigidbody2D.velocity.sqrMagnitude >0) {
    8. Debug.Log ("ISMOVING");
    9. Objsnotmoving=0;
    10. break;
    11. } else {
    12. Debug.Log ("ISNOTMOVING");
    13. Objsnotmoving=++;
    14. }
    15. } else {
    16. Debug.Log ("ERROR");
    17. Objsnotmoving=++;
    18. }
    19. }

    20. if (blocksnotmoving==blocks.Count) {
      ckecking=false;
      scorecounter.SendMessage ("goenable", 0, SendMessageOptions.DontRequireReceiver);
      Debug.Log ("DONE");
      }
    21. }
    22. }

      OK this is it and i think it works. I'll check on Phone now
     
    Last edited: Sep 28, 2014
  18. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    I checked Phone , I thought it worked at first, it was less laggy and did less random things but it still has problems.
    How the game works is that it spawns a Obj, then it checks if all Objs are moving or not, and if not it spawns a new one. But I see that sometimes it spawns 2 together (before I make the code changes it would spawn like 20 XD )
    Also sound is laggy. And when I close sound by pressing a button I created which shows when is on and off, by the time i first press that button it goes from one state to another all the time without stopping.

    But in Unity for some reason all work fine
     
  19. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    What's weird is that when I try it to my android phone it works fine, but when I run the emulator for windows phone of visual studio it's laggy and does random things that it shouldn't.
     
  20. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    ok so I tried to debug it on Visual Studio ,not in Master as I used to, but in Debug mode. and I got new exceptions.
    It says that MouseEvents.cs not found. any ideas? do I need to change the the mouse controls with touch controlls? even though it should work fine with mouse anyway?
     
    Last edited: Sep 29, 2014
  21. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    What's the full error message?
     
  22. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    I don't remember the excact report, but it was like in this link:
    http://answers.unity3d.com/questions/752477/unity-didnt-generate-mouseeventcs.html
    I know it because when I searched for the problem I found this question and it was the same as my problem.

    Also I think that Visual Studio Emulator for windows phones that opens projects from unity isn't working correctly. It's laggy runs code that it shouldn't or just runs parts of code more times than it should, or it gets more inputs (like mouse, touch) than it should. And this made me think that I did something wrong with my code. But when I tried the same .xap on a real windows phone it worked like a charm.
    Btw: I'm pretty sure it's not a PC spec problem, because I have a quite high end one.
     
  23. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    You need to be much more specific if you want help. As the saying goes, help the person to help you.
     
  24. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    Yes, sorry. I actually fixed the problem. I just debuged it on Master and it was ok. Also I thought my game was problematic but it turns out that it was the emulator's problem. After Berans helped me and I run it on a real device it worked like a charm!! So thank you very much Berans :D ;)
     
  25. lothlorientos

    lothlorientos

    Joined:
    May 20, 2014
    Posts:
    32
    If I come across again with this problem I will let you know the full report :)