Security information portal. Entertaining physics Interaction with physics in Unity

Unity- a very powerful, progressive engine with great potential. It has many built-in functions (including a physics engine NvidiaPhysX), which we, the users, do not have to enter manually. :)
In this short article I would like to discuss the physical capabilities of the engine. So, let's begin:

Rigidbody

What it is?

Behind the function Rigidbody Absolutely Solid Body is hiding ( ATT). To explain roughly and clearly, then ATT in physics and mechanics - this is an ideal solid body that, under the influence of force, cannot change its properties, but can (under its influence) move in 3 dimensions (down, up, forward, etc., i.e. in our X-Y-Z axes), and also rotate in 3 dimensions (again along axes X-Y-Z).

IN Unity, as in other game engines (again, I call them “game” engines roughly), Rigidbody is used for various objects, with which we can interact by pushing, kicking, etc. Such objects under our influence will further roll, move and collide with other objects under the influence of gravity.

What use can we find of this function?

For example, to create a car, except Rigidbody we will need 4 Wheel Collider"a and code (script) that applies force to the wheels, depending on the keys pressed.

Customizable Features

  • Mass- The mass of our object in kilograms. It is recommended not to set mass values ​​100 times greater or less than the masses of others ATT.
  • Drag- How much a body is exposed to air resistance when it moves under the influence of forces. When value 0 there is no resistance, and an infinite value will instantly stop our object.
  • Angular Drag- How much a body is exposed to air resistance when it rotates under the influence of forces. When value 0 there is no resistance, and an infinite value will instantly stop the rotation of our object.
  • Use Gravity- When turned on, the object becomes subject to the influence of gravity.
  • Is Kinematic- When enabled, the object becomes unaffected by the physics engine and can only be changed by its function Transform. This can be useful for creating moving platforms, for example.
  • Interpolate- Applies only if the movements of your ATT seem strange or awkward to you, etc.:
    1. None: No interpolation applied
    2. Interpolate: Compared to the transformation of the previous frame ( frame), the next one will be smoothed.
    3. Extrapolate: The transformation of the current frame is smoothed out in comparison with the estimated (approximate) transformation of the next one.
  • Freeze Rotation- Prohibits any rotation, both scripted and during collisions. However, rotation can be performed using the function transform.Rotate()
  • Collision Detection- Used to prevent fast moving objects from passing through other objects without finding Collision"ov (a special "grid" on objects with which they collide with each other and with the player).
    1. Discrete: The default value is to ensure that our object “notices” all other objects that it may collide with.
    2. Continuous: Use Discrete Collision with dynamic collision objects (which have ATT), A Continuous Collision for static MeshCollider"ov (without ATT). Mode Continuous Dynamic uses Continuous Collision for one specific ATT. Rest ATT will use the mode Discrete. (This will greatly affect the load on the physics engine, just leave Discrete, if there are no problems with collisions of fast objects)
    3. Continuous Dynamic: Used for objects in mode Continuous or Continuous Dynamic Collision. Continuous Collision will also be used for static MeshCollider"ov (without ATT). For all others the mode is used Discrete. Used for fast moving objects.

How can we use this feature?

Basic knowledge.

To use ATT, we need an already created game object ( GameObject), by clicking on it, we go to the menu along the following path: Components - Physics - Rigidbody . All, ATT added! :)
Now the object is subject to gravity, you can apply forces to it using scripts, but in order for the object to behave exactly the way you want, you need to add Collider or Joint.

Code rules the world.

In the script we will now manipulate our object using functions AddForce() And AddTorque() .
Since I'm in Unity I apply JavaScript, my examples will be with it, links to other scripting examples (at C# or Boo) you will find below in paragraph Additional information on ATT.

» Rigidbody.AddForce

// Rigidbody.AddForce uses 2 types of formulas, like many other functions related to movement in space. // Type 1: function AddForce (force: Vector3, mode: ForceMode = ForceMode.Force) : void // Force that throws an object up relative to the global coordinate system. function FixedUpdate() (rigidbody.AddForce(Vector3.up * 10); ) // Uses Vector3, a built-in Unity function that is, in principle, similar to the standard coordinate system. // Type 2: function AddForce (x: float, y: float, z: float, mode: ForceMode = ForceMode.Force) : void // The same thing, but used here X-Y-Z system coordinates function FixedUpdate() (rigidbody.AddForce(0, 10, 0); )

» Rigidbody.AddTorque

// The function spins the object around a given axis. // Type 1: function AddTorque (torque: Vector3, mode: ForceMode = ForceMode.Force) : void // Spins the ATT around the global Y axis. function FixedUpdate () ( rigidbody.AddTorque (Vector3.up * 10); ) // Type 2: function AddTorque (x: float, y: float, z: float, mode: ForceMode = ForceMode.Force) : void // Does the same thing, but again in a different measurement system. function FixedUpdate() (rigidbody.AddTorque(0, 10, 0); )

ATT interacts with objects.

For the proper operation of our ATT they need to be supplied Collider"ami (or Collision"ami, as you please ^.^).
Read more about colliders below.

Size matters!

Observe the dimensions of your object, because they are much more significant even than mass ATT. If your object is moving incorrectly, hanging in the air, or not colliding, try adjusting its magnitude (not ATT, but the object itself). When importing a model from a 3D editor, its dimensions are preserved, so be careful at the modeling stage and respect the dimensions of all models.

Additional information on ATT

