Basic Unity Concepts for Programmers

Hello, Habr! While working on the Unity theme, we found an interesting blog that might deserve 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 programming journey 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?



Scene



The scene is the largest block describing the organization of objects in memory. Scenes contain the objects that make up your game.



In the basic case, a scene represents a single level of 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.







A 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 objects



The 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.



It is allowed to nest game objects into each other. 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 merged into an empty “Interior_Props” object 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 during game development.







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 affects 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 (eg Animator, Rigidbody, Collider) are the components that make up this object.



Each game object is made up of components .



A component implements a well-defined set of behaviors required to be executed 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.
  • , car Player Input Controller ( ), , , , .


Moreover, it is possible to write large and complex components, where the 1-in-1 component is equal to the encoded object (for example, the component playercontains the code that fully describes the character, and the enemy component, in turn, completely encodes the enemy), it is usually customary to extract logic by splitting it into small "streamlined" pieces corresponding to specific features. For example:



The code has a MonoBehaviorubiquitous parent class for representing components. Most non-embedded components will inherit from MonoBehavior, which in turn inherits from Behaviorand Component, respectively.



  • , , Player () Enemy () LivingObject, , , .
  • , , , , .


Components receive various callbacks throughout their lifecycle, which are called Messages in the Unity environment. To messages include, in particular, OnEnable/OnDisable, Start, OnDestroy, Updateand others. If an object implements a method Update(), then that 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 flagged 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



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.



Template instances



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 the tree object is made in the form of a template, then you can make instances of trees of different heights). All instances based on a template inherit from and override the template data.



Nested templates



As of Unity 2018.3, template nesting is supported, which is to be expected:



  1. A parent 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.
  2. 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 you edit the game, these objects are loaded into memory and then saved back to disk using the serialization system in place 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. These fields must be serialized in order for the MonoBehavior to accept input when constructing the scene during its initialization.



The most basic type of Unity, in particular GameObject, MonoBehaviorand resources amenable to serialization and can obtain their original values when you create directly from the Unity editor. Public fields in yourMonoBehaviorare serialized by default (if they are of a serializable type), and for this private fields must first be marked with an attribute Unity [SerializeField], and then they can also be serialized.





Screenshot of Chaos Reborn by Snapshot Games, 2015. BY-CC-SA 3.0



Conclusion



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.



All Articles