Search code examples
c#unity-game-enginesolid-principlessingle-responsibility-principle

Advice on Unity3D SOLID SRP


I'm currently making a game in Unity3D and am trying to implement the Single-Responsibility Principle of SOLID into my game as I'm learning it.

I was wondering if anyone could explain a little more on what a good implementation of SRP looks like because I feel like I'm breaking it.

I've broken down my classes into the basics parts:

  • PlayerInput.cs - Gets Input an stores them into variables (Horizontal, Vertical, RMB, etc)
  • PlayerController.cs - Handles attacks and player states (idle, moving, attacking) ATM
  • PlayerMovement.cs - Handles movement and rotation (look at mouse)
  • AnimationController.cs - Handles All Animations

When I started I felt I was following SRP but now the game is getting more complex. Each class listed above gets a reference to the others which seems unnecessary. I'm using like 5 GetComponents in each class and it seems repetitive because they are all on the same object. In other words SRP seems like more work and is making it less efficient.

For example, both the PlayerController and the PlayerMovement script have a reference to AnimationController where AnimationController has a reference to both as well. All of the scripts have a reference to PlayerInput. (Keep in mind I'm leaving out other player related scripts like crafting and equipment to keep this simple but my Start and Awake methods are full of a bunch of GetComponent calls)

Could anyone explain SRP to me better and maybe point me in the right direction so I'm not using GetComponent so much on the same GameObject.

Thanks


Solution

  • You already correctly identified the problem, which obviously needs to be solved regardless of theoretical principles. But ok, let's discuss SRP first:

    The SRP refers two older concepts namely coupling and cohesion. Unfortunately the name "SRP", is confusing, ambiguous and only contains one side of the equation, which is to split stuff. It doesn't mention that stuff the belongs together should be actually together.

    So the point of all this is to enable maintainability, which is a shorthand for creating less future work. To do this it seems reasonable that things that refer to eachother should be actually together. This means methods that work with some data should be co-located with that data (i.e. in the same object). Stuff that is loosely related (i.e. refer to each other rarely) should be split.

    How to do this in practice depends on the business case and is not always apparent. I suggest an exercise. Put these things together in one class, call it Player for example. Simplify it, remove all setter/getters and indirections. Then try to see if there are areas that only loosely refer to each other, or refer only in one direction. These will be good candidates to split out.

    Try to split up meaningful things instead of technical ones, i.e. Movement, Attack, Player are all good, Controller, Animation are questionable (though not always bad).