Lesson 23 - Static Fields and Methods

Tutorial Series: Introduction to Unity with C# Series

Previous Article  |  Next Article


Transcript

Now, before we wrap up everything that we've learned so far about Object-Oriented Programming to a nice bow and go into the Unity API, I want to touch on a few things to round out your understanding a bit better before we do that. The first thing I want to look at is how our classes have fields and methods that so far have been accessible only through our object instances. Right? We've had to always create an instance of our class in order to access, modify, read and write those fields or use those methods. There's actually a way to make a field or method so that it can be accessed without having to refer to an object. You don't even have to have an object instance. That is achieved by prefixing a field or method with the keyword "static". Let's show that with this example.

Going back to our Human class, let's just make this field static. Before the variable type, after the access modifier, I will put in "static", alright? When we mark this field as being static, we're saying that it doesn't belong exclusively to the object instance, but rather to the entire class itself. Let me illustrate this in action to give you an idea of what I mean by this. Going back to our AnimalFactory here, we will just get rid of the Debug here so we can focus on what we need to. Now let's try to access that Bipedal field of our person instance and what do you see? It's not there any longer. IntelliSense it doesn't even show it up even though it's a public field right? Still public so other classes should be able to see it. Well that's because it doesn't any longer belong to the instance, it belongs the class in general. Either Humans in general, not instances but in general, either Bipedal by nature or not. That's why we chose this as a static field. You access that static field by referring to the class itself. The type and then the dot accessor, and there you go. There's our public static field for Bipedal and you can assign it whatever you want, and that's how you make sense of statics.

So the obvious question is, when should you use a static field in general? Well you probably aren't going to use them that much when you write code specifically in Unity, in our Unity projects but you will come across statics in Unity's API pretty often. The rule of thumb is you use a static to designate where some value is shared across all instances. You can think of it that way. In the moment that you change that value, it changes it for all instances of that class. Again, that's the way you can think of it. Perhaps you're creating a simulation game, or a "god game" as they call it, and you want to do something like this. We can still use our Human class code here. As before, we had fields that did not belong to the class in general. That is, it wasn't shared across all instances. Let's give this human class again a Gender, right? Not everybody is of the same gender. Sorry string, and Age. Not everybody is the same age, so that's not going to be static. If we're creating a god game, right, and we want to manipulate some value that is shared across all Humans, if we imagine that condition, we may want to create something like this. public static bool FreeWill. I chose free will as a static here because it's an example where, regardless of its value, since it's a bool here it's either true or false, but regardless of if it's true or false, what's immediately clear is its value should be shared across all instances of Human. Either these Humans all have FreeWill or none of them have FreeWill.

When we switch that value, it switches it for all of them. They may all have these different Genders and Ages for each instance but fundamentally they share, as a part of their class definition, whether or not they have FreeWill. I don't want to get into a philosophical debate, this is just one example, but I thought it was maybe an instructive one. You can also prefix a method with a static keyword and you would need to do that when that method does some process that, say, changes a static field, a static field that it's referencing from the same class definition. For example, you can do something like this, have a method that references this static field FreeWill. Let's make static method, public static returns void,ChangeFreeWill(), and this will be a very simple line of code, FreeWill = !FreeWill although I would not necessarily read it that way. You can read it as FreeWill equals the opposite of FreeWill, alright? Whatever FreeWill is, if it's true it becomes false, if it's false it becomes true, as we went over with our bools and looking at the exclamation operator. Now admittently, this is a very contrived example. Let's assume there's a lot more stuff going on here in the method for ChangeFreeWill() just to justify its existence right?

Just to make a point, let's think about why it would necessary to have ChangeFreeWill() to be a static method. Would it make sense to access a static field shared by all instances that belonged to that class by going through any one instance of the class? Would it make sense to do something like this? Human Steven, just to use one example. We have our Steven object now. Would it make sense to access the FreeWill static bool that belongs to the entire class through Steven and we change that value by accessing the ChangeFreeWill() method, which we see within IntelliSense, it doesn't even let us do it. And it doesn't work obviously, because we set ChangeFreeWill() as a static method so it's not surprising, but just conceptually and intuitively it doesn't make sense to go through any one person: me, you, anyone to change a field that we all fundamentally share. That's why in method, in a class of that static field that we all share, a method that references that static field, shouldn't be able to be invoked from any individual. That's a conceptual way of understanding why we have to go through the class itself, so the method that references that static field has to be static itself. If you keep that in your head, this example, hopefully it will help make sense as you move along.

Since going through the instance, it doesn't make sense to modify that static field let's just do this properly and do it through the class itself. Human, hit the dot accessor and there's our method. In case you haven't noticed by now, the fields in Visual Studio have this little blue box to the left of it, and methods have the pink box, just so it helps you visually understand what you're looking at as you're using the dot accessor. We'll just access the ChangeFreeWill() method and just to show you how that works, although it's not terribly important right now, let's just output the value for FreeWill. Which we actually haven't set, so let's just set it first. Depending on your philosophical take on this matter, doesn't matter what we set it at but let's just say, false alright? Then we output that to Unity, we no longer need this code right now so I'm just going to comment it out. True. It just flips that FreeWill bool static value. Just so we keep that reference to what didn't work, I'll quickly write out again what we had before, and comment that out because it's just going to cause an error, and there we go.

