Search Unity

Setting position not working on last iteration

Discussion in 'Scripting' started by Mikenekro, Aug 30, 2018.

  1. Mikenekro

    Mikenekro

    Joined:
    May 11, 2014
    Posts:
    21
    So I am looping through each character class that the player can select and instantiating the toggle on the screen. Everything works fine until it gets to the last toggle.

    On the last toggle, setting the localPosition of the instantiated object displays correctly in the Debug.Log but in the editor, the localPosition does not change.

    For instance:

    if the mainTog localPosition = 0, -25, 0
    and the last iteration moves the toggle to: 0, -175, 0
    Debug.Log displays the position as: 0, -175, 0
    but the screen and inspector show the position as: 0, -25, 0

    So if there are 4 classes in the classes list, the first 3 classes are instantiated correctly but the 4th character class is not instantiated correctly.

    Does anybody know why this is happening? Also, why does this only happen on the last item in the list?

    Note: int pos = i; is there for the AddListener

    Code (CSharp):
    1.  
    2. Toggle mainTog;
    3. GameObject newToggle;
    4. List<CharClass> classes = ClassHolder.Classes;
    5.  
    6. for (int i = 0; i < classes.Count; ++i)
    7. {
    8.     int pos = i;
    9.  
    10.     newToggle = Instantiate(mainTog.gameObject);
    11.     newToggle.transform.SetParent(mainTog.transform.parent);
    12.     newToggle.transform.localPosition =
    13.     new Vector3(newToggle.transform.localPosition.x, mainTog.transform.localPosition.y - (pos * 50.0f), 0);
    14.              
    15.     Debug.Log("Class Number: " + pos + ", Local Position: " + newToggle.transform.localPosition);
    16.  
    17.     newToggle.GetComponentInChildren<TextMeshProUGUI>().text = classes[pos].Name;
    18.  
    19.     newToggle.GetComponent<Toggle>().onValueChanged.AddListener((val) => { SelectClass(pos, val); });
    20. }
    21.  
    Also, I just tried this: If I put the code in a Coroutine and wait for 1 frame before instantiating, this fixes the problem but I am still at a loss as to why this even happened in the first place.

    Code (CSharp):
    1.  
    2. Toggle mainTog;
    3. GameObject newToggle;
    4. List<CharClass> classes = ClassHolder.Classes;
    5.  
    6. for (int i = 0; i < classes.Count; ++i)
    7. {
    8.     int pos = i;
    9.  
    10.     yield return null;
    11.  
    12.     newToggle = Instantiate(mainTog.gameObject);
    13.     newToggle.transform.SetParent(mainTog.transform.parent);
    14.     newToggle.transform.localPosition =
    15.     new Vector3(newToggle.transform.localPosition.x, mainTog.transform.localPosition.y - (pos * 50.0f), 0);
    16.              
    17.     Debug.Log("Class Number: " + pos + ", Local Position: " + newToggle.transform.localPosition);
    18.  
    19.     newToggle.GetComponentInChildren<TextMeshProUGUI>().text = classes[pos].Name;
    20.  
    21.     newToggle.GetComponent<Toggle>().onValueChanged.AddListener((val) => { SelectClass(pos, val); });
    22. }
    23.  

    I am on Windows 10 using Unity 2017.3.0f3
    Building for Standalone build
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Is it possible that anything else is changing the position of the last one after you create it? Layout groups? Other code that references the same variable? Something in the Awake() or Start() of the prefab you are duplicating?

    You might try increasing or decreasing the number that you are creating to determine whether it happens to "the last one" or "the Nth one".
     
  3. samizzo

    samizzo

    Joined:
    Sep 7, 2011
    Posts:
    487
    Echoing what @Antistone said, is there an animator that might be writing defaults? Probably not the case because you said it only happens to the last item in the list and each item is the same prefab but you never know.

    Sam
     
  4. Mikenekro

    Mikenekro

    Joined:
    May 11, 2014
    Posts:
    21
    @Antistone

    Yea I just tried with 15 iterations and it is always the last one that this happens to. Also nothing else touches the position of these objects besides the instantiation (see below). The only thing that modifies them currently is the code above.


    @samizzo

    With the defaults, I did shorten the instantiation in the code above and I had it instantiating to the "mainTog" localPosition. I tried again without using
    newToggle = Instantiate(mainTog.gameObject, mainTog.transform.localPosition);
    but then it just instantiates below and left of the position that I assign (See image).

    Edit:
    Does this mean that the Instantiation is changing the position back at the end of the frame after I assign a new position?
     

    Attached Files:

  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I don't understand your picture. The "Nulls" all look lined up. There's a white box in the last row that looks odd, but if that's the thing you're talking about, there's a lot different than just its position!

    In order to ensure that you're looking at the objects you think you are, maybe add a line that sets
    newToggle.gameObject.name = "Toggle " + pos
     
  6. Mikenekro

    Mikenekro

    Joined:
    May 11, 2014
    Posts:
    21
    @Antistone

    Right that last box is the last button. I added the loop position to it and disabled the scroll mask so you can see the what is happening better.

    Edit: The white box was just the highlight from hovering over the toggle.
     

    Attached Files:

  7. samizzo

    samizzo

    Joined:
    Sep 7, 2011
    Posts:
    487
    It might be even simpler if you just use a VerticalLayoutGroup - then you don't even have to bother setting the position at all (sorry, I know that doesn't answer the "why is this happening" though :).

    Sam
     
  8. Mikenekro

    Mikenekro

    Joined:
    May 11, 2014
    Posts:
    21
    @samizzo

    You're right, I didn't even think of that haha. I'll give that a try. This is still a strange issue.
     
    samizzo likes this.
  9. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Setting the position manually is more efficient than using a layout group, because the layout group will (almost certainly) recalculate positions more often than necessary. But if performance is not a major concern, either a vertical layout group or a grid layout group can probably arrange things the way you want.

    Your OP described a problem with the Y coordinate, but that looks like it's in the wrong place horizontally. My instinct is that something is messing up your anchors and/or pivot.

    A couple of oddities I notice in your posted code, that may or may not be relevant:
    • You set the X position relative to newToggle but set the Y position relative to mainTog.
    • newToggle appears to be scoped to the class rather than the function, which means it could theoretically be accessed from other functions.
    Regardless, it seems you must be mistaken in thinking that nothing else is modifying the toggle's position. I don't know what is modifying its position after your posted code, but something must be.
     
    samizzo likes this.
  10. Mikenekro

    Mikenekro

    Joined:
    May 11, 2014
    Posts:
    21
    Yea the X position was a mistake. It should have been mainTog. The code was actually inside of a function so none of them were scoped to the class. Sorry about that, I should have made that more clear.

    Other than that, I'm not sure what else could be changing it. I just created a brand new project that only has this code and the last toggles position is still in a very odd position.

    I don't know what version of Unity you have (I created this in 2017.3.0f3), but you can take a look at this new project where this also happens.
     

    Attached Files:

  11. samizzo

    samizzo

    Joined:
    Sep 7, 2011
    Posts:
    487
    I took a look at your project in Unity 2017.3.0p3 and it happened to me also, even if you replace the toggles with a simple text label. This seems like a bug - I would report it to Unity and attach this project!

    Sam
     
    Mikenekro likes this.
  12. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Converted your test project backwards to Unity 2017.1.1f1 and I was not able to reproduce your behavior. Tog 20 is in the proper position for me.

    (By the way, unless your game allows multi-classing, you may want to add a ToggleGroup.)
     
    samizzo likes this.
  13. Mikenekro

    Mikenekro

    Joined:
    May 11, 2014
    Posts:
    21
    @Antistone

    Must be a bug specific to the 2017.3.0 versions (maybe higher or 1 version lower). I wonder what changed in Unity 2017.3.0 that caused that? Not really asking, just pondering.

    For now I'm just going the route @samizzo pointed out for any dynamically sized scrollviews and if I need the bit of extra performance later, I could just create them in a coroutine or add an extra object that is disabled.

    Thanks for the help!

    Edit:
    Looks like this was fixed in 2018.2

    UI: Position and rotation specified when calling Object.Instantiate was not applied properly for a RectTransform (980300)
     
    Last edited: Aug 31, 2018
    samizzo likes this.