Generally lots of small scripts that do one thing really well. Yes, you have to do “GetComponent” which is cumbersome, but I usually do that during the Start() function.
With regard to encapsulation, if you are referring to fields and properties, Unity’s Inspector cannot see properties, only public fields, so people don’t encapsulate all that much. For me, generally I create both a field that can be set in the editor, and a property in the code which can be set by a programmer and is set in the Awake() function by copying the field value to the property value. I do this if, and only if, the values of the field property need to be sanity checked for valid ranges or other pre-computation needs to take place once the field value has been set up, e.g. calculating the absolute world position of something from the relative position, which I need to do for the paths in the example given below.
One of the small projects that is linked in my signature breaks down something like the layout below. I only have one “singleton” class in my entire game and that is just purely because almost all scripts need to reference it, so it maintains a static reference.
Unity Structure For “The Core”
Player Prefab
Reads the keyboard and mouse, calls the appropriate functions on the Player Movement Controller and the Player Fire Controller. Absolutely no logic in this module determines whether the player can move, it merely translates input to movement commands. (~55 lines of code)
- Player Movement Controller
Determines the speed at which the player can move, whether they can move, how they should move. (~115 lines of code)
Determines the speed at which the player can fire, whether they can fire, how many shots can exist at once, and instantiates new projectiles. (~90 lines of code)
Handles the super zapper recharging, fires the super zapper, generates visual and audible effects. (~40 lines of code)
Standard Projectile Prefab
Follows a pre-determined path (~163 lines of code)
Handles the collision between the projectile and an enemy, destroys itself when it leaves the playfield, plays sound effects. (~75 lines of code)
Enemy Fodder Prefab
Your standard enemy to be mown down in large numbers by the player wantonly shooting at them. There’s nothing special about these guys, they just die.
Follows a pre-determined path. The same script exists on all types of enemies and all projectiles that can follow a path. (~163 lines of code)
Handles collision with a projectile, determines what happens when the enemy reaches the player’s base. (~79 lines of code)
CPU
Stores a list of paths that projectiles and enemies can travel along. (~48 lines of code)
- Firing Position Controller
Calculates the firing positions that the player can move to. Draws a gizmo on the screen to represent where those positions are at edit time. (~114 lines of code)
Spawns waves of enemies for the player to shoot. (~250 lines of code)
Spawns bonuses that the player can pick up or shoot. (~200 lines of code)
Camera
Tracks the player and moves to pre-calculated positions based on the player’s firing position. Displays an editor gizmo to show where the tracking positions will appear. (~120 lines of code)
Game Controller game object
This game object exists only in the scene and lasts for as long as the game is in progress. Tracks lives, score, and other types of data that must be persistent from one level of the game to the next.
Tracks the player’s lives, increments up when they collect a free life bonus, decrements down when they get killed. (~65 lines of code)
Tracks the current level, increments up when all of the enemies for the current level have been killed. (~36 lines of code)
Tracks the player’s current score, totals up the score and any bonuses and multipliers, also increments the score over time by LERPing between two values so that the on-screen GUI score does not instantly jump from the old value to new value whenever something is killed. This LERPing score adds more dynamic feedback to the GUI. (~90 lines of code)
Enables and disables the enemies, player input and other systems at appropriate times such as during a cut-scene or when the player has died. Handles the player reaching the base, game over, and level transitions. (~200 lines of code)
Displays the in-game HUD to the user consisting of score, level #, lives, enemies remaining, etc. Only one in-game GUI script exists for the HUD to save on script calls. Individual game play elements such as bonuses and enemies handle their own GUI rendering. (~60 lines of code)
Below is the editing environment showing the firing position and camera tracking gizmos, along with a parallax field and a selected path.