Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Tile GameObject Positioning/Instantiation Issues (2020.3.38)

Discussion in '2D' started by diesoftgames, Jul 17, 2023.

  1. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    114
    When using a GameObject with a tile, that GameObject instance will be instantiated with a position of 0,0,0 and then after instantiation, will have its position corrected to match the tile. This is a problem if your GameObject has components which want to make use of its position in their Awake function (for instance if you need to do some parallaxing behaviour and need to make sure it happens the same frame the GameObject is spawned to prevent it flashing in the incorrect position).

    This would be a relatively easy thing to work around by disabling the Prefab being used as the GameObject and then calling SetActive(true) in your own StartUp method on the Tile, but the spawning/initialization logic also seems to call SetActive(true) before it calls your StartUp method.

    tldr; it seems like a tile's GameObject is being spawning with something like:
    Code (CSharp):
    1. var tileInstance = GameObject.Instantiate(tileObj, parent);
    2. // Setting tile position after instantiation
    3. tileInstance.transform.position = tilePosition;
    4. // Unnecessarily setting our instance to active
    5. tileInstance.SetActive(true);
    Instead of something like:
    Code (CSharp):
    1. var tileInstance = GameObject.Instantiate(tileObj, parent, tilePosition);
    Ultimately to work around this, I had to create a root GameObject inside my prefab which my Tile's StartUp method is responsible for enabling so that I can ensure Awake isn't called until we're in the correct position.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    If this is indeed happening:

    Then yes, it's kind of annoying.

    But it is still something reasonable to expect from a script standpoint. Why not observe the position in Start() and handle it there? Nobody else needs to know about parallaxing (your example).

    If you expect varying positions then read them in Update() and compare them to a stored value and if they change, do whatever change you need to update it.

    Also you should strive to do things in Start() unless they really need to be observed by someone else in Start().

    The reason is that Awake() and OnEnable() are these "edge of the sticky envelope" kinda functions, called deep in the commissioning process of Unity objects when the game scene is in an undefined state.

    Why not wait until all the dust settles and do stuff in Start()? I do almost nothing in Awake() except things that truly are local and stateless.

    You should also strive to make your scripts not sensitive to small timing differences like this.

    This approach:

    is fragile. Very fragile. Far less fragile would be to just move the code to Start() (or even Update() as noted above).
     
  3. diesoftgames

    diesoftgames

    Joined:
    Nov 27, 2018
    Posts:
    114
    Yeah, you're right, I'm able to shuffle around some other scripts to use Start instead of Awake to make this work rather than having to do that first gross workaround I came up with. I suppose I should start focusing more on using Start vs Awake, but I got into a habit in my own code of not having any problems with it by simply passing the position into the Instantiation call.

    While it's not a problem for this current use case now, it does seem a little odd for it to set my gameObject to active. If a prefab has been deactivated, I typically do that because I want to make sure it spawns in deactivated for whatever reason.