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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Feedback on Unity3D's API. What i've found in 2017

Discussion in 'Editor & General Support' started by CyberFox01, Jan 2, 2018.

  1. CyberFox01

    CyberFox01

    Joined:
    Oct 5, 2012
    Posts:
    23
    Merry Christmas and Happy New Year. Starting off with a grand ambition.

    About a year in with working intensely with Unity3D I have assembled a list of things that is either, broken, bothersome or can be improved. In hopes of at least reaching the attention of UT developers i give you this.
    Some are simple. I am solely a programmer so this will be mostly about the API side of U3D.
    I'm marking the headers with a color ranging from green to red indicating the severity.
    Let's begin:

    Vectors

    Transform properties
    An angel dies every time you write this:
    Code (CSharp):
    1. var pos = gameObject.transform.position;
    2. pos.y += Time.deltaTime;
    3. gameObject.transform.position = pos;
    But a simpler approach would be to write
    Code (CSharp):
    1. gameObject.transform.position.y += Time.deltaTime;
    newcomer scripters will not understand why this "sensible" line wont work.

    Another example commonly used in 2D games
    Code (CSharp):
    1. gameObject.transform.position.z = 0;
    at least provide methods to set/mutate individual components of the vectors.
    Code (CSharp):
    1. gameObject.transform.position.SetZ(0);
    2. gameObject.transform.position.AddZ(Time.deltaTime);

    change the position property to a field. Other properties such as scale and rotation could also be changed.
    Note: eulerAngles is a computed property and wont function if changed into a field.​


    Vector Math Operators
    Code (CSharp):
    1. public static Vector3 operator *(Vector3 a, Vector3 b);
    2. public static Vector3 operator /(Vector3 a, Vector3 b);
    I studied about this and found that there is quite a controversy about this and i see UT has chosen not to take a stance on this. The opinion of mathematicians is that vectors are cross multiplied. According to Wikipedia the X and * symbols are ambiguous to either function.

    In my opinion vectors should be multiplied linearly, cross multiplying is counter intuitive.

    Code (CSharp):
    1. // example of positioning an object at the bottom of a bounding box
    2. transform.position = bounds.center + (Vector3.forward * bounds.size);
    3.  
    4. // example of keeping keeping an object grounded
    5. transform.position *= new Vector3(1, 0, 1);
    this also includes the division operator.
    Code (CSharp):
    1. //example of changing 1 object scale to fit another object
    2. transform.scale = 1 / transform.scale * transform2.scale;
    and lastly. the + and - operators on primitive types. And they behave just like the scalar multiplication.

    Code (CSharp):
    1. public static Vector3 operator +(Vector3 v, float scalar) => new Vector3(
    2.     x = v.x + scalar,
    3.     y = v.y + scalar,
    4.     z = v.z + scalar
    5. );


    Remove implicit operators
    I cannot count how many times i have screwed up and hunted for the error throughout my entire codebase just find that i wrote Vector2 instead of Vector3.

    for example:

    Code (CSharp):
    1. Vector3 p1 = new Vector3();
    2. Vector2 p2 = new Vector3(1, 1, 1);
    3.  
    4. var center = p1 - (p2 - p1)/2;
    or if you're like me and use implicit variables

    Code (CSharp):
    1. var p1 = new Vector3.zero;
    2. var p2 = new Vector2.one;
    3.  
    4. var center = p1 - (p2 - p1)/2;
    the expected result is a Vector3.one/2 right? Wrong!
    The result for both is actually: {.5f, .5f, 0} for both.
    Z turned to zero. Why? What happened is that i have accidentally written Vector2 instead of Vector3 in p2 and U3D liberally converts between them.
    This is especially troublesome when you go crazy with autocomplete and you write vec{enter}.up.

    Vectors aren't interchangeable. Whether or not the programmer is converting from 2d to 3d coordinates is up to the programmer how he want to map the components.
    Some want to use XY for side-scroller
    Others use XZ for top down

    So just remove all the implicit operators as they cause more harm than good.​

    Remove partial constructors in vectors
    Also a bit continued on the implicit operators are the constructors. Which can also cause confusion.
    The only constructors necessary are

    Code (CSharp):
    1. public class Vector2{
    2.    public Vector2();
    3.    public Vector2(float x, float y);
    4. }
    5.  
    6. public class Vector3{
    7.    public Vector3();
    8.    public Vector3(float x, float y, float z);
    9. }
    this one is pointless. again it's up to the programmer how they handle 2d -> 3d conversions

    Code (CSharp):
    1. public Vector3(float x, float y);


    While making this list i came to realize that these are too experimental and doesn't provide anything of substance. They a interesting though. You don't have to read this section. There is also no color markers.

    Vector IEnumerable implementation
    I have this one my own Vector2 implementation but i have personally never used it.

    Code (CSharp):
    1. public IEnumerator<float> GetEnumerator() {
    2.    yield return x;
    3.    yield return y;
    4. }
    5.  
    6. IEnumerator IEnumerable.GetEnumerator() {
    7.    return GetEnumerator();
    8. }
    Code (CSharp):
    1. Vector3 p1 = new Vector3(1, 1, 1)
    2.  
    3. var sum = p1.Sum(); // 1 + 1 + 1 == 3 using linq


    IEnumerable<float> to VectorN
    an extension method.
    Code (CSharp):
    1. public static Vector3 ToVector3(this IEnumerable<float> enumerator){
    2.    var arr = enumerator as float[] ?? enumerator.Take(3).ToArray();
    3.    return new Vector3(arr[0], arr[1], arr[2]);
    4. }
    which enables this
    Code (CSharp):
    1. var vec = new float[]{ 1, 1, 1 }
    2. var point = vec.ToVector3();
    it may be useful when porting data.​


    Vector collection initializes
    this one is pretty handy but is sadly only available inside on object initialization expressions.

    Code (CSharp):
    1. public class Vector3 : IEnumerable<float>{
    2.    private int _index;
    3.    public void Add(float n){
    4.        switch(_index++){
    5.            case 0: x=n; return;
    6.            case 1: y=n; return;
    7.            case 2: z=n; return;
    8.        }
    9.    }
    10. }
    and usage would be:

    Code (CSharp):
    1. public class Vectors{
    2.    public Vector3 Pos;
    3.    public Vector3 Rot;
    4.    public Vector3 Size;
    5. }
    6.  
    7. var newVecs = new Vectors{
    8.    Pos = { 0, 0, 0 },
    9.    Rot = { 0, 90, 0 },
    10.    Size = { 1, 1, 1 }
    11. };


    Editor

    Play mode persistence
    The toy-box Playmode is a neat idea where you can try out stuff and it wont mess up your scenes while you do it. But there is grief when you're adjusting the properties of something live. Like you're adjusting the speed of running cycle and you must run it in Playmode. Now this is simple of course when you just need to remember 1 property value. But when you have 10 changes you need to screenshot them and spend time typing them back in. Or you simply forget and start screaming when everything resets after 30 minutes of adjustments.

    There would be solutions available. For example when you exit Playmode U3D will give you a list of properties you changed and ask which you want to save.

    Another solution would be the ability to firstly identify which properties has been altered. Much like Maya does when you have key-framed properties. Unity should highlight changed properties and with an ability to save with in the right click menu.​


    Always Online
    I guess this one is gonna fall on powerless ears since this stuff is usually decided by the brass.
    The U3D launcher will show a white screen until a connection can be established. Living in a 3rd world country this is quite a hassle cause with the spotty internet there quite a chance i need to restart the launcher several times until it successfully connects.
    And even when i manage to actually open the project there's a chance it will pop up again asking me for login.
    I figured if i blocked it in the firewall it would revert to offline mode automatically but i need to disable the entire network adapter for that to happen. Even with the offline license installed. If the adapter is connected you must connect before using U3D.
    I have a solution that works for now, I'm not gonna share it cause i have a feeling UT is making active efforts to patch these methods and keep U3D online by all means.

    But why need so much license verification for a product that's free? Dial down on the always online DRM and my life would be a bliss.​


    Threading

    Simple static function to return back to the mainthread
    I could create my own tools for this but i'd like a first class solution that doesn't come off as an ugly hack.
    I'm talking about background threads.
    there is the MonoBehavior.Invoke() but it doesn't work like you'd expect. I know U3D officially doesn't support threading. But for those who decide to do it anyway. At least give us a way to send functions back to the main thread. Any UI framework i know of have this. BeginInvoke(Action), Dispatcher.Invoke(Action) and it's boilerplate design when working with HTTP.​

    UnityWebRequest Background thread
    I can't begin to fathom the inner workings take enables unity to use the IEnumerable hack work, and it's most likely what prevents threading from working. But nonetheless calling a WebRequest from a background thread and then Invoking back to the main thread is how we've done things for decades and by now should be a no-brainer.

    It's only a matter of time before i implement a new web request using Sockets and callbacks. (And C# async once they roll that out.)​

    Exceptions
    Ok this is probably my own fault for doing threads even though they discouraged it. I had a parallel program and i was getting tons of errors but not in the obvious places. I had an an Out Of Range exception when i accessed an array. Or actually i didn't, but after testing and debugging for hours i realized it, U3D had not thrown the error in the console and as such the threads just silently failed. This may be harder to fix but. It's a bug nonetheless.​


    Other

    Debug Gizmos
    Debug.DrawWireSphere()
    Debug.DrawWireCube()
    Debug.DrawMeshCube()
    Debug.DrawIcon()
    etc...

    I think it's not for fair that the best of the debugging utilities are locked away in OnDrawGizmos(). Copy these members into the Debug class too and make them static so we can access them anywhere. As usual i had to create yet another wrapper.

    You could implement it by either:
    1. Pass the message to the Gizmo class
    2. Build the lines using the Debug.DrawLine()​

    JSON
    In any JSON system out in the wild that is not U3D, commonly it is agreed that we use Properties not Fields.
    I get that the JSON serializer were built to work as an implementation of the existing system using the [Serializable] attribute. But Jesus it's inflexible. If i add a new complex field i always needed to set the attributes for every single data-model we had. And the collections? The way of using List<> and Dictionary<,> raw pain when you spell it out. The List and Dictionary classes does not have the [Serializable] attribute. So you would have to subclass it and add the attribute on that class.

    After working with the JSON system for a month or so i gave up. The need for a better serializer was so prevalent that i had to delay my project for a week developing a new object serializer/deserializer. Tons of others have done the same. It's not hard to make one and UT really did a shabby job on this.

    Det´ en ommer!​

    Multipart formdata
    Another one that did not follow the standard as usual and is causing problems on my webserver.

    According to the RFC1341 standard (Which i had study while trying to fix it)

    Section 7.2.1 states that the boundary is formatted like "--gc0p4Jq0M2Yt08jU534c0p\r\n" not length sensitive. But definitely does not contain an extra pair of "\r\n"

    if you briefly search the internet "unity3d multipart formdata boundary" you will find that I'm not the only one who came across this issue.

    the solution i used was building the boundary by myself and setting the header. Then using the UploadHandlerRaw class on the WWWForm.data. I can't remember why that worked since i made it about 8 months ago, but it's has been running without issues so far. Except from the threading of course.​

    Answers and Documentation that leads to packages
    This happens most frequently when working with Shaders but also happens when people reference example projects.
    When i look for an answer an i see someone says "Oh you can find this implementation in the Particles/Multiply in the Standard Shaders package" why not just paste the lines of code? Or even better link to an online Repo where i can read the code immediately, In the browser. Instead of referencing a package you can reference an online api like.
    code.unity.com/StandardShaders/Particles%2FMultiply?lineFrom=120&lineTo=140
    this would open a page where code is highlighed for me. Github already has this functionality.

    Although aside from that API there isn't much to be done here, it's entirely up to the community how they choose to articulate themselves.​

    Show in explorer
    Currently when you click "Show in Explorer" it will open the containing folder with the selected item highlighted.
    Well I'd like to add another condition. If the selection is a folder don't highlight it, Open it.​

    Console Exceptions
    Has this always been broken or is it just recently?
    I find my consoles errors is thrown somewhere in List.cs:457 or something. Code that is part of the framework. If you can't clean the shown stack in a performant at least let the double click search upwards in the stack until it hits user code.​

    Auto detect normal
    some sugar for the users.
    Normal maps have this distinct blue color.
    Well simply Average(pixes).B == ~127. Or vector lengths == ~1.
    It does require throughout analysis of the picture which is quite consuming in an already slow process.​

    Text Asset Preview
    Currently it uses 8 space tabs.
    Change to 4 spaces. Like VisualStudio and MonoDevelop.​

    And Lastly
    Code (CSharp):
    1. Mathf.Tau = Mathf.PI*2;
    Because why not?​



    All done! If you survived. Please come again!
    If you have any comments please share. Otherwise I'll just drift back into the shadows. Good luck in 2018.
     
  2. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    A lot of the issues you outline are somewhat alleviated by extension methods.
     
  3. CyberFox01

    CyberFox01

    Joined:
    Oct 5, 2012
    Posts:
    23
    Not "a lot of". Just the first one can be extension methods.
    Code (CSharp):
    1. gameObject.transform.position.AddZ(Time.deltaTime);
    Which i also have in my codebase. But it's just bandaid.