Why Unity engine encapsulate everything?

Started by
5 comments, last by HappyCoder 7 years, 1 month ago

Is there any reason for Unity to encapsulate for example the x, y and z coordinates like this: gameObjectName.transform.position.x

and not just do this: gameObjectName.x or if you need the position in vector form that just do: gameObjectName.position

and another thing that I don't understand is why do I need to write GetComponent<componentName>() for every component that I need and not just gameObjectName.component

Any reason to make things for complicated?

Thank you in advance.

Advertisement
It's a combination of two things.

Your first example is a case where organization matters. Having a transform with a position is much more organized than keeping dozens of member variables on a single object.

The second example is where genericity has won out; in other words, in order to make things as general-purpose as possible, Unity has opted to take this route instead of other alternatives.

This is not really a situation where one approach is "right" and another is "wrong" - there are tradeoffs involved in both scenarios, and sometimes those are nice and sometimes they are pesky.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Besides what is mentioned above, I see it kind of as keeping "objects" as actual separate objects/classes. If you only have a .x .y .z for position, then you don't have a nice object. With an object, you can just use .position where it makes good sense. For example, if you want to get the distance between two such positions, you need the x, y, and z for both, and as separate variables that makes 6 arguments to a function, or 3 if the function were called comparing "this" object to another. But with everything all together in one object/class, you only need to send "position" to the function calls. This is also great because "position" is a Vector3. And Vector3 type variables are not only x, y, z values, but actual classes, with nice methods you can use.

About the second part, it is more for organization I think(not that Apoch is wrong, rather just adding on). If you have a hierarchy of parent/child classes, with some methods on the parent where it makes sense, then you start getting into a lot of the purpose of OOP. I'm no expert on the subject of course, but it makes sense. By having a nice Monobehavior object/class, Unity can suddenly be really powerful. Monobehavior includes the whole event system Unity is proud to have. It also internally includes the stuff needed to be used in the editor, for the whole component drag & drop system, etc... that is included in Monobehavior. Every class you make that is going to execute code(not just storage or similar) will be a child class of Monobehavior so that you can use all that Monobehavior has to offer.

*****

And my apologies there ApochPiQ. I accidently downrated your post there, and it doesn't let me get rid of that. That's my bad.



why do I need to write GetComponent<componentName>() for every component that I need and not just gameObjectName.component


Because you can create your own classes derived from MonoBehaviour and add those as components. Since fields and properties like gameObject.component have to be defined in the class, and C# does not let you add fields at runtime like some languages do, you would have to edit the GameObject source code to add any of your custom components (which would be a bad idea even if you could).

You can use extension methods, though I would not recommend it.

It's a combination of two things.

Your first example is a case where organization matters. Having a transform with a position is much more organized than keeping dozens of member variables on a single object.

The second example is where genericity has won out; in other words, in order to make things as general-purpose as possible, Unity has opted to take this route instead of other alternatives.

This is not really a situation where one approach is "right" and another is "wrong" - there are tradeoffs involved in both scenarios, and sometimes those are nice and sometimes they are pesky.

I can't see how having bunch of member variables in an object is unorganised, we don't see those variables but only when we want to call them, they are hidden.

Maybe you meant that it is a mess for the actual Unity engine creators, but they I think that the creators need to think more about the organisation of the developers.

Anyway, there is nothing I can do about it..

Thanks

and another thing that I don't understand is why do I need to write GetComponent() for every component that I need and not just gameObjectName.component

I'm not Unity user, so I will answer based on my understand of writting game engines.

That allows to test if an object has some component or not by using some sort of function "has_component()". Notice that Unity is strongly centered around the parent-child and subling-subling system.

Parent-child: the object need to test if the parent contains a component. Example: the global position of an object is affected by the parent's position, so the object, to get its global transform, needs to check if the parent contains the 'transform' component first.

Sibling-sibling: when one component is dependent on another, the component needs to check if the owner object contains that other component first. Example: shader component and mesh component.

How's that acomplished? Everything is in that list owned by the object is a "component", that contains information (maybe a string variable "type") about what is the type of the component. If I was to reproduce the same thing in C, I could just make an structure holding the string and a pointer to the actual data of the component:


struct ccomponent {
    char type[200];
    void *data;
    void (*on_update)(ccomponent *);
    void (*on_render)(ccomponent *);
}

struct cobject {
    char type[200];
    int parent_id;
    list/array *components;
...
}

As ApochPiQ said:

This is not really a situation where one approach is "right" and another is "wrong" - there are tradeoffs involved in both scenarios, and sometimes those are nice and sometimes they are pesky.

I've implemented the situation above before, and it has pros and cons. Wasn't suitable for my case, as to me having to search for parent/sibling components and comparing strings to identify their types was wasteful. However, the pro is the agnosticity regarding the type of the owner. With that system, I can access the 'transform' of a parent without knowing what's the type of the parent, just retrieving the 'transform' component.

The other approach (that is: without that system), update() and render() goes to the object, and not the component, and the "component" itself doesn't exist anymore, it's something like this:


struct cplayer {
    ctransform transform; ----or---- double x; double y;
    int life;
}

struct cobject {
    char type[200];
    void *data; ----> set to cplayer
    int parent_id;
    void (*on_update)(ccomponent *);
    void (*on_render)(ccomponent *);
...
}

Here, when I allocate a 'cobject', I will also allocate the 'cplayer' and assign 'void *data' to it, and I will also assign 'on_update()' and 'on_render()' that will deal with it. I don't need to parse a list/array of components anymore, since I have direct access (through a pointer) to the player variables. However, with that abstraction lost, I don't have access to a parent data UNLESS I write a code for each case: for each different type of parent.

Pros and cons.

I can't see how having bunch of member variables in an object is unorganised, we don't see those variables but only when we want to call them, they are hidden.
Maybe you meant that it is a mess for the actual Unity engine creators, but they I think that the creators need to think more about the organisation of the developers.
Anyway, there is nothing I can do about it..
Thanks


You could always add your own method extensions.


using UnityEngine;
namespace GameObjectExtension
{
    public static class TransformHelper
    {
        public static float getX(this GameObject target)
        {
            return target.transform.position.x;
        }

        public static float getY(this GameObject target)
        {
            return target.transform.position.y;
        }

        public static float getZ(this GameObject target)
        {
            return target.transform.position.z;
        }
    }
}
Then to use it

// top of the file
using GameObjectExtension;
...
var xPos = gameObject.getX();
More info here
https://msdn.microsoft.com/en-us//library/bb383977.aspx
My current game project Platform RPG

This topic is closed to new replies.

Advertisement