On this, describe ATT or Rigidbody, I think I'll finish. However, there are a couple of tips, especially for those who have made it all the way here :)

  1. Standard cube size in Unity equals 1 meter, therefore, it is very convenient to check the size of your models using it. To create a cube, select from the menu GameObject - Create Other - Cube
  2. Relative indicator Mass defines how two objects will interact with each other.
  3. Mass does not affect the speed of falling from a height, for these purposes use Drag.
  4. The higher the values Drag, the more the object weighs. standard values ​​vary from 0.001(hard piece of metal) to 10(feather).
  5. If you need to change an object both using scripts and using physics, add to it ATT with parameter Kinematic.

Colliders

What it is?

In the previous section we looked at the principle of operation Rigidbody and mentioned the so-called colliders. Collider for us - an auxiliary object in the form of a mesh of a simple primitive or, conversely, complex shape, which is located around our model or part of the model and interacts with other objects if they are also surrounded by colliders.
To clearly explain to connoisseurs of the *Warcraft 3* world editor, imagine the model we imported, to which we did not assign path textures in the dudad editor - this will be our object; and the role of colliders here will be played by blockers of the path around the model. Naturally, this is a rather rough comparison, because in Unity they are much more functional. Well, let's take a closer look.

Types of colliders.

Colliders are added through the menu Component - Physics . There are several types:

  • Box Collider- in the shape of a cube.
  • Sphere Collider- in the shape of a sphere.
  • Capsule Collider- in capsule form.
  • Mesh Collider- automatically creates a collider based on the shape of the object's mesh; it cannot collide with other colliders of the same type. Mainly used for static objects, such as a race track environment.
  • Wheel Collider- used for wheels, a very useful thing.
  • Compound Collider- combinations of primitives that together act as one. To create such a complex collider, you need to add child objects to our base collider, and then bind them to them using a primitive. Thus, for example, it is very convenient to make simple colliders for cars.

Customizable Features

In principle, all colliders are similar to each other, they are simply used for objects of different shapes, however they have several different parameters.

  • Cube
    • Material- Shows how the collider interacts with other objects, while assigning physical material, for example, metal, ice, etc.
    • Is Trigger- If the parameter is enabled, then the object is affected by the script, not physics.
    • Size- Collider size along X-Y-Z axes.
    • Center- The position of the collider, relative to the local coordinates of the object.
  • Sphere
    • Radius- Sphere radius, replaces the parameter Size.
    • The remaining parameters are unchanged.
  • Capsule(parameters replace size)
    • Radius- Capsule thickness.
    • Height- The height of the cylindrical part of the collider (without rounded bases).
    • Direction- The direction of the collider, relative to the local coordinates of the object.
  • Mesh Collider(parameters replace size)
    • Mesh- Selecting the desired mesh to create a collider.
    • Smooth Sphere Collisions - Enabling this feature smoothes the surface of the collider. It should be used on smooth surfaces, for example, an inclined landscape without unnecessary angularity, along which the spheres should roll.
    • Convex- When enabled, allows our collider to collide with others of the same kind. Convex Mesh Collider"s are limited to 255 triangles.
  • Wheel Collider(parameters replace size)
  • Radius- Wheel radius.
  • Suspension Distance- Maximum distance to increase wheel suspension. The suspension always increases down the local axis Y.
  • Suspension Spring- The suspension tries to reach the specified point using various forces.
  1. Spring:// Tries to reach the specified point (position). The higher the parameter, the faster it is achieved.
  2. Damper:// Softens and slows down the speed of the suspension. The higher the value, the slower the shock absorber moves.
  3. Target Position:// The total "path" the pendant can "travel". 0 means a fully extended shock absorber, and 1 - fully compressed. The default value is 0, which corresponds to a normal car suspension.
  • Mass- Wheel weight.
  • Forward/Sideways Friction - Friction parameters when the wheel simply rolls and when it rolls sideways (this happens in skids or during drifting).


I like +15 - 0

Views: 734


My strange creative path took me into game development. Thanks to an excellent student program from an IT company whose name consists of one Greek small letter, collaborating with our university, we managed to assemble a team, generate documentation and establish Agile game development under the supervision of a high-class QA engineer (hello, Anna!)

Without much thought, Unity was chosen as the engine. This is a wonderful engine on which you can really quickly and easily do very bad game, which no one in their right mind would ever play. To create good game, you still have to dig through the documentation, delve into some of the features and gain development experience.

Our game used the physics engine in an unexpected way, which caused many performance issues on mobile platforms. This article, using our game as an example, describes my struggle with the physics engine and all those features of its work that were noticed on the way to a viable beta version.

A game

A few words about how it is made.
Made using Blender and a couple of Python scripts. At the time of shooting, in the corner of the screen there were 16 squares, the color of which encoded 32 bits of a floating point number - the rotation of the phone in this moment time. R, G - data, B - parity. 0 - 0, 255 - 1. The video shot on a computer was divided into frames using ffmpeg, and each render frame was assigned a decrypted angle. This format made it possible to survive any compression during the shooting process and overcome the fact that all programs have slightly different ideas about the passage of time. In reality, the game plays the same way as in the render.


