All posts in "Clean Code"

SOLID Unity3D Code Architecture – The Open Closed Principal

Are you ready to start using the SOLID principals in your Unity3D Project?¬† Learn how the Open Closed Principal (the O in SOLID) can make your game easier to develop, extend, and maintain.¬† By using simple interfaces and separating out some code, we’ll convert a solution that’s destined for messiness into a clean and SOLID Unity3D project.

Video

What to Look Out For

  1. Adding new functionality requires you to modify your existing classes
  2. Your class is handling different inputs in different ways to the same method.
  3. You start to see if & else if statements cluttering your code.

Ways to Implement The Open Closed Principal in Unity

  • Have your classes act on interfaces, not discrete implementations
  • Use base classes and override their functionality
  • Add events to your class and have other components on the gameobject register for those events instead of the class calling them directly

 

Continue reading >
Share

Unity Coding Standards

Today, we’ll talk about Unity Coding Standards. ¬†We’ll cover things to do, things to avoid, and general tips to keep your projects clean, maintainable, and standardized.

Things to avoid

I want to prefix this by saying that the thoughts¬†in this post are guidelines and not meant to be a criticism of anyone. ¬†These are personal preferences and things I’ve picked up from experience across a variety of different projects.

If you find that you commonly do and use some of these things, don’t be offended, just try to be conscious of the issues that can arise. ¬†With that little disclaimer, here are some of the key things I always fight to avoid and recommend you do your best to limit.

Public Fields

I won’t go deep into this as I think I’ve already covered it here. ¬†Just know that public fields are generally a bad idea. ¬†They often tend to be a precursor to code that’s difficult to read and maintain.

If you need to access something publicly, make it a property with a public getter.  If you really need to set it from another class, make the setter public too, otherwise use a property that looks like this:

public string MyStringThatNeedsPublicReading { get; private set; }

Large Classes

I’ve seen far too many Unity projects with class sizes that are out of control. ¬†Now I want to clarify that¬†this is not¬†something only¬†specific to unity, I’ve seen classes over 40k lines long in some AAA game projects. ¬†I’ve seen .cs & .js files in web apps over 20k lines long.

That of course does not make them right or acceptable.

Large classes are hard to maintain, hard to read, and a nightmare to improve or extend.  They also always violate one of the most important principals in Object Oriented Programming.  The principal of Single Responsibility.

As a general rule I try to keep an average class under¬†100 lines long. ¬†Some need to be a bit longer, there are always exceptions to the rules. ¬†Once they start approaching 300 lines though, it’s generally time to refactor. ¬†That may at first seem a bit crazy, but it’s a whole lot easier to clean up your classes when they’re 300 lines long than when they reach 1000 or more. ¬†So if you hit this point, start thinking about what your class is doing.

Is it handling character movement?  Is it also handling audio?  Is it dealing with collisions or physics?

Can you split these things into smaller components? ¬†If so, you should do it right away, while it’s easy.

Large MethodsCoding Standards - too long list

Large classes are bad.  Large methods are the kiss of death.

A simple rule of thumb: if your method can’t fit on your screen, it’s too long. ¬†An ideal method length for me is 6-10 lines. ¬†In that size it’s generally doing one¬†thing. ¬†If the method grows far beyond that, it’s probably doing too much.

Some times, as in the example below, that one thing is executing other methods that complete the one bigger thing.  Make use of the Extract Method refactoring, if your method grows too long, extract the parts that are doing different things into separate methods.

Example

Take this Fire() method for example.  Without following any standards, it could easily have grown to this:

Original

