This page has been translated automatically.
Видеоуроки
Интерфейс
Основы
Продвинутый уровень
Подсказки и советы
Основы
Программирование на C#
Рендеринг
Профессиональный уровень (SIM)
Принципы работы
Свойства (properties)
Компонентная Система
Рендер
Физика
Редактор UnigineEditor
Обзор интерфейса
Работа с ассетами
Контроль версий
Настройки и предпочтения
Работа с проектами
Настройка параметров ноды
Setting Up Materials
Настройка свойств
Освещение
Sandworm
Использование инструментов редактора для конкретных задач
Расширение функционала редактора
Встроенные объекты
Ноды (Nodes)
Объекты (Objects)
Эффекты
Декали
Источники света
Geodetics
World-ноды
Звуковые объекты
Объекты поиска пути
Player-ноды
Программирование
Основы
Настройка среды разработки
Примеры использования
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Плагины
Форматы файлов
Материалы и шейдеры
Rebuilding the Engine Tools
Интерфейс пользователя (GUI)
Двойная точность координат
API
Animations-Related Classes
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
VR-Related Classes
Работа с контентом
Оптимизация контента
Материалы
Визуальный редактор материалов
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Учебные материалы

Создание управляемого персонажа

Давайте создадим робота, который может перемещаться по игровой зоне и сталкиваться с объектами или стенами. Наш персонаж будет летать над полом и поворачиваться лицом к курсору.

Шаг 1. Включение физики для модели робота#

Робот со сложной 3D-моделью будет представлять игрового персонажа в игре. Мы уже импортировали Node Reference со Skinned Mesh, анимацию полета и материалы для робота.

Робот должен уметь перемещаться по игровой площадке и сталкиваться со статическими и физическими объектами. Для этого он должен иметь физическое тело и коллизионную форму, приблизительно соответствующую его контурам.

  1. Поместите импортированную ноду programming_quick_start\character\robot\robot.node на пол внутри игровой зоны, перетащив ее из Asset Browser непосредственно в Editor Viewport.

  2. При выбранной ноде robot щелкните Edit в разделе Reference окна Parameters. Откроется Node Reference, и текущий выбор должен быть сфокусирован на ноде robot ObjectMeshSkinned. Теперь переключитесь на вкладку Physics окна Parameters и назначьте тело Rigid выбранному ObjectMeshSkinned.

  3. Установите для параметра LDamping значение 5.0, чтобы убедиться, что робот со временем будет терять скорость.
  4. Прокрутите вниз до раздела Shapes и добавьте форму Capsule к телу.

Форма капсулы будет использоваться в качестве приблизительного объема для столкновений с другими объектами в мире.

Шаг 2. Настройка элементов управления#

Мы приложим линейный импульс к телу, чтобы переместить робота с помощью клавиш клавиатуры WASD. Движение робота будет определяться в соответствии с ориентацией камеры. Кроме того, давайте ограничим вращение и вертикальное перемещение, основанные на физике, чтобы избежать нежелательного поведения при управлении.

Чтобы сориентировать робота лицом к курсору, мы будем использовать один из типов пересечений, называемый World Intersection. Он проведет линию от положения курсора до пола, чтобы получить точку пересечения, которая будет использоваться в качестве ориентира для вращения робота. Вы можете прочитать больше об управлении различными пересечениями здесь.

Лучший способ управлять вводом с клавиатуры и мыши — это использовать класс Input. Это позволяет вам проверить состояние кнопок и получить текущие координаты мыши. Альтернативные методы обработки входных данных описаны здесь.

