

Or, you could put a queue in between them, so that the logic system can put things into the queue and the presentation will read what’s coming from the queue.Ī good way to decouple logic from presentation as your game grows is with a message bus. You can create a buffer object whose sole purpose is to provide storage area where the logic can write things and the presentation can read things. If we take the Pong-style example game again: how will the Ball logic and Score presentation talk to one another? Is the ball logic going to inform the score presentation when something happens with regards to the ball? Is the score logic going to query the Ball logic? They will need to talk to one another, somehow. You can also decouple objects by inserting glue logic between them. The ball simulation does not really own the location of the ball it runs a simulation tick based on the location of a ball that is provided, and then returns the result.
UNITY 3D GAME DESIGN UPDATE
If you look at the position update logic in FixedUpdate(), we can see that the code needs to send in a position and then it returns a new position from there. There are more things that we can do to this. There are only a few clear areas of responsibility left in the MoneBehavior at this point. If we look at the reorganized version above, one significant change we see is that the Destroy() operation is no longer buried many layers down. What we end up with is that Ball has a logic portion that controls the simulation in some ways, and the result of that simulation feeds back into the MonoBehavior. However, does it make sense for a ball simulation to make decisions based on what it actually hits? That sounds more like game logic. The only job it has to do is physics integration and reacting whenever the ball hits something. If we go back to the ball example, we’ve moved the simple physics simulation into a C# class that we call BallSimulation. With this method you want to split up the logic by type of responsibility.

On the other hand, if you use regular C# classes, then the editor does not understand the objects, and cannot display them natively in the Inspector, and so on. And, regular C# code can be shared with native. Regular C# classes have better language facilities than Unity’s own objects for breaking down code into small, composable chunks. Moving MonoBehaviors to regular C# classes is another method to look at, but what are the benefits of this? One way of doing that is using ScriptableObjects, and there are already some great resources out there on this method. I think that for many games, it’s worthwhile to get as much code as possible out of MonoBehaviors. The general game logic, input handling, physics simulation and presentation could reside within MonoBehaviors, ScriptableObjects or raw C# classes.įor exposing parameters in the Inspector, MonoBehaviors or ScriptableObjects can be used.Įngine event handlers, and the management of a GameObject’s lifetime, need to reside within MonoBehaviors. Here are ways to create those smaller parts: There are a number of different types of responsibilities in these classes–game logic, input handling, physics simulations, presentations and more. There's an opportunity here to break things up into smaller parts. In large code bases it is rare to allow entities to delete themselves the tendency is instead to have owners delete things that they own. That is where the trigger logic deletes its own GameObject. The homemade physics simulation is not just the movement in FixedUpdate() it also encompasses the reaction when the ball hits a wall.ĭeep within the OnTriggerEnter() callback is a Destroy() operation. As soon as the ball starts moving, the information about initial velocity is lost. We are reusing the same variable for two slightly different purposes. It doesn’t look like much, but on closer inspection, we see that the ball has a velocity that is used both by the designer to set the initial velocity vector of the ball, and by the homemade physics simulation to keep track of what the current velocity of the ball is. Let’s look at a simple example as shown in the image above. It’s a principle that you can apply to a code base of any size. If applied correctly you should be able to give short answers to the questions, “what does a particular class do?” as well as “what does it not do?” This makes it easy for every developer on your team to understand what the individual classes do. Let’s see how we can split them up by working from what’s called the Single Responsibility Principle, which stipulates that each class should handle one single thing. If this was a game in actual development, you would see the individual MonoBehaviors grow larger and larger.