I don't want you to worry too much about the details surrounding statics but I just want to clarify one point. In the example we looked at, we made the ChangeFreeWill() method static because it accesses a static field. Conceptually, this makes sense and maintains a certain consistency. However, it isn't strictly necessary. You could make the ChangeFreeWill() method non-static which would let you access the static field through the Steven instance in our example. It just doesn't make a lot of sense to do so. Of course, there are always edge cases in code where that actually might be useful but generally it's not useful. Technically it's okay for a non-static member to reference a static member or an instance member to reference a static member. On the other hand, what is strictly forbidden when it comes to working with statics is for a static member to reference an instance, or put another way a non-static member in its own class, for example. In other words, an instance member can reference a static member because the static member is always knowable to the instance because the instance knows the reference never changes, it will always be statically referencing the class. Whereas a static member can't access an instance member because the instance member is "unknowable" to the static member. This becomes a lot clearer when you ask, "How would this static method know whose "Age we're talking about here? "What instance does it belong to?" The static method has no way of knowing this so this reference is strictly not allowed.

Much of the time you make something static so you have a global reference point for all other classes that could find it useful to reference it frequently. For example, every one of our classes that have been making use of the static method Log() found in the Debug class, right? We've been using that all the time. One of the reasons why it's static is because we're just outputting information to the console. There's no real reason to make an instance every time we do so. That's just a lot of extra code and memory resources for what should be a very simple process that is useful to many classes across the board. That definition fits the Debug.Log() perfectly and that's why it's a static method. This might seem like, at this point, a lot to keep swimming in your head but really it will become second nature with time, as you get used to using these different tools available to you as you move along in coding. Right now, however, I want you to get the understanding of this entire object model, containment, access structure, and so on, mainly so that we can delve deeper into the Unity API. I'm not expecting you to have absolute mastery at this point, it's just dipping your toes into these concepts, just so that we can look at the Unity API, which is kind of opening up a giant toolbox, and knowing all this stuff I've been showing you about C#'s OOP nature, which hopefully makes a difference between understanding roughly what those tools are and how to use them and having no clue how to use them even to begin with.

Perhaps you've heard that saying, "To a hammer, everything looks like a nail"? Well in much the same way you can say, "To a person who doesn't understand tools "and toolbox everything looks like a hammer." If you get my drift. I think you're more or less prepared. I know you're more or less prepared at this point, to not look at everything as just being a hammer in code at this point. We'll go deeper into our actual Unity code and game logic by continuing our prototype and looking at the Unity API in the next few videos. I know that you're probably eager to go back to actual game development. I promise we'll be doing just that very soon. Thanks a lot.


Related Articles in this Tutorial:

Lesson 1 - Who This Course is For

Lesson 2 - What to Expect from this Course

Lesson 3 - Installation and Getting Started

Lesson 4 - Starting the First Project

Lesson 5 - Prototype Workflow

Lesson 6 - Basic Code Review

Lesson 7 - Game Loop Primer

Lesson 8 - Prototyping Continued

Lesson 9 - C# Fundamentals and Hello World

Lesson 10 - Variables and Operations

Lesson 11 - Variables and Operations Continued

Lesson 12 - Floats, Bools and Casting

Lesson 13 - If Statement Conditionals

Lesson 14 - If Statements Continued

Lesson 15 - Complex Evaluations and States

Lesson 16 - Code Syntax vs. Style

Lesson 17 - Variable Scope

Lesson 18 - Object-Oriented Programming Intro

Lesson 19 - OOP, Access Modifiers, Instantiation

Lesson 20 - Object Containment and Method Returns

Lesson 21 - "Has-A" Object Containment

Lesson 22 - "Is-A" Inheritance Containment

Lesson 23 - Static Fields and Methods

Lesson 24 - Method Inputs and Returns

Lesson 25 - Reference vs. Value Types

Lesson 26 - Introduction to Polymorphism

Lesson 27 - Navigating the Unity API

Lesson 28 - Applying What You've Learned and Refactoring

Lesson 29 - Constructors, Local Variables in the Update Method

Lesson 30 - Collecting Collectibles, Items and Powerups

Lesson 31 - Spawning and Managing Prefab Powerups

Lesson 32 - Implementing Powerup State Logic

Lesson 33 - Displaying Text, OnGUI, Method Overloading

Lesson 34 - Referencing Instantiated GameObjects, Parenting

Lesson 35 - Understanding the Lerp Method

Lesson 36 - Creating Pseudo Animations in Code

Lesson 37 - Understanding Generic Classes and Methods

Lesson 38 - Animations Using SpriteSheets and Animator

Lesson 39 - Working with Arrays and Loops

Lesson 40 - Debugging Unity Projects with Visual Studio

Lesson 41 - Camera Movement and LateUpdate

Lesson 42 - Playing Audio Clips

Lesson 43 - Routing Audio, Mixers and Effects

Lesson 44 - Adding Scoring Mechanics and Enhancements

Lesson 45 - Scene Loading and Game Over Manager

Lesson 46 - Understanding Properties

Lesson 47 - Controller Mapping and Input Manager

Lesson 48 - Understanding Enums

Lesson 49 - Dealing with Null References

Lesson 50 - Handling Variable Framerates with time.DeltaTime

Lesson 51 - Preparing the Project for Final Build

Lesson 52 - Final Build and Project Settings

Lesson 53 - Introduction to the Unity Physics Engine

Lesson 54 - Understanding FixedUpdate vs. Update

Lesson 55 - Movement Using Physics

Lesson 56 - Attack Script and Collision Events with OnCollisionEnter2D

Lesson 57 - Projectiles and Stomping Attack

Lesson 58 - Parallax Background and Scrolling Camera

Lesson 59 - Infinitely Tiling Background Sprites

Lesson 60 - OOP Enemy Classes

Lesson 61 - OOP Enemy Classes Continued

Lesson 62 - Trigger Colliders and Causing Damage

Lesson 63 - Multi-Dimensional Arrays and Procedural Platforms

Lesson 64 - Finishing Touches

Lesson 65 - Series Wrap


Comments

Please login or register to add a comment