Давайте используем Компонентную систему C++ для реализации этой логики. Мы создадим компонент C++ и назначим его на ноду робота в мире.

  1. Чтобы начать писать код, мы должны открыть наш проект в IDE. Перейдите к SDK Browser и выберите Open Code IDE.
  2. В среде IDE создайте новый класс C++ (файлы *.h и *.cpp) и назовите его PlayerController. Убедитесь, что он наследуется от класса Unigine::ComponentBase.

  3. Скопируйте приведенный ниже код и вставьте его в соответствующие файлы в вашем проекте и сохраните их в вашей IDE.

    Примечание
    Рекомендуется использовать Visual Studio в качестве IDE по умолчанию.
    PlayerController.h (C++)
    #pragma once
    #include <UnigineComponentSystem.h>
    
    #include <UnigineGame.h>
    #include <UnigineControls.h>
    #include <UnigineStreams.h>
    #include <UniginePlayers.h>
    #include <UnigineWorld.h>
    #include <UnigineConsole.h>
    #include <UnigineMathLib.h>
    #include <UnigineRender.h>
    
    class PlayerController : public Unigine::ComponentBase
    {
    public:
    	// declare constructor and destructor for our class and define a property name. 
    	COMPONENT_DEFINE(PlayerController, ComponentBase)
    	// declare methods to be called at the corresponding stages of the execution sequence
    	COMPONENT_INIT(init); 
    	COMPONENT_UPDATE_PHYSICS(updatePhysics);
    
    protected:
    	void init();
    	void updatePhysics();
    
    private:
    	void move(const Unigine::Math::vec3& direction);
    
    	Unigine::BodyRigidPtr rigid;
    
    	Unigine::PlayerPtr player;
    
    	// a WorldIntersection object to store the information about the intersection
    	Unigine::WorldIntersectionPtr intersection = Unigine::WorldIntersection::create();
    
    	Unigine::Math::Vec3 pos;
    
    };
    PlayerController.cpp (C++)
    #include "PlayerController.h"
    using namespace Unigine;
    using namespace Math;
    
    REGISTER_COMPONENT(PlayerController);
    
    void PlayerController::init()
    {
    	player = Game::getPlayer();
    
    	if (node)
    	{
    		rigid = node->getObjectBodyRigid();
    		if (rigid)
    		{
    			rigid->setAngularScale(vec3(0.0f, 0.0f, 0.0f)); // restricting the rotation
    			rigid->setLinearScale(vec3(1.0f, 1.0f, 0.0f)); // restricting Z movement
    			rigid->setMaxLinearVelocity(8.0f); // clamping the max linear velocity
    		}
    
    	}
    }
    
    void PlayerController::updatePhysics()
    {
    	if (!Console::isActive())  // do not process input if the console is shown
    	{
    		// check if W key is pressed
    		if (Input::isKeyPressed(Input::KEY::KEY_W))
    			move(player->getWorldDirection(MathLib::AXIS::AXIS_Y)); // move forward
    
    		// check if S key is pressed
    		if (Input::isKeyPressed(Input::KEY::KEY_S))
    			move(player->getWorldDirection(MathLib::AXIS::AXIS_NY)); // move backward
    
    		// check if A key is pressed
    		if (Input::isKeyPressed(Input::KEY::KEY_A))
    			move(player->getWorldDirection(MathLib::AXIS::AXIS_NX)); // move left
    
    		// check if D key is pressed
    		if (Input::isKeyPressed(Input::KEY::KEY_D))
    			move(player->getWorldDirection(MathLib::AXIS::AXIS_X)); // move right
    
    		// finding the positions of the cursor and the point moved 100 units away in the camera forward direction 
    		ivec2 mouse = Input::getMousePosition();
    		Vec3 p0 = player->getWorldPosition();
    
    		Vec3 p1 = p0 + Vec3(player->getDirectionFromMainWindow(mouse.x, mouse.y)) * 100;
    
    		// casting a ray from p0 to p1 to find the first intersected object
    		ObjectPtr 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 transform matrix for the body preserving current angular and linear velocities
    		if (obj && rigid)
    		{
    			pos = intersection->getPoint();
    			pos.z = rigid->getTransform().getTranslate().z; // project the position vector to the Body Rigid pivot plane
    			Mat4 transform = Math::setTo(rigid->getTransform().getTranslate(), pos, vec3_up, AXIS::AXIS_Y);
    			rigid->setPreserveTransform(transform); // turn the character's body
    		}
    	}
    }
    
    // moving the rigid body with linear impulse in the specified direction
    void PlayerController::move(const Unigine::Math::vec3& direction)
    {
    	// direction is a normalized camera axis vector 
    	if (rigid)
    		// direction is a normalized camera axis vector 
    		rigid->addLinearImpulse(direction);
    }
  4. Чтобы использовать компоненты C++, нужно инициализировать систему компонентов. Измените метод init() класса AppSystemLogic, как показано ниже (файл AppSystemLogic.cpp). Также включите автоматическую распаковку NodeReference для удобства.

    AppSystemLogic.cpp (C++)
    #include <UnigineComponentSystem.h>
    
    using namespace Unigine;
    
    int AppSystemLogic::init()
    {
    	// initialize ComponentSystem and register all components
    	ComponentSystem::get()->initialize();
    
    	// unpack node references to find child nodes by name
    	World::setUnpackNodeReferences(true);
    
    	return 1;
    }
  5. Соберите и запустите проект с помощью вашей IDE (нажмите Ctrl + F5 в Visual Studio), система компонентов сгенерирует файл свойств для компонента.
  6. Переключитесь обратно в UnigineEditor и выберите ноду robot (ObjectMeshSkinned) в окне World Nodes. Затем щелкните Add New Property в окне Parameters и назначьте вновь созданное свойство на PlayerController.

    Примечание
    Убедитесь в том, что назначаете свойство именно ноде ObjectMeshSkinned, находящейся внутри NodeReference!

Шаг 3. Завершение и запуск#

  1. Отключите обнаружение пересечений для каждой поверхности ноды робота, чтобы игнорировать пересечения с собственными поверхностями робота, так как мы не хотим, чтобы они учитывались при реализации вращения нашего робота.
  2. Для каждого объекта стены в мире перейдите в окно Parameters и найдите раздел Surfaces на вкладке Node. Выберите поверхность box меша и откройте окно Intersection Mask. Снимите флажок с первого бита Intersection Mask 0, чтобы стены не влияли на поворот персонажа игрока.

  3. Чтобы курсор всегда был виден, перейдите в раздел Windows->Settings->Controls, измените режим Mouse Handle на User. Вы также можете управлять курсором с помощью API.
  4. Сохраните изменения мира и робота с помощью File->Save World (или нажмите горячую клавишу Ctrl+S).

Соберите и запустите игру в своей среде разработки, чтобы опробовать управление роботом.

Примечание
Чтобы запустить отладочную версию вашего проекта из браузера SDK, включите режим Debug в Customize Run Options.
Последнее обновление: 27.02.2024
Build: ()