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

Simple things in Unity that I hope get fixed/improved some day.

Discussion in 'General Discussion' started by rheirman, Sep 5, 2023.

  1. rheirman

    rheirman

    Joined:
    Sep 30, 2019
    Posts:
    34
    I've been developing a game in Unity for a couple of years now, and I've mostly enjoyed the experience. There have been a few frustrations though that I'd like to share, just to vent a bit (and who knows this'll every reach the Unity staff). They're extremely simple things that seem very rudimentary, but just ended up needing very annoying workarounds that hurt my soul. Below is my list of issues and workarounds that I used.

    Not being able to instantiate inactive game objects (without a workaround).
    There have been a few instances in my project where I really needed to instantiate an inactive game object, so that I could add a few components or do other changes to my object before any Awake methods are called. The only way I was able to do this was extremely ugly. Either:
    - I had to instantiate the object in a disabled parent, and then move the object to a different parent.
    - I had to disable the prefab from which the object is instantiated, then instantiate the object, make the desired changes, and then enable both the object and prefab again.

    No easy way to detect objects marked for destruction.
    If you call UnityObject.Destroy(), that'll mark the object for destruction, but it won't actually be destroyed until the end of the frame. This is perfectly fine for me, but what did surprise me is that there doesn't seem to be a good way to detect that the object had actually been marked for destruction. In some cases I just need to know which objects will no longer be there next frame. So what I did to solve this is add a flag to my objects called isMarkedForDestruction, and calling my own DestroyAndMark method sets this flag. However, if I forget to call this method and just call Destroy directly, the flag won't be set.

    GetComponents doesn't have a documented order
    Maybe this is just a lack of documentation, but in my project I'm serializing a bunch of compoments, and I need to know which is which when deserializing them again. For that to work I'm currently just relying on the fact that GetComponents seems to have a fixed order, but this isn't documented anywhere. To properly solve this I'd need to save an index of each component and order the components by this index when I'd retrieve them, but for various reasons that go beyond the scope of this post that would be a real pain to implement.

    Shader Graph UI shaders don't work when using an canvas with render mode set to 'overlay' (anymore)
    I'm using a couple of shader graph shaders to spice up my UI. After a recent Unity update (I don't recall which one) they just stopped working (transparent pixels got replaced by black pixels). Apparently this is 'by design' (see: https://issuetracker.unity3d.com/is...-ui-with-canvas-render-mode-set-to-overlay).I fail to understand why. I had to switch over to render mode: camera, and that fixed it, but it was a massive pain to make this switch.

    If I simply missed something and there was a better way to do what I wanted to do, please correct me!
     
    Last edited: Sep 5, 2023
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    Just have a method, which destroys, and marks whatever properties you need.

    Single responsibility principle.
    Then you never forget to call anything.
     
  3. rheirman

    rheirman

    Joined:
    Sep 30, 2019
    Posts:
    34
    So what I did to solve this is add a flag to my objects called isMarkedForDestruction, and calling my own DestroyAndMark method sets this flag. However, if I forget to call this method and just call Destroy directly, the flag won't be set.

    Maybe I'm misunderstanding your point, but that's exactly what DestroyAndMark does - it destroys and marks the object. I won't forget calling it, but I'm not working on this project alone. I have to tell everyone that contributes: 'hey, don't just Destroy, but please call our own DestroyAndMark implementation. If Unity did the actual marking, then everyone would be on the same page by default.
     
  4. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    524
    If you are open to discussing these it might turn out that a) it isn't so very important and/or b) something else :)

    Not being able to instantiate disabled behaviours (without a workaround).

    Isn't "disabled" defined? So there would be a disabled but not really disabled setting? Ideally you could post an example and perhaps there is a not-so-ugly solution. Or on the other hand people agree with the assessment.
     
  5. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    524
    No easy way to detect objects marked for destruction.

    Isn't sub-frame time a very short period in which to check the status of something that will be gone? Would the property be there to check after it was destroyed?

    Again I don't know your particular use case but any sort of example would help. Not just in Unity but I have never destroyed/disposed of an object and then wondered what some property value was immediately afterward.
     
  6. rheirman

    rheirman

    Joined:
    Sep 30, 2019
    Posts:
    34
    Sorry, I'm reading back what I typed now and I clearly wasn't paying attention to what I was typing. I typed 'behaviours', but the actual problem I had was with game objects that cannot be instantiated in an inactive state. I edited the post, it should be a bit more clear now.
     
  7. rheirman

    rheirman

    Joined:
    Sep 30, 2019
    Posts:
    34
    Maybe it's quite specific to my project, but it can happen quite easily actually.

    Just to give an example. I have routine in my game that lets a character load a cannonball into a cannon. When the cannonball is loaded, the cannonball is destroyed, and the routine ends. When the routine ends, there's a check that lets characters drop any items they were carrying to complete that job if they were still carrying something (this is to make sure characters never have). However, without any precautions, the character will drop the to be destroyed cannonball before it actually gets destroyed (causing further issues since that to be destroyed cannonball gets registered elsewhere). You could say: why don't you just wait a frame and let the job end after that, but this code is generically used in different places, so having to wait a frame for nothing would be undesired.
     
  8. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    524
    I'm not finding the current system to be particularly limiting. Rarely I've had to implement a Initialize method to properly set up something with dependencies that may not be ready. I'll hazard a guess that you will never be able to instantiate an inactive game object if you cannot do that now. Won't it break things for everyone else?
     
  9. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    524
    Maybe it's quite specific to my project, but it can happen quite easily actually.

    Maybe a bit too specific :) I think convincing the rest of your team to use your method would be easier. Do they make up their own logging options? Set the colors to whatever they feel like? A bit of agreement would go a long way and you will notice the problem and the problematic coder during the code review before merging the changes.

    I don't see how (if the property is part of the object being destroyed) that you have a reasonable chance of checking the value of the property. In any case (again) I don't see it being implemented.
     
  10. IllTemperedTunas

    IllTemperedTunas

    Joined:
    Aug 31, 2012
    Posts:
    608
    Have you tried initializing in the "OnDisable()" or "OnEnable()" function? Are you utilizing both Awake() and Start() to step initialization?

    Also don't forget you can sort the call order of scripts in preferences, this is super important for initializations to work properly. Setting the initialization script, or the scripts they rely on to the bottom or top of the call order might rectify the problem (but can also break everything if you're not careful).
     
  11. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    524
    I just checked my code and I apparently worked around the need for the Initialize method some time back. It was just being called from Start so I've moved it now. OnEnable is a good one to remember, thanks.

    This is for a VRChat project and we don't have access to Awake. The ordering of scripts could be very useful in some cases.
     
    IllTemperedTunas likes this.
  12. FredMoreau

    FredMoreau

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    112
    Hi @rheirman,

    regarding
    Can you provide mode details, like which Unity version, which Render Pipeline and which Target/Sub-Target you're using?

    Thank you.
     
  13. rheirman

    rheirman

    Joined:
    Sep 30, 2019
    Posts:
    34
    Oh yeah definitely, and I'm aware of being able to set execution order through the settings and I use OnEnable, Awake and Start. It's a bit hard to explain why I need this without explaining a lot of context, but I can give an example.

    We have a parser in our project that (very boldly said) loads xml and turns it into game objects and components. Objects generated this way need to behave consistent to objects that are already in the scene or are loaded from a prefab directly. However, for the parser to work, it needs to instantiate a game object from a prefab, then add components loaded from xml. However the problem I'm running into with this is that the object loaded from the prefab calls all its awake and OnEnable methods immediately when it is instantiated. At this moment the components from xml haven't been added, and the object actually expects those components to exist. Sometimes this can be solved by just putting all code that expects dependencies to be loaded in the Start method, but that isn't always sufficient, some code just needs to be executed in Awake (I can give a concrete example of this, but I don't wanna make this a long wall of text).
     
  14. rheirman

    rheirman

    Joined:
    Sep 30, 2019
    Posts:
    34
    It might be for you because you never ran into this issue :). I'm definitely not the only one working around this. Here's a random thread proving that: https://forum.unity.com/threads/how-to-check-if-a-gameobject-is-being-destroyed.1030849/

    I can understand though that showing a random post that shows I'm not the only one tackling this issue isn't a great way of proving that this should be a feature built in Unity, but to me it just seems that whether an object is marked for destruction is relevant info that should be exposed.
     
  15. rheirman

    rheirman

    Joined:
    Sep 30, 2019
    Posts:
    34
    I'm using Universal Render Pipeline, Unity Version 2021.3.6f1, Target Platform: Windows 64-bit. I think it stopped working after I switched from 2020 to 2021. There's a thread about this exact same issue here: https://forum.unity.com/threads/shader-graph-ui-image-shader-does-not-work.1202461/page-2

    Oh I read at the end of the threat there's a fix for this in Unity 2023, a bit too late for me though :).
     
    Last edited: Sep 5, 2023
  16. IllTemperedTunas

    IllTemperedTunas

    Joined:
    Aug 31, 2012
    Posts:
    608
    Random idea, instead of instantiating from a bare bones prefab, have you considered instantiating a prefab, adding the components, THEN instantiating a prefab of that clone so the components all exist when it's generated? (I'm not entirely sure this is possible) Then you could destroy the middle clone object or use it as a base for generating other objects that need these components.

    I'm not familiar with your project, but could you maybe migrate all your initialization code from awake and put them at the start of your fixed update since your components stream in over several frames:
    if(componentsDontExist) { try to add components; return;} //at the start of updates to various loops where things aren't working properly.

    I've been through some nightmare scenarios with initializations, and one thing that would have certainly helped, is better directing to where in the code the missing data was so I could have quickly solved the issue. Sometimes the debug messages take us directly to the problem when we double click it, and sometimes it just takes us to a very top level function call, and we're totally lost as to where the data isn't being communicated.
     
  17. rheirman

    rheirman

    Joined:
    Sep 30, 2019
    Posts:
    34
    Oh that's an interesting solution. I didn't consider that yet no. However the current solution I'm using works fine actually:
    I disable the prefab object directly, then spawn the object using the disabled prefab (the object gets instantiated disabled this way), then I add all the components, and then I set the object active, and I make sure that the the prefab object active state is reset to its old value again.This works, but it isn't exactly elegant (neither is creating an in-between object that needs to be destroyed)

    Migrating all Awake calls is something that I just cannot afford right now given the scope of the project. Putting it on FixedUpdate actually wouldn't work for all objects, because objects register the space they occupy in their Awake method. When spawning multiple objects in the same frame, I need to make sure they don't occupy the same space. Of course it would be possible to move the objects after spawning them, but that could mean there won't be enough space to spawn all objects and this would be detected too late then.

    All I'm saying is that it would be absolutely great for this kind of work if you'd be able to instantiate objects without them triggering their Awake/OnEnabled methods immediately (without any workarounds).
     
  18. FredMoreau

    FredMoreau

    Unity Technologies

    Joined:
    May 27, 2019
    Posts:
    112
    Yes, UI Canvas sub-targets were added to all three render pipelines in 2023.2.
    There are ways to use other sub-targets for UI shaders, but with issues, which is why it was addressed with new specific sub-targets.

    Thanks for your feedback.