Is Unity (slightly) discouraging for standard OOP?

Hi,

I have very limited knowledge of OOP but I feel that the way Unity is built is not fully compatible with what I learnt about the OOP paradigm.

For instance, I feel it is the right thing to have a manager gameobject so that every class that wants to mess with my player’s properties must must call the manager.playerscript.setSomeValues() rather than manipulating the player’s public fields directly. Player values should instead be private and revealed only through public get and set routines that I provide. Same with the camera: For example, if the player OnTriggerEnters a certain collider, I want the camera to move back a bit or change its target, and I should do so by calling manager.camerascript.setCameraOffset(-20f) or something like that rather than by manipulating the camera script’s public offset property.

When I try to apply this to Unity, I feel it does not encourage this approach. Inspector variables must be public whereas in my description they should be private and only modified by methods.

Am I getting this wrong? Please help me correct my view so I can align better with Unity’s view.

What you see as public properties are actually getters and setters that are methods and that is fully in accord with OOP. I actually found that Unity is very good at helping me build OOP structures (using inheritance, interfaces, etc…) and following all the main principles of OOP.

I wouldn’t say OOP is discouraged or less-supported in Unity. My belief is that OOP creates structure and saves the programmer’s time on coding and Unity doesn’t hinder these values.

I see the public variables/properties as a great way to allow designers to edit values without going through the code. I am working on a 2D endless runner with custom physics and most of my values are public so my designer can get the feel of the game correct. I can always make these variables private after they have been perfected.

Unity has a Component-Object Model implemented which can divert your attention from OOP practices but there’s nothing stopping you from going full OOP with C#.

False. Here is how you should be using them:

[SerializeField] bool variableName;
public bool VariableName { 
  get { return variableName; }
  set { variableName = value; }
}

Sounds complicated. I think it’s generally a much better practice to raise events that provide the data you need, and work with that data, instead of calling public methods of other classes. It’s easy to make spaghetti code when you’re manipulating other objects instead of having each of them react individually.

In the Player class:

public static event Action ImportantThingHappened;

void OnTriggerEnter(Collider otherCollider) {
   if (otherCollider == theOneThatMatters)
      ImportantThingHappened();
}

In the YourGameNamespace.Camera class:

Player.ImportantThingHappened += () => SetOffset(-20f);

setCameraOffset(-20f) is a method and therefore should not be in camelCase in Unity’s langauges, but I don’t think it’s good encapsulation to have the word Camera in there. The Camera should be offsetting itself.

Again, I think all of the main confusion coming from Instability assuming that a code like:

transform.position = new Vector3(0,0,0);

actually directly accesses a public property of the class. That may or may not be true (probably not true :slight_smile: ). Using a setter here is exactly equivalent to using something like SetPosition(Vector3 pos) and fully “approved” and supported by OOP principals.

Thank you, you nailed it, this is my confusion! Let’s say the setup is

public class playerScript: MonoBehaviour
{

    public float maxSpeed;

public void setMaxSpeed(float value) { maxSpeed = value; }
}
public class enemy : MonoBehaviour
{
void Awake()
{
Gameobject player = Gameobject.Find("Player");
playerScript ps = player.GetComponent<playerScript>();
playerScript.maxSpeed = 20.0f;
}
}

My confusion is that this is changing a public property! I would prefer maxSpeed were private and changing this private field would be done through setMaxSpeed. But that is clearly not the best thing to do because then maxSpeed would not appear in the inspector.

No. Standalone Set and Get methods are obsolete except when you have to write an extension method. If it’s your own code, use a property like I showed you. (Except, don’t actually do it in this case. You probably don’t even need to allow modification of the private field through a public property; the enemy should not be modifying the speed of the player. The player should change its own speed based on something that the enemy does, if necessary.)

You’re using camelCase for everything. Use PascalCase for classes, methods, properties, and events.

Try to do this the way Jessy recommends (and is the right way to do this - no doubt):

    [SerializeField] float maxSpeed;
    public float MaxSpeed {
      get { return maxSpeed; }
      set { maxSpeed = value; }
    }

