While working on the Unity theme, we found an interesting blogperhaps worthy of your closer attention. We offer you a translation of the article on basic concepts of Unity, also published on the Medium portal
If you have programming experience and are trying to get into game development, it can be difficult to find tutorials that adequately explain the required context. You will probably have to choose between materials, some of which describe the OOP paradigm, others – the C # language and Unity concepts, or start right away with advanced tutorials; in the latter case, you will have to deduce the basic concepts yourself.
Therefore, in order to partially fill this gap, I decided to write a series of articles Unity for Software Engineers… This is the first one. The article is intended for readers with an understanding of programming and software architecture, especially those who are close to the same approach to learning that I am: starting with the basics and gradually moving up.
I started my journey in programming about 17 years ago by discovering Game maker… I spent many hours on independent programming of small games and tools, in the process I got seriously carried away with programming.
Since then, however, the game development landscape has changed dramatically. When I tried Unity after a long pause in game development, what I wanted most was to understand the basic concepts: What are the building blocks of a game in Unity? What do you need to know about how these building blocks are represented in memory or on disk? How is idiomatic code organized? What patterns are preferred?
The scene is the largest block describing the organization of objects in memory. Scenes contain the objects that make up your game.
In the base case, the scene represents a single level your game, where one scene is loaded at any given time. In more advanced scenarios, you may have two or more scenes active at the same time. In this case, scenes can be additionally loaded into memory or unloaded. It is especially convenient to load several scenes during gameplay when building a large-scale world; keeping remote areas of the game world on disk rather than memory makes it easier to meet the performance demands you face.
Unity Scene Editor loaded with a default empty 3D scene. Empty Unity3D scenes contain the Main Camera and Directional light objects by default.
Sample scene in the Unity editor; several objects are highlighted here. This scene representation can be used to edit levels in the game.
Every game object in Unity must be in a scene.
Game Object (in code
GameObject) Is one of the basic building blocks of which the game is built.
In the form of game objects, you can represent both physical entities observed in the game (e.g., character, ground, tree, landscape, light, weapon, bullet, explosion) and metaphysical (e.g. equipment manager, multiplayer controller, etc. .).
Each game object has position and rotation values. They don’t matter for metaphysical objects.
Nesting game objects into each other is allowed. The position and rotation of each object is relative to its parent object. An object located directly in the scene is positioned relative to “world coordinates”.
A group of objects nested together in the scene and combined in an empty object “Interior_Props”, made for structuring purposes
There are many reasons why you might want to nest objects. For example, you might decide that from a structural point of view it makes sense to put your entire “environment” (for example, the individual elements that make up a city or village) in an empty parent object. Thus, the environment can be “compactified” and, along with the entire representation of a given scene, can be transferred to where it is required when developing a game.
A group of objects nested within a player object. Here we see the player’s weapon, avatar, and various UI elements displayed around the player.
Nesting objects can also be meaningful from a functional point of view. For example, the “Car” object may contain code that controls both the speed and the turns of the vehicle as a whole. But it can have separate child objects representing four wheels (moreover, all wheels will spin independently), car body, windows, etc. When the parent object “Car” is moved, all its child objects will move, keeping their orientation relative to the parent object and relative to each other. For example, we can schedule that the character opens the door, and this action concerns the door, and not the whole car.
Components (and monobehaviors)
The Warrior object from the previous screenshot is shown above the Inspector window in the Unity interface. Each of the illustrated sections (e.g. Animator, Rigidbody, Collider) are the components that make up this object
Each game object consists of components…
A component implements a well-defined set of behaviors required to be able to execute
GameObject… Everything that makes an object what it is is the contribution of the components that make it up:
- The only “visible” car element will have a Renderer component that renders the car, and probably a Collider component that sets the collision boundaries for it.
- If the car represents a character, then the car object itself can have a Player Input Controller that receives all keystroke events and translates them into code that controls the movement of the car.
Moreover, it is possible to write large and complex components, where a 1-in-1 component is equal to the object being encoded (e.g., a component
player contains the code that fully describes the character, and the enemy component, in turn, completely encodes the enemy) it is usually customary to extract logic, splitting it into small “streamlined” pieces corresponding to specific features. For instance:
The code has
MonoBehavior, the ubiquitous parent class for representing components. Most non-embedded components will inherit from
MonoBehaviorwhich in turn inherits from
- All objects with health, be it
Enemy(Enemy) may have a component
LivingObjectthat sets the initial health value, takes damage and enforces death when the object dies.
- In addition, the player can have an input component that controls the movement imparted to him, and the enemy can have a similar component implemented using artificial intelligence.
Components receive various callbacks throughout their lifecycle, which are called Messages in the Unity environment. Messages include, in particular,
Update other. If the object implements the method
Update(), then this method will magically be called by Unity every frame of the game loop while the object is active and the specified component is active. These methods can be labeled
private; in this case, the Unity engine will still call them.
As you might guess, components can provide public methods as well. Other components can take a reference to this and call these public methods.
Resources are entities located on disk that make up a game project. These include networks (models), textures, sprites, sounds, and other resources.
When your scenes are serialized to disk, the system presents them as resources, made up of game objects within them. In the next section, we’ll also look at how to turn commonly reused game objects into a resource called prefabs.
Resources can also represent less “tangible” objects, such as input control maps, graphical settings, string databases for internationalization, and more. You can also create your own resource types using ScriptableObjects. Here’s an article on how to keep things like this.
For a development project, resources are the key piece of information in the code base, along with the code itself.
The finished game package will contain most of your resources. They will be saved to disk on the device where the game is installed.
Game objects, their components and input parameters exist as separate instances in the scene. But what if objects of a certain class are repeated every now and then? Such objects can be designed in the form of templates, each of which is, in fact, an object in the form of a resource.
Instance templates in the scene lend themselves to local modifications to distinguish them from each other (for example, if an object tree made in the form of a template, you can make instances of trees of different heights). All instances based on a template inherit from and override the template data.
As of Unity 2018.3, template nesting is supported, which is to be expected:
- A parent object, with child objects represented as templates, can itself be represented as a template. Within the parent template, the child template allows its own modifications. In the scene, the entire hierarchy of templates is instantiated at once, and modifications specific to a particular scene can also be built on top of it.
- A templated instance residing in a scene and provided with its own local modifications can be saved as an independent “Prefab Variant” resource. This variant is a template resource inheriting from another template, on top of which additional modifications are applied.
These concepts are composited: a template version of a nested template is possible, or, for example, a template version of a template version.
Serialization and Deserialization
All resources, scenes and objects in your project are permanently stored on disk. When editing a game, these objects are loaded into memory and then saved back to disk using serialization systemsoperating in Unity. In test runs of the game, objects and scenes in memory are loaded using the same serialization system. This system also correlates the resources in the compiled package with the loaded / unloaded scene objects in memory.
The serialization / deserialization thread operating in the Unity engine loads the resources located on disk into memory (in your project: for editing or test run of the game, or in the game itself, when loading the scene) and is responsible for saving the state of the objects and components you edited back into the corresponding scenes and template instances.
Hence, the serialization system is also a key element of working with the Unity editor. In order for the MonoBehavior to accept input when constructing the scene during its initialization, these fields must be serialized.
Most of Unity’s base types, in particular
MonoBehavior and resources amenable to serialization and can receive initial values when created directly from the Unity editor. Public fields in your
MonoBehavior are serialized by default (if they are of a serializable type), and private fields for this must first be marked with the attribute
Unity [SerializeField]and then they can be serialized too.
Screenshot of Chaos Reborn by Snapshot Games, 2015. BY-CC-SA 3.0
Above, we looked at the basic structural concepts used in the architecture of Unity games. After reading more about them, and how the resources stored on disk relate to the memory representations of those resources, you should get an understanding of the engine and then move on to the more advanced tutorials.