protected virtual void Fire()
{
	if (_animation != null && _animation.GetClip("Fire") != null)
		_animation.Play("Fire");

	var muzzlePoint = NextMuzzlePoint();
	if (_muzzleFlashes.Length > 0)
	{
		var muzzleFlash = _muzzleFlashes[UnityEngine.Random.Range(0, _muzzleFlashes.Length)];

		if (_muzzleFlashOverridePoint != null)
			muzzlePoint = _muzzleFlashOverridePoint;

		GameObject spawnedFlash = Instantiate(muzzleFlash, muzzlePoint.position, muzzlePoint.rotation) as GameObject;
	}

	if (_fireAudioSource != null)
		_fireAudioSource.Play();

	StartCoroutine(EjectShell(0f));

	if (OnFired != null) OnFired();

	if (OnReady != null)
		OnReady();

	var clip = _animation.GetClip("Ready");
	if (clip != null)
	{
		_animation.Play("Ready");
		_isReady = false;
		StartCoroutine(BecomeReadyAfterSeconds(clip.length));
	}

	_currentAmmoInClip--;
	if (OnAmmoChanged != null)
		OnAmmoChanged(_currentAmmoInClip, _currentAmmoNotInClip);

	RaycastHit hitInfo;

	Ray ray = new Ray(muzzlePoint.position, muzzlePoint.forward);
	Debug.DrawRay(muzzlePoint.position, muzzlePoint.forward);

	if (TryHitCharacterHeads(ray))
		return;

	if (TryHitCharacterBodies(ray))
		return;

	if (OnMiss != null) OnMiss();

	if (_bulletPrefab != null)
	{
		if (_muzzleFlashOverridePoint != null)
			muzzlePoint = _muzzleFlashOverridePoint;
		Instantiate(_bulletPrefab, muzzlePoint.position, muzzlePoint.rotation);
	}
}

This method is handling firing of weapons for an actual game. ¬†If you read over it, you’ll see it’s doing a large # of things to make weapon firing work. ¬†You’ll also notice that it’s not the easiest thing to follow along. ¬†As far as long methods go, this one is far from the worst, but I didn’t want to go overboard with the example.

Even so, it can be vastly improved with a few simple refactorings.  By pulling out the key components into separate methods, and naming those methods well, we can make the Fire() functionality a whole lot easier to read and maintain.

Refactored

    protected virtual void Fire()
	{
		PlayAnimation();

		var muzzlePoint = NextMuzzlePoint();
		SpawnMuzzleFlash(muzzlePoint);

		PlayFireAudioClip();
		StartCoroutine(EjectShell(0f));

		if (OnFired != null) OnFired();
		HandleWeaponReady();

		RemoveAmmo();

		if (TryHitCharacters(muzzlePoint))
			return;

		if (OnMiss != null) OnMiss();

		LaunchBulletAndTrail();
	}

With the refactored example, a new programmer just looking at the code should be able to quickly determine what’s going on. ¬†Each part calls a method named for what it does, and each of those methods is under 5 lines long, so it’s easy to tell how they work. ¬†Given the choice between the 2 examples, I’d recommend #2 every time, and I hope you’d agree.

CasingCasing

The last thing I want to cover in this post is casing. ¬†I’ve noticed in many projects I come across, casing is a mess. ¬†Occasionally, project I see have some kind of standard they’ve picked and stuck to.¬† Much of the time though,¬†it’s all over the place with no consistency.

The most important part here is to be consistent.  If you go with some non-standard casing selection, at least be consistent with your non-standard choice.

What I’m going to recommend here though is a typical set of¬†C# standards that you’ll see across¬†most professional projects in gaming, business, and web development.

Classes

Casing: Pascal Case

public class MyClass : MonoBehaviour { }

Methods

Casing: Pascal Case (No Underscores unless it’s a Unit Test)

private void HandleWeaponReady()

Private Fields

Coding Standards - Private FieldCasing: camelCase Рwith optional underscore prefix

// Either
private int maxAmmo;
// OR my prefered
private int _maxAmmo;

This is one of the few areas where I feel some flexibility.  There are differing camps on the exact naming convention to be used here.

Personally, I prefer the underscore since it provides an obvious distinction between class level fields and variables defined in the scope of a method.

Either is completely acceptable though.  But when you pick one for a project, stick with it.

Public Fields

It’s a trick, there shouldn’t be any! ūüėČ

Public Properties

Casing: Pascal Case

public int ReaminingAmmoInClip { get; private set; }

These should also be Automatic Properties whenever possible. ¬†There’s no need for a backing field like some other languages use.

Again you¬†should also mark the setter as private unless there’s a really good reason to set them outside the class.

 

Wrap Up

Again, this is just a short list of a few things that I think are really important and beneficial for your projects. ¬†If you¬†find this info useful, drop in a comment and I’ll work to expand out the list. ¬†If you have your own recommendations and guidelines, add those as well so everyone can learn and grow.
Thanks, and happy coding!

Continue reading >
Share

Dependency Injection and Unit Testing Unity

This post will be the first in what will likely be a long series. Dependency Injection and Unit Testing are generally considered staples in modern software development. Game development for a variety of reasons is one of the few areas where this isn’t true. While it’s starting to become more popular, there are quite a few things holding back game programmers from embracing these valuable paradigms.

