Создание управляемого персонажа
Let's create a playable robot that can move around the Play Area and collide with objects or wall obstacles. Our character will fly above the floor and rotate to face the cursor.Давайте создадим робота, который может перемещаться по игровой зоне и сталкиваться с объектами или стенами. Наш персонаж будет летать над полом и поворачиваться лицом к курсору.
Step 1. Engage Physics for Robot's ModelШаг 1. Включение физики для модели робота#
The robot with a complex 3D model will represent the playable character in the game. We have already imported the Node Reference with the Skinned Mesh, the flying animation, and materials for the robot.Робот со сложной 3D-моделью будет представлять игрового персонажа в игре. Мы уже импортировали Node Reference со Skinned Mesh, анимацию полета и материалы для робота.
The robot must be able to move around the Play Area and collide with static and physical objects. In order to do so, it should have a physical body and a collision shape approximating its volume.Робот должен уметь перемещаться по игровой площадке и сталкиваться со статическими и физическими объектами. Для этого он должен иметь физическое тело и коллизионную форму, приблизительно соответствующую его контурам.
-
Place the imported programming_quick_start\character\robot\robot.node on the floor inside the Play Area by dragging it from the Asset Browser directly to the Editor Viewport. Поместите импортированную ноду programming_quick_start\character\robot\robot.node на пол внутри игровой зоны, перетащив ее из Asset Browser непосредственно в Editor Viewport.
-
With the robot node selected click Edit in the Reference section of the Parameters window. The Node Reference shall open and the current selection shall focus on the robot ObjectMeshSkinned node. Now switch to the Physics tab of the Parameters window and assign a Rigid body to the selected ObjectMeshSkinned.При выбранной ноде robot щелкните Edit в разделе Reference окна Parameters. Откроется Node Reference, и текущий выбор должен быть сфокусирован на ноде robot ObjectMeshSkinned. Теперь переключитесь на вкладку Physics окна Parameters и назначьте тело Rigid выбранному ObjectMeshSkinned.
- Set LDamping parameter to 5.0 to make sure that the robot will lose speed over time.Установите для параметра LDamping значение 5.0, чтобы убедиться, что робот со временем будет терять скорость.
-
Scroll down to the Shapes section and add a Capsule shape to the body.Прокрутите вниз до раздела Shapes и добавьте форму Capsule к телу.
The capsule shape will be used as an approximation volume for collisions with other objects in the world.Форма капсулы будет использоваться в качестве приблизительного объема для столкновений с другими объектами в мире.
Step 2. Set Up ControlsШаг 2. Настройка элементов управления#
We will apply a linear impulse to the body to move the robot with keyboard WASD keys. The robot's motion will be determined according to the camera's orientation. Also, let's restrict the physics-based rotation and vertical movement to avoid unwanted control behavior.Мы приложим линейный импульс к телу, чтобы переместить робота с помощью клавиш клавиатуры WASD. Движение робота будет определяться в соответствии с ориентацией камеры. Кроме того, давайте ограничим вращение и вертикальное перемещение, основанные на физике, чтобы избежать нежелательного поведения при управлении.
To orient the robot to face the cursor, we will use one of the intersection types called World Intersection. It will trace a line from the cursor position to the floor to get an intersection point that will be used as a reference for the robot's rotation. You can read more about managing various intersections here.Чтобы сориентировать робота лицом к курсору, мы будем использовать один из типов пересечений, называемый World Intersection. Он проведет линию от положения курсора до пола, чтобы получить точку пересечения, которая будет использоваться в качестве ориентира для вращения робота. Вы можете прочитать больше об управлении различными пересечениями здесь.
The best way to manage keyboard and mouse inputs, is to use the Input class. It enables you to check the state of the buttons and get the current mouse coordinates. Alternative methods for input handling are described here.Лучший способ управлять вводом с клавиатуры и мыши — это использовать класс Input. Это позволяет вам проверить состояние кнопок и получить текущие координаты мыши. Альтернативные методы обработки входных данных описаны здесь.
Let's use the C# Component System to implement this logic. We will create a C# component and assign it to the robot's node in the world.Давайте используем Компонентную систему C# для реализации этой логики. Мы создадим C# компонент и назначим его ноде robot в мире.
-
In the Asset Browser right-click and choose Create Code->C# Component and call it PlayerController.Щелкните правой кнопкой мыши в Asset Browser и выберите Create Code->C# Component, назовите компонент PlayerController.
-
Select the robot node (ObjectMeshSkinned), then click Add New Component or Property in the Parameters window and assign the PlayerController component.Выберите ноду robot (ObjectMeshSkinned), затем щелкните Add New Component or Property в окне Parameters и назначьте компонент PlayerController.
Make sure you assign the component to the ObjectMeshSkinned node inside the NodeReference!Убедитесь в том, что назначаете компоненту именно ноде ObjectMeshSkinned, находящейся внутри NodeReference! -
Open your IDE to edit the component by double-clicking on the created PlayerController.cs in the Asset Browser and сopy the code below.Откройте IDE, чтобы отредактировать компонент, дважды щелкнув по созданному PlayerController.cs в Asset Browser и скопируйте приведенный ниже код.
It is recommended to use VS Code as a default IDE.Рекомендуется использовать VS Code в качестве IDE по умолчанию.using System; using System.Collections; using System.Collections.Generic; using Unigine; #if UNIGINE_DOUBLE using Vec3 = Unigine.dvec3; using Mat4 = Unigine.dmat4; using Scalar = System.Double; #else using Vec3 = Unigine.vec3; using Mat4 = Unigine.mat4; using Scalar = System.Single; #endif [Component(PropertyGuid = "AUTOGENERATED_GUID")] // <-- this line is generated automatically for a new component public class PlayerController : Component { Player player; BodyRigid rigid; Vec3 pos; //a WorldIntersection object to store the information about the intersection WorldIntersection intersection = new WorldIntersection(); void Init() { player = Game.Player; rigid = node.ObjectBodyRigid; rigid.AngularScale = new vec3(0.0f, 0.0f, 0.0f); // restricting the rotation rigid.LinearScale = new vec3(1.0f, 1.0f, 0.0f); // restricting Z movement rigid.MaxLinearVelocity = 8.0f; // clamping the max linear velocity } void UpdatePhysics() { // forward if (Input.IsKeyPressed(Input.KEY.W)) Move(player.GetWorldDirection(MathLib.AXIS.Y)); // backward if (Input.IsKeyPressed(Input.KEY.S)) Move(player.GetWorldDirection(MathLib.AXIS.NY)); // left if (Input.IsKeyPressed(Input.KEY.A)) Move(player.GetWorldDirection(MathLib.AXIS.NX)); // right if (Input.IsKeyPressed(Input.KEY.D)) Move(player.GetWorldDirection(MathLib.AXIS.X)); // finding the positions of the cursor and the point moved 100 units away in the camera forward direction ivec2 mouse = Input.MousePosition; Vec3 p0 = player.WorldPosition; Vec3 p1 = p0 + new Vec3(player.GetDirectionFromMainWindow(mouse.x, mouse.y)) * 100; // casting a ray from p0 to p1 to find the first intersected object Unigine.Object obj = World.GetIntersection(p0, p1, 1, intersection); // the first bit of the intersection mask is set to 1, the rest are 0s // finding the intersection position, creating a transformation matrix to face this position and setting the transofrm matrix for the body preserving angular and linear velocities if (obj) { pos = intersection.Point; pos.z = rigid.Transform.Translate.z; // project the position vector to the Body Rigid pivot plane Mat4 transform = MathLib.SetTo(rigid.Transform.Translate, pos, vec3.UP, MathLib.AXIS.Y); rigid.SetPreserveTransform(transform); } } // moving the rigid body with linear impulse in the specified direction void Move(vec3 direction) { //directon is a normalized camera axis vector rigid.AddLinearImpulse(direction); } }
You can copy this sample code and paste it to your source files, however, be careful not to change the values of the default [Component(PropertyGuid = "")] attributes.Вы можете скопировать этот пример кода и вставить его в свои исходные файлы, но значение атрибута [Component(PropertyGuid = "")] изменяться не должно. -
Return to the UnigineEditor. The PlayerController component will be automatically reimported, since it just has been changed. After the Reimport process, you will receive a prompt message, indicating the results of the C# Component System compilation.Вернитесь в UnigineEditor. Компонент PlayerController автоматически реимпортируется, поскольку он только что был изменен. После процесса повторного импорта вы получите сообщение с подсказкой, указывающее на результаты компиляции системы компонентов C#.
If you encounter the red error message in the Editor, indicating that some of the C# components were not built, check the Editor's Console window for details.Если вы видите красное сообщение об ошибке в редакторе, указывающее на то, что какие-то компоненты C# не собрались, проверьте окно Console редактора для получения подробной информации. - Press Ctrl+S to save the world and the robot's NodeReference.Нажмите Ctrl+S, чтобы сохранить мир и NodeReference робота.
Step 3. Finalize and RunШаг 3. Завершение и запуск#
- Turn off the Intersection detection for every surface of the robot node to ignore intersections with the robot's own surfaces, as we do not want it in our robot's rotation implementation.Отключите обнаружение пересечений для каждой поверхности ноды робота, чтобы игнорировать пересечения с собственными поверхностями робота, так как мы не хотим, чтобы они учитывались при реализации вращения нашего робота.
-
For every wall object in the world, go to the Parameters window and find the Surfaces section in the Node tab. Select the box surface of the mesh and open an Intersection Mask window. Uncheck the first Intersection Mask 0 bit to make sure that walls will not affect the player's character turning.Для каждого объекта стены в мире перейдите в окно Parameters и найдите раздел Surfaces на вкладке Node. Выберите поверхность box меша и откройте окно Intersection Mask. Снимите флажок с первого бита Intersection Mask 0, чтобы стены не влияли на поворот персонажа игрока.
- To make the cursor always visible, go to Windows->Settings->Controls section, change the Mouse Handle mode to User. You can also control the cursor via API.Чтобы курсор всегда был виден, перейдите в раздел Windows->Settings->Controls, измените режим Mouse Handle на User. Вы также можете управлять курсором с помощью API.
- Save changes to the world and the robot via File->Save World (or press Ctrl+S hotkey).Сохраните изменения мира и робота с помощью File->Save World (или нажмите горячую клавишу Ctrl+S).
Now build and run the game in the UnigineEditor to try out the robot's controls.Теперь создайте и запустите игру в UnigineEditor, чтобы опробовать управление роботом.