The airplane flies through an endless and unpredictable cave, in which there are bonuses, all sorts of coins and enemies at which you can shoot homing missiles. I crashed into the wall and immediately lost.
A distinctive feature of the game is that the level is nailed to the horizon and the control in it is gyroscopic, and absolute. I tilted the phone 45 degrees and the airplane flew at an angle of 45 degrees. You need to make a loop - you have to rotate the tablet. There is no sensitivity, only hardcore.
Let us highlight two main and obvious problems for the developer:
Problem 1: Infinity
Unity stores and processes object coordinates as regular 32-bit floats, with a precision of somewhere up to 6 decimal places. The problem is that our game is endless and if we fly long enough, all sorts of crazy bugs will start, including teleportation through walls. There are several approaches to solve this problem:
  • Ignoring. In Minecraft, for example, rounding errors only made the game more interesting, giving rise to .

  • Teleportation to (0;0;0) when the airplane moves too far from the origin.

  • Change of reference point. It is not the plane that moves, but the level around it.
  • In our case, the only acceptable option is the third, which was implemented. More on implementation a little later.
    The first - ignoring - is absolutely unacceptable. Creating a robot that can play our game forever is an interesting (and very simple) problem that someone will solve. And ordinary Korean players should not be underestimated - the airplane is fast, the level is generated unpredictably. And if you fly and fly before passing through walls, then much more accurate shooting will obviously begin to fail after 5 minutes of flight.
    The second - teleportation of the player and the entire world - brings mobile devices to their knees, in some cases - for about half a second. This is very noticeable and therefore unacceptable. But this is a completely acceptable option for simple people. endless games for PC.

    Problem 2: Level Generation

    There are several basic approaches to building endless runners:
  • Using ready-made level segments that fit together randomly. This is done, for example, in Subway Surfers. It's easy to implement, but the player quickly gets used to it and knows what to prepare for, which is boring.

  • The level is simply a straight line on which obstacles are randomly placed. This is done in Joypack Joyride and Temple Run. In our case, this would greatly limit the number of maneuvers.

  • Everything is randomly generated. The most difficult, unpredictable and interesting option for the player.
  • Of course, we chose the most difficult option. At its heart there is a very complex state machine that performs random transitions through them. But within the framework of this article, it is not the mechanism that is of interest, but the process of level generation and its organization, taking into account the chosen starting point.

    Level structure

    We are flying in a cave, it has a floor and a ceiling - a couple of blocks, elementary building units. The blocks are combined into segments that fit seamlessly together. The segments, as a whole, rotate around the aircraft and move along its velocity vector, creating the illusion of flight. If a segment leaves the camera's field of view, it is cleared of blocks, docked to the last segment of the level and filled with new blocks, according to the instructions of the generator. The totality of such segments is the level.
    Experienced Unity developers could quite justifiably wince, estimating the amount of work and all the possible pitfalls. But in words everything is simple, but I had no development experience...

    Basic Laws of Physics in Unity

    Over a month of development, experimentation and reading documentation, I identified three basic laws of physics in Unity. They can be violated, but the price for violation is productivity. The engine will not warn you in any way about an error, and without a profiler you may never know about them. Failure to comply with these laws may slow down your gameplay in tens once. As I understand it, breaking any law results in the physics engine marking the offending collider as incorrect and recreating it on the object, followed by recalculation of the physics:
    1. Colliders should not move, rotate, turn on, turn off or change size.
    Once you have added a collider to an object, forget about any impact on it or the objects that contain it. A regular collider is a purely static object. A tree, for example, can have one collider. If a tree can fall on the player, the tree will fall along with the performance. If this tree grows from a magical nutrient cloud that does not have a collider, but can move, this will be accompanied by a drop in performance.
    2. If an object moves or rotates, it must be a rigid body i.e. have a Rigidbody component.
    This is written about in the documentation, yes. Which you don’t have to read carefully to start making a game, because Unity is very simple and intuitive.
    Rigidbodies change the relationship of the physics engine to the object. External forces begin to act on it, it can have linear and angular velocities, and most importantly, a rigid body can move and rotate using the physical engine without causing a complete recalculation of physics.
    There are two types of rigid bodies - ordinary and kinematic. Ordinary bodies interact with each other and with ordinary colliders - one body cannot pass through another. Kinematic bodies follow simplified simulation rules - they are not affected by any external forces, including gravity. They are free to go through anything.
    If you don’t mind putting objects under the control of a physics engine, use regular rigid bodies. For example, if you need to beautifully roll stones off a cliff. If your scripts or animators control the object directly, use kinematic bodies, so you don’t have to constantly fight with the engine and random object collisions. For example, if you have an animated character or a guided missile that explodes on contact with something.
    3. If the object is a rigid body, it must move and rotate through rigid body methods.
    Forget about directly calling "Transform" on an object immediately after adding a collider to it. From now on, Transform is your enemy and a performance killer. Before you write transform.position =... or transform.eulerAngles = ..., say the phrase " I now absolutely clearly understand what I’m doing, I’m satisfied with the brakes that will be caused by this line.” Don’t forget about the hierarchical connections: if you suddenly move an object containing rigid bodies, the physics will be recalculated.
    There are three levels of rigid body control:
    - The highest and, therefore, natural level is through strength. These are the AddForce and AddTorque methods. The physics engine will take into account the body mass and correctly calculate the resulting speed. All interactions of bodies occur at this level.
    - Medium level - change of speeds. These are the velocity and angularVelocity properties. On their basis, the forces influencing the bodies during their interaction are calculated, as well as, obviously, their positions at the next moment in time. If a rigid body has a very low speed, it “falls asleep” to save resources.
    - The lowest level is the direct coordinates of the object and its orientation in space. These are the MovePosition and MoveRotation methods. At the next iteration of the physics calculation (this is important because each subsequent method call within one frame replaces the call of the previous one), they teleport the object to a new position, after which it lives as before. Our game uses this level, and only this level, because it provides complete control over the object.

    What's left behind? Turn on and off the object and scale. I don't know if there is a way to change the size of an object without confusing the engine. It's quite possible not. Turning off an object is painless, but turning it on... yes, causes a recalculation of physics in the vicinity of the turned on object. Therefore, try not to include too many objects at the same time, stretch this process over time so that the user does not notice.

    There is a law that does not affect productivity, but does affect performance: a rigid body cannot be part of a rigid body. The parent object will dominate, so the child will either stand still relative to the parent, or behave unpredictably and incorrectly.

    There is one more feature of Unity that is not related to physics, but is worthy of mention: dynamically creating and deleting objects via the Instantiate/Destroy methods is INSANELY slow. I'm afraid to even imagine what happens under the hood during the creation of an object. If you need to create and delete something dynamically, use factories and fill them with the necessary objects while the game is loading. Instantiate should be called as a last resort - if the factory suddenly runs out of free objects, and forget about Destroy forever - everything created should be reused.

    Application of laws in practice

    (this section contains the process of reasoning when creating the game and its features)

    The level obviously needs to rotate and move.
    Let's make our life easier forever by placing the level's rotation axis - the airplane - at the origin of coordinates. Now we can calculate the distance from a point to it by calculating the length of the point's coordinate vector. It's a small thing, but nice.
    Moving objects together is easy to implement through the object hierarchy in Unity because children are part of the parent. For example, the described level structure is logically implemented as follows:
    - Axis of rotation
    - - Level
    - - - Segment 1
    - - - - Block 1 (Collider)
    - - - - ...
    - - - - Block N
    - - - Segment 2...
    - - - Segment 3...
    - - - Segment 4...
    (You can even do without the level object)

    The script on the axis receives data from the gyroscope and sets the appropriate angle for it... And it violates many rules at once, because the rotation will be transmitted through the hierarchy to the colliders, which will drive the physics engine crazy. You will have to make the axis a rigid body and rotate it through the appropriate method. But what about the level movement? Obviously, the rotation axis and the level object will not move, each segment must be moved individually, otherwise we are faced with the problem of infinity. This means that the solid bodies must be segments. But we already have a rigid body higher in the hierarchy and a rigid body cannot be part of a rigid body. A logical and elegant hierarchy is not suitable; everything will have to be done by hand - both rotation and translation, without using an object for the rotation axis. Be prepared for this if you have unique gameplay features.

    If you had to move the segments directly, then you would have to rotate them. The main difficulty is that in the Unity physics engine there is no method to “rotate an object around an arbitrary point” (Transform has it, but don’t be tempted). There is only “rotate around your center.” This is logical, because rotation around an arbitrary axis is both rotation and movement, and these are two different operations. But it can be imitated. First, we rotate the segment around its axis, then we rotate the coordinates of “our axis” around the plane. Thanks to the fact that we have the plane at the origin of coordinates, we don’t even have to remember school geometry and go to Wikipedia, Unity already has everything. It is enough to convert the rotation angle into a quaternion and multiply it by the coordinates of the point. By the way, I found out about this right while writing the article; before that, the rotation matrix was used.

    We have enemies pushing the plane into the wall, hoping to kill. There is a shield that pushes the plane away from the walls, helping to survive. This is implemented trivially - there is a displacement vector, which is added to the coordinates of each segment every frame and reset after that. Anyone who wants to kick the airplane, through a special method, can leave the vector of their kick, which will be added to this displacement vector.

    Ultimately, the actual coordinates of the segment, each frame, are calculated by the level's motion control center something like this:
    Vector3 position = segment.CachedRigidbody.position; Vector3 deltaPos = Time.deltaTime * Vector3.left * settings.Speed; segment.truePosition = Quaternion.Euler(0, 0, deltaAngle) * (position + deltaPos + movementOffset);
    After all the calculations and crutches necessary to make precise segment joining work during regeneration, segment.truePosition is sent to the MovePosition method of the segment's rigid body.

    conclusions

    How fast does all this work? On older flagships - Nexus 5 and LG G2 - the game flies at 60 FPS, with a barely noticeable drawdown when turning on new colliders during segment generation (this is inevitable and there is no way around it) and pushing worms out of the ground (you can create some kind of hell, to get around this, but now there is a deliberate violation of the third law). 40 stable FPS is produced by any device with a gyroscope that we came across. Without knowledge and consideration of all laws, performance was, to put it mildly, unsatisfactory and the phones overheated. So much so that I was thinking of writing my own simple specialized engine for 2D physics. Fortunately, physics in Unity turned out to be flexible enough that all problems could be worked around and created unique game, only a couple of weeks of experiments were enough.

    Now, knowing all the main pitfalls of the Unity physics engine, you can quickly clone our game, destroying the dreams, lives and faith of three poor students in humanity. I hope this article will save you a lot of time in the future and help you find not-so-obvious violations of the laws of productive physics in your projects.

    Read the documentation and experiment, even if you use simple and intuitive tools.

    *Unity* is a very powerful, progressive engine with great potential. It has many already built-in functions (including the *NvidiaPhysX* physics engine), which we, the users, do not have to manually register. :)
    In this short article I would like to discuss the physical capabilities of the engine. So, let's begin:

    Rigidbody
    =
    = What is this? =
    Behind the *Rigidbody* function is an Absolutely Rigid Body (*ATT*). To explain roughly and clearly, *ATT* in physics and mechanics is an ideal solid body that, under the influence of force, cannot change its properties, but can (under its influence) move in 3 dimensions (down, up, forward, etc.). etc., i.e. in our X-Y-Z axes), and also rotate in 3 dimensions (again along the X-Y-Z axes).

    In *Unity*, as in other game engines (again, I call them “game” engines roughly), *Rigidbody* is used for various objects that we can interact with by pushing, kicking, etc. Such objects under our influence will further roll, move and collide with other objects under the influence of gravity.

    What use can we find of this function? =
    For example, to create a car, in addition to *Rigidbody* we will need 4 Wheel Collider"a and *code* (*script*) that applies force to the wheels, depending on the keys pressed.

    • *Mass* - Mass of our object in kilograms. It is recommended not to set mass values ​​100 times greater or less than the masses of other *ATT*.
    • *Drag* - How much a body is subject to air resistance when it moves under the influence of forces. With a value of *0* there is no resistance, and an infinite value will instantly stop our object.
    • Angular Drag- How much a body is exposed to air resistance when it rotates under the influence of forces. With a value of *0* there is no resistance, and an infinite value will instantly stop the rotation of our object.
    • Use Gravity- When turned on, the object becomes subject to the influence of gravity.
    • Is Kinematic- When enabled, the object becomes unaffected by the physics engine and can only be changed by its *Transform* function. This can be useful for creating moving platforms, for example.
    • *Interpolate* - Applies only if the movements of your ATT seem strange or awkward to you, etc.:
    1. None: No interpolation applied
    2. Interpolate: Compared to the transformation of the previous frame (*frame*), the next one will be smoothed.
    3. Extrapolate: The transformation of the current frame is smoothed out in comparison with the estimated (approximate) transformation of the next one.
    • Freeze Rotation- Prohibits any rotation, both scripted and during collisions. However, rotation can be performed using the function // transform.Rotate()
    • Collision Detection- Used to prevent fast moving objects from passing through other objects without finding Collision"ov (a special "grid" on objects with which they collide with each other and with the player).
    1. Discrete: The default value is to ensure that our object “notices” all other objects that it may collide with.
    2. Continuous: Use Discrete Collision with dynamic collision objects (which have *ATT*), and Continuous Collision for static MeshCollider"ov (without *ATT*). Mode Continuous Dynamic uses Continuous Collision for one specific *ATT*. The rest of the *ATT* will use the _Discrete_ mode. (This will greatly impact the load on the physics engine, just leave _Discrete_ unless you have problems with fast objects colliding)
    3. Continuous Dynamic: Used for objects in _Continuous_ mode or Continuous Dynamic Collision. Continuous Collision will also be used for static MeshCollider"ov (without *ATT*). For all others, the _Discrete_ mode is used. Used for fast moving objects.

    How can we use this feature? =
    = Basic knowledge.
    To use *ATT*, we need an already created game object (*GameObject*), by clicking on it, we go to the menu along the following path: Components - Physics - Rigidbody . That's it, *ATT* added! :)
    Now the object is subject to gravity, you can apply forces to it using scripts, but in order for the object to behave exactly the way you want, you need to add a *Collider* or *Joint*.

    Code rules the world.
    In the script we will now manipulate our object using functions AddForce() And AddTorque() .
    Since I use *JavaScript* in *Unity*, my examples will be with it, links to other scripting examples (at C# or *Boo*) you will find below, in paragraph Additional information on ATT.

    Rigidbody.AddForce

    // Rigidbody.AddForce uses 2 types of formulas, like many other functions related to movement in space. // Type 1: function AddForce (force: Vector3, mode: ForceMode = ForceMode.Force) : void // Force that throws an object up relative to the global coordinate system. function FixedUpdate() (rigidbody.AddForce(Vector3.up * 10); ) // Uses Vector3, a built-in Unity function that is, in principle, similar to the standard coordinate system. // Type 2: function AddForce (x: float, y: float, z: float, mode: ForceMode = ForceMode.Force) : void // The same thing, but here the X-Y-Z coordinate system is used. function FixedUpdate() (rigidbody.AddForce(0, 10, 0); )

    Rigidbody.AddTorque

    // The function spins the object around a given axis. // Type 1: function AddTorque (torque: Vector3, mode: ForceMode = ForceMode.Force) : void // Spins the ATT around the global Y axis. function FixedUpdate () ( rigidbody.AddTorque (Vector3.up * 10); ) // Type 2: function AddTorque (x: float, y: float, z: float, mode: ForceMode = ForceMode.Force) : void // Does the same thing, but again in a different measurement system. function FixedUpdate() (rigidbody.AddTorque(0, 10, 0); )

    ATT interacts with objects.
    For our *ATT* to operate properly, they need to be equipped Collider"ami (or Collision"ami, as you please ^.^).
    Read more about colliders below.


    Size matters!
    Observe the dimensions of your object, because they are much more significant even than the *ATT* mass. If your object is moving incorrectly, hanging in the air, or not colliding, try adjusting its magnitude (not *ATT*, but the object itself). When importing a model from a 3D editor, its dimensions are preserved, so be careful at the modeling stage and respect the dimensions of all models.

    Additional Information by ATT =
    This is where I’ll probably finish describing *ATT* or *Rigidbody*. However, there are a couple of tips, especially for those who have made it all the way here :)

    1. The standard cube size in *Unity* is 1 meter, therefore, it is very convenient to check the size of your models using it. To create a cube, select from the menu GameObject - Create Other - Cube
    2. The relative *Mass* metric determines how two objects will interact with each other.
    3. *Mass* does not affect the speed of falling from a height; for these purposes, use *Drag*.
    4. The higher the *Drag* values, the more the item weighs. standard values ​​vary from 0.001(hard piece of metal) to 10(feather).
    5. If you need to modify an object both using scripts and using physics, add *ATT* to it with the *Kinematic* parameter.

    You can view scripted examples of the influence of external forces on an object with the *ATT* function at the following links:
    *AddForce*
    *AddTorque*

    To change the script example, click on the text with the name of the programming language!

    Colliders
    =
    = What is this? =
    In the previous section, we looked at the principle of operation of *Rigidbody* and mentioned the so-called *colliders*. *Collider* for us is an auxiliary object in the form of a grid of a simple primitive or, conversely, complex shape, which is located around our model or part of the model and interacts with other objects if they are also surrounded by colliders.
    To clearly explain to connoisseurs of the *Warcraft 3* world editor, imagine the model we imported, to which we did not assign path textures in the dudad editor - this will be our object; and the role of colliders here will be played by blockers of the path around the model. Naturally, this is a rather rough comparison, because in *Unity* they are much more functional. Well, let's take a closer look.

    Types of colliders. =
    Colliders are added through the menu Component - Physics . There are several types:

    • Box Collider- in the shape of a cube.
    • Sphere Collider- in the shape of a sphere.
    • Capsule Collider- in capsule form.
    • Mesh Collider- automatically creates a collider based on the shape of the object's mesh; it cannot collide with other colliders of the same type. Mainly used for static objects, such as a race track environment.
    • Wheel Collider- used for wheels, a very useful thing.
    • Compound Collider- combinations of primitives that together act as one. To create such a complex collider, you need to add child objects to our base collider, and then bind them to them using a primitive. Thus, for example, it is very convenient to make simple colliders for cars.


    Custom Features =
    In principle, all colliders are similar to each other, they are simply used for objects of different shapes, however they have several different parameters.

    • *Cube*

    * *Material* - Shows how the collider interacts with other objects, while assigning a physical material, for example, metal, ice, etc.
    * Is Trigger- If the parameter is enabled, then the object is affected by the script, not physics.
    * *Size* - The size of the collider along the X-Y-Z axes.
    * *Center* - The position of the collider, relative to the local coordinates of the object.

    • *Sphere*

    * *Radius* - Radius of the sphere, replaces the *Size* parameter.
    * Other parameters remain unchanged.

    • *Capsule* (parameters replace size)

    * *Radius* - Capsule thickness.
    * *Height* - The height of the cylindrical part of the collider (without rounded bases).
    * *Direction* - Direction of the collider, relative to the local coordinates of the object.


    • Mesh Collider(parameters replace size)

    * *Mesh* - Select the desired mesh to create a collider.
    * Smooth Sphere Collisions - Enabling this feature smoothes the surface of the collider. It should be used on smooth surfaces, for example, an inclined landscape without unnecessary angularity, along which the spheres should roll.
    * *Convex* - When enabled, allows our collider to collide with others of the same kind. Convex Mesh Collider"s are limited to 255 triangles.

    • Wheel Collider(parameters replace size)

    * *Radius* - Wheel radius.
    * Suspension Distance- Maximum distance to increase wheel suspension. The suspension always increases down the local *Y* axis.
    * Suspension Spring- The suspension tries to reach the specified point using various forces.

    1. Spring: Attempts to reach the specified point (position). The higher the parameter, the faster it is achieved.
    2. Damper: Softens, slows down the speed of the suspension. The higher the value, the slower the shock absorber moves.
    3. Target Position: The total "path" the pendant can "travel". *0* means the shock absorber is fully extended, and *1* means it is fully compressed. The default value is 0, which corresponds to a normal car suspension.

    * *Mass* - Wheel mass.
    * Forward/Sideways Friction - Friction parameters when the wheel simply rolls and when it rolls sideways (this happens in skids or during drifting).

    We are writing Arkanoid in Unity. Ball and platform mechanics

    So, we continue the series of articles about writing a simple game in Unity - a classic arkanoid. We will only use 2D tools provided to us by the engine. In each of the articles we will touch on one of the aspects of writing a game, and in this one we will set in motion the ball and the platform under the control of the player.

    Here is a list of all articles:

    1. Mechanics of ball and platform.

    Where are we staying?

    In the previous lesson, we set up a project, transferred resources into it, and created the first simple scene. If you have not read, we strongly recommend that you correct this defect.

    Result preview

    Platform movement

    We already have the platform itself - we created it in the last lesson. All that remains is to teach her to move, and exclusively to the left or to the right, i.e. along the X axis. To do this we will need to write a script ( Script).

    Scripts are pieces of program code that are responsible for some specific task. Unity can work with scripts written in three programming languages: Boo, JavaScript and C#. We'll use the latter, but you can try your hand at other languages.

    So, to create a script, let's go to the tab Project, find the folder of the same name there Scripts and click on it right click mice. Let's choose Create -> C# Script. A new file will appear called NewBehaviourScript. Rename it PlayerScript for convenience. On the tab Inspector you can see the contents of the script.

    Double click to open the script. The MonoDevelop development environment will launch, which you can later change to any editor convenient for you. Here's what you'll see:

    Using UnityEngine; using System.Collections; public class NewBehaviourScript: MonoBehaviour ( // use this method to initialize void Start () ( ) // Update is called when every frame of the game is rendered void Update () ( ) )

    All Unity scripts have two methods by default:

    • Start(): Used to initialize the variables or parameters we need in the code.
    • Update(): Called every frame of the game, needed to update the game state.

    In order to move the platform, we need two types of information: position and speed.

    So you need to create two variables to store this information:

    public float playerVelocity;
    private Vector3 playerPosition;

    Note that one variable is declared publicly and the other is private. Why is this being done? The fact is that Unity allows you to edit the values ​​of public variables without going to the MonoDevelop editor, without the need to change the code. This feature is very useful in those cases. when it is necessary to adjust some value “on the fly”. Platform speed is one of those values, and that's why we announced it publicly.

    Save the script in the MonoDevelop editor and go to the Unity editor. Now we have a script and we need to assign it to some object, in our case the platform. Select our platform in the tab Hierarchy and in the window Inspector add a component by clicking the button Add Component.

    Adding our script to the component can be done in another way. Drag our script into the button area Add Component. In the tab Inspector you should see something like this:

    Please note that a field has appeared in the script component Player Velocity, which can be changed immediately. This was made possible thanks to the public declaration of the variable. Set the parameter to 0.3 and go to the MonoDevelop editor.

    Now we need to find out the position of the platform: playerPosition. To initialize a variable, you must access the script object in the Start() method:

    // use this method to initialize void Start() ( // get the starting position of the platform playerPosition = gameObject.transform.position; )

    Great, we have determined the starting position of the platform, and now we can move it. Since we only need the platform to move along the X axis, we can use the GetAxis method of the Input class. We will pass the string Horizontal to this function, and it will return 1 if the “right” key was pressed, and -1 if the “left” key was pressed. By multiplying the resulting number by the speed and adding this value to the player’s current position, we get movement.

    We will also add a check for exiting the application by pressing the Esc key.

    This is what we should end up with:

    Using UnityEngine; using System.Collections; public class PlayerScript: MonoBehaviour ( public float playerVelocity; private Vector3 playerPosition; // use this method to initialize void Start () ( // get the starting position of the platform playerPosition = gameObject.transform.position; ) // Update is called when every frame of the game is rendered void Update () ( // horizontal movement playerPosition.x += Input.GetAxis ("Horizontal") * playerVelocity; // exit the game if (Input.GetKeyDown(KeyCode.Escape))( Application.Quit(); ) / / update the platform position transform.position = playerPosition; ) )

    Save the script and return to the Unity editor. Click the button Play and try to move the platform using the left and right buttons.

    Defining the Play Area

    You most likely noticed that the platform can move outside playing field. The fact is that we do not have any checks for going beyond any boundaries.

    Let's add another public variable to our existing script and call it boundary .

    This variable will store the maximum coordinate of the platform along the X axis. Since we are going to build levels in a symmetrical form around a point with coordinates (0, 0, 0), the absolute value of the boundary variable will be the same for both the positive part of the X axis and the negative one.

    Now let's add a couple of conditions. Let's do it quite simply: if the position we calculated is greater than boundary or less than -boundary , then we simply set new position along the X axis, equal to the value of the boundary variable. In this way, we guarantee that the platform will not travel beyond our borders and will never leave the playing area. Here's the code:

    Using UnityEngine; using System.Collections; public class PlayerScript: MonoBehaviour ( public float playerVelocity; private Vector3 playerPosition; // use this method to initialize void Start () ( // get the starting position of the platform playerPosition = gameObject.transform.position; ) // Update is called when every frame of the game is rendered void Update () ( // horizontal movement playerPosition.x += Input.GetAxis ("Horizontal") * playerVelocity; // exit the game if (Input.GetKeyDown(KeyCode.Escape))( Application.Quit(); ) / / update the platform position transform.position = playerPosition; // check for out-of-bounds if (playerPosition.x< -boundary) { transform.position = new Vector3 (-boundary, playerPosition.y, playerPosition.z); } if (playerPosition.x >boundary) ( transform.position = new Vector3(boundary, playerPosition.y, playerPosition.z); ) ) )

    Now go back to the editor and, switching to the game, find optimal value boundary variable. In our case, the number 5.46 came up. Open Inspector and reset the platform's X position to 0 and the parameter Boundary set according to the value you found.

    Click the button Play and make sure you did everything correctly. The platform must only move within the playing field.

    Enabling physics

    To make the collisions more realistic, we will use physics simulation. In this article we will add physical properties ball, platform and field boundaries. Since we are writing a 2D game, we will use 2D colliders. A collider is a separate type of component that allows an object to react to the colliders of other objects.

    In the window Hierarchy select our platform, go to Inspector and press the button Add Component. In the window that appears, type collider. As you can see, there are quite a lot of options. Each collider has specific properties corresponding to the associated objects - rectangles, circles, etc.

    Since our platform is rectangular in shape, we will use Box Collider 2D. Select it, and the component will automatically determine the dimensions of the platform: you will not need to set them manually, Unity will do it for you.

    Do the same for 3 borders ( Hierarchy -> Inspector -> Add Component -> Box Collider 2D).

    The ball is a little different: it has a round shape. Let's select the ball and add a component for it Circle Collider 2D.

    In fact, the circle and rectangle collider are very similar, except that instead of the parameter Size, which determines the width and length, is used in a circle Radius. Explanations here, we think, are unnecessary.

    Elastic collision

    In order for our ball to bounce off blocks, walls and platforms, we need to set the surface (material) for the physical component added earlier. Unity already has everything, we just need to add the necessary material.

    Open the window Project and inside the folder Asset create a new folder called Physics. Right-click on the newly created folder and select Create -> Physics2D Material. Set the name to BallPhysicsMaterial .

    Each surface in Unity has two parameters: friction (friction) and elasticity (bounciness). You can read more about the physics engine and series physical parameters. If you need a completely elastic body, then you should set friction to 0 and elasticity to 1.

    Now we have ready-made material, but it has nothing to do with the ball yet. Select the ball object in the tab Hierarchy and in the window Inspector you will see a field Material component Circle Collider 2D. Drag your newly created content here.

    Adding a Component Rigid Body

    In order for our ball to move under the control of physics, we must add one more component to it: Rigid Body 2D. Select the ball object in the window Hierarchy and add the above component - although it has several parameters, we are only interested in one: Gravity Scale. Since our ball will only move due to bounces, we will set this parameter to 0 - this way we guarantee that gravity will not react to the object. Everything else can be left unchanged.

    Ball behavior

    Let's create a separate script for the ball (again using C# as a programming language) and call it BallScript. Associate the created script with an object ( Hierarchy -> Inspector -> Add Component).

    Before we start writing the script, let's define the behavior of the ball:

    1. The ball has two states: inactive (when it is on the platform at the beginning of the game) and active (when it is in motion).
    2. The ball will only become active once.
    3. When the ball becomes active, we apply a force to it so that it begins to move.
    4. If the ball goes out of bounds of the playing field, it is rendered inactive and placed on the platform.

    Based on this information, let's create global variables ballIsActive , ballPosition and ballInitialForce:

    private bool ballIsActive;
    private Vector3 ballPosition;
    private Vector2 ballInitialForce;

    Now that we have a set of variables, we need to prepare the object. In the Start() method we must:

    • create a force that will be applied to the ball;
    • transfer the ball to an inactive state;
    • remember the position of the ball.

    Here's how to do it:

    Void Start () ( // create a force ballInitialForce = new Vector2 (100.0f,300.0f); // transfer to inactive state ballIsActive = false; // remember the position ballPosition = transform.position; )

    As you may have noticed, the force applied is not strictly vertical, but inclined to the right - the ball will move diagonally.

    Void Update () ( // check if the space bar is pressed if (Input.GetButtonDown ("Jump") == true) ( ​​) )

    The next step is to check the state of the ball, since we only need to set the force if the ball is in an inactive state:

    Void Update () ( // checking if the spacebar is pressed if (Input.GetButtonDown ("Jump") == true) ( ​​// checking the state if (!ballIsActive)( ) ) )

    Assuming that we are at the beginning of the game, then we must apply a force to the ball and set it to the active state:

    Void Update () ( // check if the space bar is pressed if (Input.GetButtonDown ("Jump") == true) ( ​​// check the state if (!ballIsActive)( // apply the force rigidbody2D.AddForce(ballInitialForce); // set active state ballIsActive = !ballIsActive;

    If you now turn on the game, pressing the spacebar will actually start the ball moving. However, you may notice that the ball in its inactive state does not behave quite correctly: if we move the platform, the ball should move with it, but in fact remains in the same position. Stop the game, let's fix this.

    In the Update method, we must check the state of the ball, and if it is inactive, we need to set the position of the ball along the X axis to be the same as that of the platform.

    The solution is quite simple, but how do we get the coordinates of a completely different object? Elementary - we will create a variable of type GameObject and save a reference to the platform object:

    public GameObject playerObject;

    Let's go back to the Update() method:

    Void Update () ( // check if the space bar is pressed if (Input.GetButtonDown ("Jump") == true) ( ​​// check the state if (!ballIsActive)( // apply the force rigidbody2D.AddForce(ballInitialForce); // set active state ballIsActive = !ballIsActive; ) if (!ballIsActive && playerObject != null)( // set the new position of the ball ballPosition.x = playerObject.transform.position.x; // set the position of the ball transform.position = ballPosition; ) ) )

    Save the script and return to the Unity editor. You probably noticed that the playerObject variable is declared, used, but not initialized anywhere. Yes, that is right. To initialize it, go to the tab Hierarchy, find the ball and in the window Inspector find the component Ball Script. This component has a parameter PlayerObject, currently empty:

    Find in the tab Hierarchy our platform and drag it onto the field PlayerObject. Start the game by pressing the button Play, and make sure everything works.

    Game reset

    If at this stage you start the game and lose (so that the ball falls out of bounds), then nothing will return to normal. But in fact, the game state should be reset. Let's fix this.

    This state is very easy to catch: the ball will be active, and its position along the Y axis will be negative. If this is the case, then we turn the ball into an inactive state and place it on the platform:

    If (ballIsActive && transform.position.y< -6) { ballIsActive = !ballIsActive; ballPosition.x = playerObject.transform.position.x; ballPosition.y = -4.2f; transform.position = ballPosition; }

    But this is not the end. After saving the script and starting the game, you will notice that each time you restart the level, the ball gains more and more power. Why is this happening? The point is that we are not clearing the forces applied to the ball. To correct this shortcoming, we can use the IsKinematic parameter, turning it off before adding force and turning it on after the fall.

    This is what our final Update() method came out with:

    Public class BallScript: MonoBehaviour ( private bool ballIsActive; private Vector3 ballPosition; private Vector2 ballInitialForce; // GameObject public GameObject playerObject; // use this method to initialize void Start () ( // create the force ballInitialForce = new Vector2 (100.0f,300.0 f); // switch to inactive state ballIsActive = false; // remember the position ballPosition = transform.position) void Update () ( // check for pressing the spacebar if (Input.GetButtonDown ("Jump") == true) ( // check the state if (!ballIsActive)( // reset all forces rigidbody2D.isKinematic = false; // apply the force rigidbody2D.AddForce(ballInitialForce); // set the active state ballIsActive = !ballIsActive; ) if (!ballIsActive && playerObject ! = null)( // set a new position of the ball ballPosition.x = playerObject.transform.position.x; // set the position of the ball transform.position = ballPosition; ) // check if the ball falls if (ballIsActive && transform.position.y< -6) { ballIsActive = !ballIsActive; ballPosition.x = playerObject.transform.position.x; ballPosition.y = -4.2f; transform.position = ballPosition; rigidbody2D.isKinematic = true; } } }

    But now that’s all for sure. Launch the game and check if everything works as expected.

    In the next part

    So, the second article has come to an end. Now you have learned how to work with scripts, colliders and the keyboard. Next time we'll talk about the mechanics of game blocks.



    Backgammon