I’d like to open by giving a quick description of the benefits you’ll gain by embracing dependency injection. ¬†Before you jump away thinking “I don’t need this” or “this will be too complicated”, just take a look at what you have to gain. ¬†And let me try to quell any fears, this is something you can definitely take advantage of, it won’t be hard, it’ll save you time, and your code will be improved.

 

Benefits – What do I have to gain?

Loose Coupling

Dependency Injection by it’s nature encourages very loose coupling. ¬†This means your objects and classes don’t have tight dependencies on other classes. ¬†Loose coupling leads to having code that is much¬†less rigid¬†and brittle.

Re-usbility Across Projects

Loose coupling also makes your classes much easier to use across projects. ¬†When your code has dependencies on¬†many other classes or static global variables, it’s much harder to re-use that code in other projects. ¬†Once you get into the habit of good separation and dependency injection, you’ll find that reuse becomes a near trivial task.

Encourages Coding to Interfaces

While you can certainly code to interfaces without Dependency Injection, using it will naturally encourage this behavior.  The benefits of this will become a bit more obvious in the example below, but it essentially allows you to swap behavior and systems in a clean way.

Cleaner Code

When you start injecting your dependencies, you quickly end up with less “spaghetti-code”. ¬†It becomes much clearer what a classes job is, and how the class interacts with the rest of your project. ¬†You’ll find that you no-longer have to worry about a minor change in one piece of code having an unexpected consequence in something that you thought would be completely unrelated.

As an example, once while working on a major AAA MMO game, I saw a bug fix to a specific class ability completely break the entire crafting system.  This exactly the kind of thing we want to avoid.

Unit Testing

This is one of the most commonly stated benefits to Dependency Injection. ¬†While it’s a huge benefit,¬†you can see above that it’s not the only one. ¬†Even if you don’t plan to unit test initially (though you should), ¬†don’t rule out dependency injection.

If you haven’t experienced a well unit tested project before, let me just say that it’s career changing. ¬†A well tested project is less likely to slip on deadlines, ship with bugs, or fail completely. ¬†When your project is under test, there’s no fear when you want to make a change, because you know immediately when something is broken. ¬†You no-longer need to run through your entire game loop to verify that your changes work, and more importantly that you haven’t broken other functionality.

 

 

If it’s so good, why isn’t this common place?

Now,¬†I’d like to cover a few of the reasons the game industry has been slow to adopt Dependency Injection & Unit Testing.

C++

