Hello! In our last session, we took a major step forward by writing your first C# scripts. You learned how to use variables, functions, and control flow to bring a simple square to life, moving it around the screen with your keyboard. Every script you've written so far has inherited from a special Unity class called MonoBehaviour, which is what allows it to be attached to a GameObject.
Today, we're going to expand on that foundation by exploring one of the most powerful concepts in programming: Object-Oriented Programming (OOP). Specifically, we'll focus on how to create your own custom classes. This will allow you to design reusable "blueprints" for the various elements of your game, like character stats, items, or abilities. Moving beyond a single script for everything is the key to managing the complexity of the RPG you want to build.
By the end of this lesson, you will be able to apply these principles to create your own data structures, making your code more organized, flexible, and easier to manage.
Why Custom Classes? The Factory Analogy
As your game grows, you'll find that putting all your logic into a single MonoBehaviour script becomes unmanageable. A character isn't just one thing; it's a combination of movement logic, stats, an inventory, health, and more. The core idea of OOP is to separate these different responsibilities into their own logical containers, or classes.
A great way to think about this comes from the video below. It proposes an analogy: if variables are boxes for data and functions are machines that process it, then classes are the factories that contain related groups of boxes and machines.
C# Classes in Unity! - Beginner Scripting Tutorial
This video from Unity's official channel introduces the role of classes in organizing your code. Pay close attention to the "single responsibility principle."
Watch the first part of the video on what classes are. The key takeaway is that we should aim to give each script a single, clear purpose. This makes our project easier to understand, debug, and expand.
Creating Your First Custom Class: A Blueprint for Stats
For your action-adventure RPG, characters will need statistics like strength, agility, and intelligence. Let's create a blueprint for a generic "stat."
- In your Unity project's
Projectwindow, create a new C# script namedStat. - Open the script. By default, Unity creates a
MonoBehaviourclass. We are going to change this. We want to create a simple data container, not a component that gets attached to a GameObject.
Modify the Stat.cs file so it looks like this:
// Notice this class does not have ": MonoBehaviour"
public class Stat
{
public int baseValue;
// We could add more fields later, like a list of modifiers from gear.
}
This is a plain C# class. It has no Start() or Update() methods and can't be attached to GameObjects. It's simply a blueprint that defines what a "Stat" is: in this case, something that has a baseValue.
Using Your Custom Class in a Component
Now, let's create a MonoBehaviour script that uses our new Stat class.
- Create another C# script named
CharacterStats. This one will be aMonoBehaviour. - Open
CharacterStats.csand add public variables of your newStattype.
using UnityEngine;
public class CharacterStats : MonoBehaviour
{
public Stat strength;
public Stat intelligence;
public Stat agility;
}
Now, let's see this in action.
- Create an empty GameObject in your scene and name it "Player".
- Attach the
CharacterStatscomponent to it.
Look at the Inspector window for the "Player" object. You'll see the CharacterStats component, but the strength, intelligence, and agility fields are nowhere to be found. Why is that?
[System.Serializable]: Making Your Classes Visible
By default, the Unity Inspector only knows how to display basic data types (like int, float, string) and references to other Unity Objects (like Transforms or Materials). It doesn't know how to draw our custom Stat class.
To fix this, we need to give Unity a hint using an attribute. An attribute is extra information you provide about your code, placed in square brackets [] right before a class or variable declaration.
Go back to your Stat.cs script and add the [System.Serializable] attribute above the class definition:
using System.Collections; // You may need to add this line if you get an error
using UnityEngine;
[System.Serializable] // This attribute tells Unity to show this class in the Inspector
public class Stat
{
public int baseValue;
}
Save the script and return to the Unity editor. Now, look at the Player GameObject's Inspector. You should see expandable fields for Strength, Intelligence, and Agility, each with a Base Value field you can edit directly! This is an incredibly powerful workflow for creating and tweaking game data.
Creating Objects with new and Constructors
While you can now set the baseValue in the editor, let's see how to work with these objects in code. If you tried to access strength.baseValue in the Start() method of CharacterStats, you would get an error called a NullReferenceException.
This is because we've defined the slots for our stats, but we haven't actually created the Stat objects to put in those slots yet. To create an instance of a class, we use the new keyword. This calls the class's constructor, a special method that initializes the new object.
C# Classes in Unity! - Beginner Scripting Tutorial
Let's return to the Unity video to see how to create instances of a class and how constructors work.
Watch the segment that demonstrates how to create an instance of a class, known as an object. Then, continue watching the explanation of constructors to understand how objects are initialized.
Let's apply this. In your CharacterStats.cs script, let's initialize these stats in the Awake() method (which runs even before Start()).
using UnityEngine;
public class CharacterStats : MonoBehaviour
{
public Stat strength;
public Stat intelligence;
public Stat agility;
void Awake()
{
// We create a new Stat object and assign it to our strength variable.
strength = new Stat();
strength.baseValue = 10;
intelligence = new Stat();
intelligence.baseValue = 12;
agility = new Stat();
agility.baseValue = 8;
Debug.Log("Character's Strength: " + strength.baseValue);
}
}
Now, if you press Play, you'll see the message "Character's Strength: 10" in your Console, and any values you set in the Inspector will be overwritten by this code.
Inheritance: Creating Specialized Blueprints
Now that we can create our own basic classes, let's explore another core OOP principle: inheritance. Inheritance allows a class (the "child" or "derived" class) to receive all the properties and methods of another class (the "parent" or "base" class). This is perfect for creating specialized versions of a general concept.
This creates an "is-a" relationship: A Sword is-a Weapon. A Goblin is-a Enemy.
C# Inheritance in Unity! - Intermediate Scripting Tutorial
This tutorial from Unity explains the concept of inheritance, which is fundamental to building scalable game systems.
First, watch the overview of what inheritance is. Then, skip ahead to the "animal kingdom" example, which illustrates the hierarchical structure and the "Is-A" relationship. Finally, see a practical gamedev example with Humanoid, Enemy, and Player classes.
Let's apply this to an RPG item system.
- Create a new C# script named
Item. Make it a[System.Serializable]class, not aMonoBehaviour. This will be our parent class.[System.Serializable] public class Item { public string itemName; public int value; } - Now, create a script named
Weapon. We'll make it a child ofItem.[System.Serializable] public class Weapon : Item // The colon indicates that Weapon inherits from Item { public int damage; } - Create one more,
Potion.[System.Serializable] public class Potion : Item { public int healthRestored; }
Because Weapon and Potion inherit from Item, they automatically get the itemName and value fields without us having to rewrite them. This is the power of code reuse.
You can see this pattern used frequently in Unity development. The image below shows a script SummonCreature1 that inherits from a custom SpellEffect class, demonstrating a specialized type of spell.

Conclusion
In this lesson, we've taken a significant step into the world of Object-Oriented Programming. You've moved beyond using only the MonoBehaviour class and have started designing your own custom class blueprints.
Here are the key takeaways:
- Classes are blueprints for objects, helping to organize your code according to the single responsibility principle.
- Not all classes need to be
MonoBehaviours; you can create simple C# classes to act as data containers or for other logic. - The
[System.Serializable]attribute is essential for making your custom classes visible and editable in the Unity Inspector. - You must create an instance of a class using the
newkeyword before you can use it. - Inheritance (
class Child : Parent) is a powerful tool for code reuse, allowing you to create specialized versions of base classes.
Next Steps
Now that you have a better understanding of how classes and objects are created, our next lesson will focus on when they are created and used within Unity's framework. We will take a closer look at the Unity Game Loop, diving into the order of execution for key methods like Awake(), Start(), and Update(). Understanding this sequence is vital for writing reliable code and managing the lifecycle of your game's objects.