Does anyone have suggestions regarding best practices for object oriented design in Unity? I’ve been trying to incorporate this as my projects get larger, but I’m having a difficult time resolving OOP with Unity’s built-in structure.
For example, how can I associate Game Objects with classes? Should I create classes which extend GameObject? With Unity, it’s tempting to use GameObjects, rather than classes, as the basic structural elements, and to add script components to them as needed. However, the becomes confusing as projects become more complex.
I’ve been experimenting, and I’ve been able to create a class with a constructor which creates a primitive game object, and contains a link to it. However, the script does not then become a component of the game object. You can see my confusion.
Does anyone have any thoughts on using OOP with Unity?
Every Unity script, whether you use JS, C# or Boo, is a class, so in essence every Unity application is Object Oriented.
In your post, you seem to hint at wanting to use the specific concept of Object inheritance to structure your application.
While “object inheritance” has its place for certain problems you may encounter in your game, the main building blocks of Unity games “GameObjects” work according to the “object composition” principle. Complex behavior is derived from combining different components that add generic behavior.
If you search google for “inheritance vs composition”, you will find a vast number of resources explaining the difference and why composition may be a better choice for GameObjects than inheritance.
A more practical response: You should not try to derive from GameObject. If you choose to use inheritance at all in your design, it should be applied to MonoBehaviours (i.e. the components that add behavior to your GameObjects) or to classes that do not appear at all in your game world (like underlying data structures, or mathematical tools).
As an example, if your player object and monster object share some code, is usually best to make a separate script (aka MonoBehaviour) that implements the shared code and have that present on both enemies and monsters (and have the scripts with their specific code interface with that).
That doesn’t mean inheritance is obsolete. When you need a script with a certain interface, but with different implementations, you could use inheritance. For example, the Unity components MeshCollider, SphereCollider and BoxCollider all implement the same Collider API in different ways.
Composition, combined with concepts like inversion of control, is pretty much the more modern view of OO rather than the inheritance-heavy hierarchies that were dominant in the 90s and early 00s.
Unity supports that very well, and the editor, through use of drag’n’drop of scripts onto other scripts, acts as a reasonable IoC/DI container.
The whole “A Player is a Creature is a PhysicsGameObject is a PhysicalGameObject is a GameObject is an Entity” architecture is showing its limitations pretty severely at this time.
I’m also trying to use Object Oriented Programming with Unity3D but I’ve fount a problem that I don’t know how to solve…
Let’s say I have an interface (I’m using C#) and two implementations:
public interface A_Interface{
abstract int GetValue();
}
[System.Serializable]
public class A_Implementation1 : InterfaceA{
public int value;
public GetValue(){
return value;
}
}
[System.Serializable]
public class A_Implementation2 : InterfaceB{
public int value1
public int value2;
public GetValue(){
return value1 + value2;
}
}
Then, I have an object that uses A_Interface:
public class B : MonoBehaviour{
A_Interface a;
...
}
¿How can I tell “class B” which implementation of the “interface A” should use? If it is possible, I’d rather not creating two classes (B1 B2) that are completely equals but each class uses a different A implementation…
If I finally chose to use the implementation 2, ¿could I change its properties values (value1 value2) in Unity3D editor?
Not sure if I’ve got your question wrong there, but you can assign your ‘a’ variable to an instance of either A_Implementation1 or A_Implementation2, but unless you cast it you can only ever call “GetValue()” on it.
I think you need your A_Implementations to subclass MonoBehaviour in order for you to attach it to a game object, after which you could create (e.g.) A1 and A2 with the respective implementation attached, and set the properties on each through the inspector. You then should be able to drag and drop either A1 or A2 onto the property on your object which has component B attached.
You are right: the “GetValue()” method would be the only method that could be called, but it wouldn’t be a problem because that would be the expected behaviour.
I thought this could be done without subclassing A1 A2 from MonoBehaviour and without assigning them to differents GameObjects, but I’ll give it a try…
I don’t know if I’m answering your question… But I’m new to Unity3D. I’m used to Object Oriented Programming. Going from Java → Unity3D and C# I found this to be a logic way to structure my classes:
Let’s say I want to have some prefab game objects:
a Vampire game object
a Skeleton game object
They have their own special properties, implemented in corresponding scripts
Vampire script (class)
Skeleton script (class)
typically added to their prefabs.
… but I want them to share properties and behaviour from an abstract super class “Creature”.
The class hierarchy could be much more sophisticated (e.g. Creature has other subclasses, like Human, Animal, etc),
but to keep this example simple, this is one way to do it:
The super class “Creature” inherits the MonoBehaviour:
public class Creature : MonoBehaviour
{
int hp;
string name;
//This works as a base constructor,
//to be called in the subclass’s Awake() or Start()
public void Init(string name, int hp)
{
this.hp = hp;
this.name = name;
}
public virtual void ShowStats()
{ print("Hello, I'm "+name+", and my HP= "+hp); } }
The Vampire and Skeleton classes inherit from Creature… and they can add extra behaviour, e.g. in overriding methods:
public class Vampire : Creature {
// Use this for initialization
void Start()
{ base.Init("Vampire", 2);
}
public override void ShowStats()
{
base.ShowStats();
print(“… and I’m a blood sucker too!”); } }
public class Skeleton : Creature {
// Use this for initialization
void Start()
{ base.Init("Skeleton", 1); } }
The sub classes - NOT Creature - will be attached to the Vampire and Skeleton prefabs.
The game logic can then find all game objects tagged with “Creature” and iteratate through them, like this:
public class GameLogic : MonoBehaviour
{
// Update is called once per frame
void Update ()
{
if (Input.GetKey(KeyCode.Space))
{
foreach ( GameObject creature in GameObject.FindGameObjectsWithTag(“Creature”))
{
creature.GetComponent().ShowStats();
//We can then invoke creature specific behaviour, e.g.
if (creature.name.Equals(“Vampire”))
{
//Do some cool vampire-specific stuff, //e.g life draining… } } } } }
Gives us…
Hello, I’m Skeleton, and my HP= 1
Hello, I’m Vampire, and my HP= 2
… and I’m a blood sucker too!
Best Regards
/Christian Andersson, Craze Music / Craze Creative Studios www.craze.se