While this doesn’t apply to Unity specifically, the game industry as a whole has primarily relied on C++. There were of course studios that developed in other languages, but to this date, outside of Unity, the major engines are all C++ based. C++ has not had nearly the same movement towards Dependency Injection or Unit Testing as other common enterprise languages (Java, C#, JS, Ruby, etc). ¬†This is changing though, and with the proliferation of unit testing and dependency injection in C#, it’s the perfect¬†time to jump in with your games.

Performance

Dependency Injection adds overhead to your game. In the past, that overhead could be too much for the hardware to handle.  Given the option between 60fps and dependency injection, 60fps is almost always the correct answer.  Now though, hardware is really fast, and 99% of games can easily support Injection without giving up any performance.

Mindset

While there are countless other “reasons” you could come across from game programmers, the key one is just an issue of mindset. ¬†Too many people have been programming without Injection and Unit testing and just haven’t been exposed to the benefits. ¬†They think “that’s for enterprise software”, “that’s something web developers do”, or “that doesn’t work for games”. ¬†My goal here is to convince you¬†that it’s worth trying. ¬†I promise if you dig in and try dependency injection and unit testing, you’ll quickly start to see the benefits, and you’ll want to spread the word as well.

 

Dependency Injection Frameworks

When you’re searching, you may also see the DI frameworks referred to as IOC containers.

You may be wondering how you get started with Dependency Injection in Unity. ¬†It’s not something built into¬†the Unity engine, but there are a variety of options to choose from on GitHub and in the Asset Store.

Personally, I’ve been using Zenject, and my samples will be done using it. ¬†But that doesn’t mean you shouldn’t look into the other options available.

Zenject

I think the description provided on the Zenject asset page does a better job describing it than I could, so here it is:

Zenject is a lightweight dependency injection framework built specifically to target Unity. It can be used to turn the code base of your Unity application into a collection of loosely-coupled parts with highly segmented responsibilities. Zenject can then glue the parts together in many different configurations to allow you to easily write, re-use, refactor and test your code in a scalable and extremely flexible way.

While I hope that after reading this series you have a good idea why you should use a dependency injection framework, and how to get started, I must highly recommend you take a look at the documentation provided on the Zenject GitHub page.

Constructor Injection

Most Dependency Injection is done via what’s called Constructor Injection. ¬†This means that anything your class relies on outside itself is passed in via the constructor.

Example

I want to give an example of how you’d use Constructor Injection in a more general sense before diving too deep into the differences with Unity. ¬†What I’m presenting here is a simplified version of a game state system I’m using in a Unity project currently.

In my project, I have a variety of game state classes.¬†¬†The different “GameStates” handle how the game functions at different stages throughout the game cycle. ¬†There are game states for things like generating terrain, lost/gameover, building, attacking, and in this example, ready to start.

In the game state “ready to start“, all we want to do is wait for the user to start the game. ¬†The game state doesn’t care how the user starts the game, only that they do. ¬†The simplest way to implement this would be to check on every update and see if the user pressed the “Fire1” button.

It may look something like this:

using UnityEngine;

public class GameStateReadyToStart : MonoBehaviour
{
    void Update()
	{
		if (Input.GetButton("Fire1"))
			SwitchToNextGameState();
	}

	private void SwitchToNextGameState()
	{
		// Logic to go to next gamestate here
	}
}

This will work, it’s simple, and quick to implement, but there are some issues with it.

 

Problems

  • Our gamestate is a monobehaviour so we can read the input during the update.
  • The Input logic is inside a class who’s job isn’t Input. ¬†The gamestate should handle game state/flow, not input.
  • Changing our input logic requires us to touch the gamestate class.
  • We’ll have to add input logic to every other gamestate.
  • Input can’t be easily varied across different devices. ¬†If we want a touch button on iPad and the A button on an xbox, we have to make bigger changes to our gamestate class.
  • We can’t write unit tests against our gamestate because we can’t trigger input button presses.

You may be thinking that’s a long list, but I guarantee there are more problems than just those.

Why not just use a Singleton?

The first answer you may come across to some of these problems is the Singleton pattern.
While it’s very popular, simple, and resolves half¬†of our issues, it doesn’t fix the rest.
Because of that, outside the game development world, the singleton pattern is generally considered bad practice and is often referred to as an anti-pattern.

 

Let’s try some separation

Now, let me show you an easy way to resolve all of the problems above.

public class GameStateReadyToStart
{
    public GameStateReadyToStart(IHandleInput inputHandler)
	{
		inputHandler.OnContinue += () =>
		{
			SwitchToNextGameState();
		};
	}

	private void SwitchToNextGameState()
	{
		// Logic to go to next gamestate here
	}
}

Here, you can see we’ve moved input handling out of the “gamestate” object into it’s own “inputHandler” class. ¬†Instead of reading input in an update loop, we simply wait for the InputHandler to tell us¬†when¬†the user is ready to continue. ¬†The gamestate doesn’t care how the user tells us to continue. ¬†All the gamestate cares about is that the user told it to switch¬†to the next state. ¬†It’s now properly separated and doing only what it should do, nothing more.

The “IHandleInput” interface for this example is very simple:

using System;

public interface IHandleInput
{
    Action OnContinue { get; set; }
}

Now, if we want to switch input types across devices, we simply write different implementations of the “IHandleInput¬†interface.
We could for example have implementations like:

  • TouchInputHandler – Continues when the user presses anything bound to “Fire1
  • GUIBasedInputHandler – Continues when the user clicks a GUI button
  • VoiceInputHandler – Continues when the user says a phrase
  • NetworkInputHandler – Continues when the user presses something on another device (think controlling a PC game with a phone)
  • TestInputHandler – Continues via a unit test designed to verify state switching doesn’t break

 

Time to Inject!

Now without going too much deeper into my example, you may be thinking “that’s nice, but now I have to pass in an input handler and manage that”.

This is where dependency injection comes into play. ¬†Instead of creating your handler and passing it into the constructor, what we’ll do is Register the handler(s) we want with our Dependency Injection Container.

To do that, we need to create a new class that derives from the Zenject class “MonoInstaller

using System;
using UnityEngine;
using Zenject;
using Zenject.Commands;

public class TouchGameInstaller : MonoInstaller
{
    public override void InstallBindings()
	{
		Container.Bind<IHandleInput>().ToTransient<TouchInputHandler>();
		Container.Bind<GameStateReadyToStart>().ToTransient<GameStateReadyToStart>();

		Container.Resolve<GameStateReadyToStart>();
	}
}

In the TouchGameInstaller class, we override InstallBindings and register our 2 classes.

Line 13 simply asks the container for an instance of the game state.

This is a very simplified version of the Installer with a single game state, later parts of this series will show how we handle multiple game states.

What we’ve done here though is avoid having to manage the life and dependencies of our “gamestate” class.
The Dependency Injection Container will inspect our classes and realize that the “GameStateReadyToStart” class has a dependency on an “IHandleInput“, because the constructor has it as a parameter.
It will then look at it’s bindings and find that “IHandleInput” is bound to “TouchInputHandler“, so it will instantiate a “TouchInputHandler” and pass it into our “gamestateautomatically.

Now, if we want to switch our implementations on different devices, we simply switch our our “TouchGameInstaller” with a new installer for the device and make no changes to our GameState classes or any existing InputHandler classes. ¬†We no longer risk breaking anything existing when we want to add a new platform. ¬†And we can now¬†hook up our GameState to unit tests by using an Installer that registers a TestInputHandler.

 

You may realize that I haven’t injected any gameobjects yet, and could be wondering how this works with monobehaviors that can’t constructors.

In the next part of this series, I’ll explain how to hook up your gameobjects and monobehaviors with the dependency injection¬†framework and continue the example showing how the entire thing interacts.

 

 

Continue reading >
Share

Editing Unity variables – Encapsulation & [SerializeField]

Editing Unity script variables in the Inspector – The case for Encapsulation & [SerializeField]

If you’ve read many Unity tutorials, you may already know that it’s very easy to edit your script¬†fields in the Unity inspector.

Most Unity tutorials (including on the official page) tell you that if you have a MonoBehaviour attached to a GameObject, any public field can be edited.

While that does technically work, I want to explain why it’s not the best way to setup your scripts, and offer an alternative that I think will help you in the future.

In this article, you’ll learn how to use proper Encapsulation while still taking full advantage of the Unity Inspector.

Take a look at this “Car.cs” script.

 

using UnityEngine;

public class Car : MonoBehaviour
{
    public Tire FrontTires;
	public Tire RearTires;

	public Tire FrontRightTire;
	public Tire FrontLeftTire;
	public Tire RearRightTire;
	public Tire RearLeftTire;

	private void Start()
	{
		// Instantiate Tires
		FrontRightTire = Instantiate(FrontTires);
		FrontLeftTire = Instantiate(FrontTires);

		RearRightTire = Instantiate(RearTires);
		RearLeftTire = Instantiate(RearTires);
	}
}

 

If you look at the Start method, you can tell that the fields “FrontTires” & “RearTires” are referring to prefabs that will be be used to instantiate the 4 tires of the car.

Once we’ve assigned some Tire prefabs, it looks like this in the Inspector.

In¬†play mode, the Start method will instantiate the 4 actual tires on our car and it’ll look like this.


 

Problem #1 – Confusion

The first thing you might realize is that there could be some confusion about which fields to assign the prefab to.
You’ve just seen the code, or in your own projects, perhaps you’ve just written it, and it may seem like a non-issue.

But if your project ever grows, it’s likely others will need to figure out the difference, and to do so, they’ll need to look at the code too.
If your project lasts more than a few days/weeks, you also may forget and have to look back through the code.

Now you could solve this with special naming. ¬†I’ve seen plenty projects where the “Prefab” fields had¬†a prefix or suffix like “Front Tires Prefab”.

That can also work, but then you still have 4 extra fields in there that you have to read every time.  And remember, this is a simple example, your real classes could have dozens of these fields.

Fix #1 – Let’s Use Properties for anything public

To resolve this, let’s change the entries we don’t want to be editable into Properties.

Microsoft recommends you make your fields all private and use properties for anything that is public.  There are plenty of benefits not described in this article, so feel free to read in detail from Microsofts article Fields(C# Programming Guide)

Now let’s change the “Car.cs” script to match this.
using UnityEngine;

public class Car : MonoBehaviour
{
    public Tire FrontTires;
	public Tire RearTires;

	public Tire FrontRightTire { get; set; }
	public Tire FrontLeftTire { get; set; }
	public Tire RearRightTire { get; set; }
	public Tire RearLeftTire { get; set; }

	private void Start()
	{
		// Instantiate Tires
		FrontRightTire = Instantiate(FrontTires);
		FrontLeftTire = Instantiate(FrontTires);

		RearRightTire = Instantiate(RearTires);
		RearLeftTire = Instantiate(RearTires);
	}
}

Here’s what it looks like in the Inspector

With that change, you may be thinking we’ve resolved the issue and everything is good now.
While it’s true that confusion in the editor is all cleared up, we still have one more problem to address.
That problem is lack of Encapsulation.

 


Problem #2 – No Encapsulation

“In general, encapsulation is one of the four fundamentals of OOP (object-oriented programming). Encapsulation refers to the bundling of data with the methods that operate on that data.”

There are countless articles and books available describing the benefits of encapsulation.

The key thing to know is that properly encapsulated classes only expose what’s needed to make them operate properly.

That means we don’t expose every property, field, or method as public.
Instead, we only expose the specific ones we want to be accessed by other classes, and we try to keep them to the bare minimum required.

Why?

We do this so that our classes/objects are easy to interact with.  We want to minimize confusion and eliminate the ability to use the classes in an improper way.

You may be wondering why you should care if things are public.  Afterall, public things are easy to get to, and you know what you want to get to and will ignore the rest.
But remember, current you will not be the only one working on your classes.

If your project lasts beyond a weekend, you need to think about:

  • other people – make it hard for them to misuse your classes.
  • and just as important, there’s¬†future you.

Unless you have a perfect memory, good coding practices will help you in the future when you’re interacting with classes you wrote weeks or months ago.

 


Problem #2 – The Example

Let’s look at this “Wall” script now to get an idea of why proper encapsulation is so important.

using UnityEngine;

public class Wall : MonoBehaviour
{
    public void Update()
	{
		if (Input.GetButtonDown("Fire1"))
			DamageCar(FindObjectOfType<Car>());
	}
	public void DamageCar(Car car)
	{
		car.FrontTires.Tread -= 1;
		car.RearTires.Tread -= 1;
	}
}

The “DamageCar” method is¬†supposed to damage all of the wheels on the car by reducing their Tread value by 1.

Do you see what’s wrong here?

If we look back to the “Car.cs” script, “FrontTires” & “RearTires”¬†are actually the prefabs, not the instantiated tires the car should be using.

In this case, if we execute the method, we’re not only failing to properly damage our tires, we’re actually modifying the prefab values.

This is an easy mistake to make, because our prefab fields that we we shouldn’t be interacting with aren’t properly encapsulated.

Problem #2 – How do we fix it?

If we make¬†the “FrontTires” & “RearTiresprivate, we won’t be able to edit them in the inspector… and we want to edit them in the inspector.

Luckily, Unity developers knew this would be a need and gave us the ability to flag our private fields as editable in the inspector.

[SerializeField]

Adding the [SerializeField] attribute before private fields makes them appear in the Inspector the same way a public field does, but allows us to keep the fields properly encapsulated.

Take a look at the updated car script

using UnityEngine;

public class Car : MonoBehaviour
{
    [SerializeField]
	private Tire _frontTires;
	[SerializeField]
	private Tire _rearTires;

	public Tire FrontRightTire { get; set; }
	public Tire FrontLeftTire { get; set; }
	public Tire RearRightTire { get; set; }
	public Tire RearLeftTire { get; set; }

	private void Start()
	{
		// Instantiate Tires
		FrontRightTire = Instantiate(_frontTires);
		FrontLeftTire = Instantiate(_frontTires);

		RearRightTire = Instantiate(_rearTires);
		RearLeftTire = Instantiate(_rearTires);
	}
}

Here you see we no-longer expose the “FrontTires” and “RearTires” fields outside of our class (by marking them private).

In the inspector, we still see them available to be assigned to.

Now our problems are solved and our class is properly encapsulated!

You may also notice that the casing on them has been changed. ¬†While this is not required to properly encapsulate your objects, it is very common practice in the C# community to denote private fields with camel case prefixed by an underscore. ¬†If you don’t like the underscore, consider at least using camel casing for your private fields and reserve pascal casing for public properties.

Video Version

Project Download

Want the source for this project to try it out yourself? Here it is: https://unity3dcollege.blob.core.windows.net/site/Downloads/Encapsulation%20SerializeField.zip

Continue reading >
Share