I am currently trying to build a game that has combat in it.
I currently plan to have these classes for now:
Stats (stores information such as base attack damage, speed, Max Health)
WeaponSystem (Stores refrence information of weapons, Changes animator attack states etc…)
Movement (Have methods such as move direction, jump, etc…)
ItemInventory (stores things such as potion and handles consming items etc…)
So for now, I have two approach for this. First approach is to have a central Player class which has all references to the classes listed above. An example of this approach might be:
//Movement in Player.cs
Vector2 moveDirection = new Vector2(input.getAxis("Horizontal"), input.getAxis("Vertical").normalized;
//refrence to Movement.cs to move, refrence to Stats.cs to get attack speed
movement.move(moveDirection, stats.movementSpeed)
//Attacking
if(input.getButton("Attack")){
Weapon.attack = true;
etc...
}
The second approach is to drop the central Player class and use events. However, I do not know which classes should have a event and which class should subscribe. Will I still need a central Player class to do this?
I have also tried to just reference classes that each class needs. For example, weapon will reference stats, stats will reference weapon, movement will reference stats, etc… However, this becomes a mess when the project starts to grow and many scripts rely on many different things and in the end, it turns into spaghetti code.
…so are there any better ways of approaching this? I seem to have trouble with OOP, especially with modular, independent code. I have tried using events, but I still seem to not be able to grasp this concept (I am confused because how does code become independent if you still need to reference the object you want to listen too?). Are there any tips and tricks to achieve this?
There are multiple different approaches to this. A great start is to check out SOLID principles and the gang of four’s design patterns. Some of this material may be more or less applicable within Unity.
In general I tend to find god classes that have references to every component on an entity or every object in a scene more hassle ten they are worth. They are a pain to keep up to date as your code changes. They also spread dependencies through your code.
You can mitigate this somewhat using interfaces. Every public member of a class should be part of an interface. (I’m currently in the habit of scrawling a quick interface at the bottom of each file. I may come to regret this later.) But unity doesn’t play nicely with serialised interfaces.
For communication between two scripts with less dependencies there are two common methods. Events and Messages.
Events are your one-to-many communication. Listeners subscribe to events. The event class does not know a thing about its subscribers, it simply fires off its event and let’s subscribers take action. Check out UnityEvents for a specific implementation in Unity.
Messages work in a different fashion. The sender sends a message to a target. The target acts on that message. Neither class knows details about the other. Check out ExecuteEvents or SendMessage.
In terms of overall structure, I like to consider code in terms of systems instead of entities. Components of your damage system might include your gun, damagable and life scripts. These components together form a system, and have more business talking to each other then your gun and your motor script have.
Within systems a little dependency is okay. Between systems it should be avoided except through narrowly defined channels. Keeping system dependencies on levels and one way between levels is also valuable.
This is not how every one works. Expect differing opinions on how much design and structure is valuable.
Thank you Boredmormon (I have seen your youtube videos before!) I have picked up a couple of things from the post that you have posted. I see how a god class will be a very bad.(It creates a ton of tightly coupled scripts which can not do anything by itself). However this leaves me with one question, without the use of the god class, how would I handle situations such as this:
-There is a motor script the handles movement.
-There are other scripts that restricts a players movement.
examples are menus, some sort of stun, before the game starts, after you are dead etc… (I would probably want to add more things while the game develops)
:). This always makes me happy. I am planning to extend the Unity Principles series out to discuss code structure soon. It will make it easier to link a video then to type it out.
Here are some options to consider, in no particular order.
Build an interface between your motor and your buffs. Depend on that.
Use ExecuteEvents to send a message to the motor. The motor can choose how to react.
Build a game state manager. Use this to trigger global events. Useful for things like game over, player dead and the like. Its typically not a huge issue to have your high level systems like movement depend on low level systems like game state. After all, we typically don’t complain that all of our code is dependent on UnityEngine. But you can still control the dependency with an interface.
Gather all of the buffs into a single ‘buffable’ component. Have the motor component check that before acting. This leave both your motor and your stun gun dependent on the buffable component, but neither depends on the other.
And as is often the case when considering structure, drawing it out helps. You don’t need a full blown UML, but simply a set of boxes defining each class, and arrows between indicating dependencies. I’ve attached an example from one of my projects.