As you can see there is a get and set methods (getter and setter - standard in all latest OOP implementations to implement properties). So when you do something like (sorry if you already aware of it):

 MaxSpeed = 123.44f;

you are in actuality calling a set method of the MaxSpeed property and you can do anything you want in that set method besides just setting maxSpeed attribute. Hope this helps.

Jessy, I apologize, but as far as using camelCase or PascalCase, I think it is a matter of personal preferences. as someone who has > 18 years of industry programming experience I’m a bit set in a ways I write my code :). I actually, use “its” prefix for all attributes of a class and i use camelCase for all the methods. I know that goes against Unity convention but it is definitely not against industry convention since industry convention is actually a set of various conventions and people choose what suits them the best. Just IMO.

Unity actually doesn’t do a great job of following convention, because they use camelCase for properties and fields. In some cases, not following convention will stop you from being able to use language features. Search for “must follow” here. Otherwise, you at least confuse other people reading your code. Coding style is not something you take with you across languages.

I don’t know what that means.

I challenge you to find well-received Stack Overflow posts that do that in C#.

People like you make me sick >=/
How do you live with yourself?..

Jessy, I agree that sometimes person stile needs to change when switching from language to language (my personal journey :slight_smile: - C → C++ → VB → C# → Java with a wjhole bunch of other stuff in between) but it is not as dire as you make it sound - the general approach remains the same and can stay mostly the same (specially in OOP languages). I guess we will have to agree to disagree here :).

When I add “its” to all my class attributes (non-static once) they look like this for example:

class MyClass
{
private float itsMaxSpeed;
}

That lets me very easily see from a first glance when attributes are used versus locals. This used to be pretty common approach. Haven’t seen people doing it in a while. Call me an “old coot” :).

when I put code in this forum I don’t do this of course.

Haha, I have to admit, this makes me faintly ill when I think about it.

I personally have never come across any real life practical reason why Its “good OOP” to not access a public field but rather create a private one and have a public Getter Setter property change it for me. Its a very Dogmatic approach… do you really need to encapsulate every single thing possible?

I have created many public fields and accessed them over the years and guess what - it worked just the same.

And NO , I dont have spaghetti code , I understand composition over inheritance , coding towards an interface not an implementation , separation of concerns , design patterns etc… Its good to learn about OOP principles … but Nothing is absolute Law , they are just guidelines/concepts.

If you are planning on developing code Libraries for other people to use then yes I guess having a very purposed public Property(getter/setter) or method API is important.

Bare in mind that OOP is not the only programming paradigm that exists in this world. As a previous post mentioned you can also benefit from learning about component orientated architectures.

From what I see these days online the new “in thing” is to get into doing the whole functional programming paradigm thing now :wink:

I’d like to learn about object oriented programming in Unity.

I don’t start with public setters. Properties allow you to have a public getter and private/protected setter. If the setter ends up having to graduate to public (which is rare), then I’m not going to bother converting it back to a field.

Ok

God what is it X.x

Seriously though…I use property setters and getters when it’s JUST setting or retrieving a value from a private member variable or such.

But, if I actually need something to happen, like several lines of code, I treat it as a method instead. Like…SetColor(Color.White), where it may retrieve the material and set the color.

I can think of some good reasons: Logging. When other classes set public field values or access them, you have to have logging in each of those classes. If you put a getter/setter around it and only go through that, you can insert logging.
Getters and setters also give you a way to better control access. You can allow public reading from other classes, but only private setting. Or none :slight_smile:
So…I generally try to stay away from public fields. But it’s more of a guideline for me than a rule :wink:

To me, this is most important why trying to debug stuff running in Unity. Is Visual Studio, you can always plop down a breakpoint. But once it is running under Unity, debugging becomes crucial. I guess to me it’s about locking stuff down, instead of leaving as a guessing game. Sometimes…I really want to know that the only thing setting a value in my class is the class itself, and not some other guy. With public fields…you have to scan all code that accesses, and see who is setting something.
To me, knowing for sure is a big benefit when trying to debug your scripts in Unity.

Only for serialized fields, which are the minority.