Replicando a física do personagem Quake 3 com U3D – Programação geral e de jogabilidade – Tutoriais

A física do controlador de personagem do mecanismo de jogo Quake 3 Arena é responsável por lidar com o movimento e a detecção de colisão do personagem do jogador. Essas físicas são projetadas para simular o movimento de um personagem de tiro em primeira pessoa (FPS) em um ambiente 3D e são baseadas em uma combinação de física cinemática e dinâmica.

Alguns dos principais recursos da física do controlador de personagem do Quake 3 Arena incluem:

  • Altura do degrau: o personagem pode subir em superfícies de até uma certa altura, permitindo-lhe passar por cima de obstáculos.
  • Limite de inclinação: o personagem pode andar em superfícies inclinadas até um determinado ângulo, mas deslizará em superfícies mais íngremes.
  • Gravidade: o personagem é afetado pela gravidade, então ele cairá se não estiver em uma superfície sólida.
  • Controle aéreo: o personagem pode ajustar sua velocidade horizontal enquanto estiver no ar, permitindo que ele dê saltos no ar e controle sua aterrissagem.
  • Atrito: o movimento do personagem é afetado pelo atrito, então eles vão desacelerar em superfícies escorregadias e parar em superfícies ásperas.
  • Detecção de colisão: a forma de colisão do personagem é usada para detectar colisões com o ambiente, para que não passem por objetos sólidos.

A física do controlador de personagem em Quake 3 Arena foi projetada para criar uma experiência de jogo dinâmica e em ritmo acelerado. A física permite que o jogador execute uma variedade de técnicas de movimento, como bunny hopping, strafe jumping e circle strafing, que é um conjunto de técnicas que permite aos jogadores se mover e se esquivar de maneira muito rápida e precisa. No geral, a física do controlador de personagem do mecanismo de jogo Quake 3 Arena é projetada para fornecer um movimento suave e responsivo para o personagem do jogador, permitindo que ele navegue pelo mundo do jogo e interaja com o ambiente de uma maneira crível e realista.

Aqui está um tutorial sobre como criar um jogo U3D com um personagem jogável em primeira pessoa e câmera em primeira pessoa, usando a física de movimento do personagem Quake 3:

Crie o mundo da física e o controlador de personagem

  • Na classe Application, adicione um novo componente PhysicsWorld à cena. Isso será usado para lidar com a simulação de física para o controlador de personagem.
  • Crie um novo componente CharacterController e adicione-o à cena. Este componente irá lidar com o movimento do personagem e detecção de colisão.
#include <Urho3D/Urho3D.h>
#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Engine/Application.h>
#include <Urho3D/Engine/Engine.h>
#include <Urho3D/Physics/PhysicsWorld.h>
#include <Urho3D/Physics/RigidBody.h>
#include <Urho3D/Physics/CollisionShape.h>
#include <Urho3D/Physics/KinematicCharacterController.h>

using namespace Urho3D;

class MyApp : public Application
{
public:
    MyApp(Context* context) : Application(context)
    {
    }

    virtual void Start()
    {
        // Create the scene
        Scene* scene = new Scene(context_);
        // Create a physics world component
        PhysicsWorld* physicsWorld = scene->CreateComponent<PhysicsWorld>();
        // Create a character controller component
        CharacterController* characterController = scene->CreateComponent<CharacterController>();
    }

    virtual void Setup()
    {
        engineParameters_["FullScreen"] = false;
        engineParameters_["WindowWidth"] = 1280;
        engineParameters_["WindowHeight"] = 720;
    }
};
  • Na função Iniciar do CharacterController, configure a forma de colisão do personagem, o corpo rígido e o controlador de personagem cinemático.
class CharacterController : public Component
{
public:
    CharacterController(Context* context) : Component(context)
    {
    }

    void Start() override
    {
        // Create a capsule collision shape for the character
        CollisionShape* shape = node_->CreateComponent<CapsuleCollisionShape>();
        shape->SetSize(Vector3(0.5f, 1.0f, 0.5f));

        // Create a rigid body for the character
        RigidBody* body = node_->CreateComponent<RigidBody>();
        body->SetMass(80.0f);
        body->SetCollisionShape(shape);

        // Create a kinematic character controller
        kinematicCharacterController_ = node_->CreateComponent<KinematicCharacterController>();
        kinematicCharacterController_->SetRigidBody(body);
        kinematicCharacterController_->SetCollisionShape(shape);
        kinematicCharacterController_->SetMaxStepHeight(0.5f);
    }

private:
    KinematicCharacterController* kinematicCharacterController_;
};

Nesse código, um novo componente CharacterController é criado e adicionado à cena na função Start() da classe Application. Na função Start() do componente, uma forma de colisão de cápsula é criada e definida para o corpo rígido do personagem, e um componente KinematicCharacterController é criado e definido para a forma de colisão do personagem. A altura máxima do degrau, que é a altura máxima que o personagem pode subir, é definida como 0,5f.

Adicione os controles de movimento do personagem

  • Na função Update do CharacterController, obtenha a entrada do jogador e use-a para calcular a direção do movimento do personagem.
  • Use a função Mover do controlador de personagem cinemático para atualizar a posição do personagem com base na direção do movimento e intervalo de tempo.
class CharacterController : public Component
{
public:
    CharacterController(Context* context) : Component(context)
    {
    }

    void Start() override
    {
        //... previous code for collision shape, rigid body and kinematic character controller

    }

    void Update(float timeStep) override
    {
        Input* input = GetSubsystem<Input>();

        // Get the move direction from the input
        Vector3 moveDirection = Vector3::ZERO;
        if (input->GetKeyDown(KEY_W))
            moveDirection += Vector3::FORWARD;
        if (input->GetKeyDown(KEY_S))
            moveDirection += Vector3::BACK;
        if (input->GetKeyDown(KEY_A))
            moveDirection += Vector3::LEFT;
        if (input->GetKeyDown(KEY_D))
            moveDirection += Vector3::RIGHT;

        // Normalize the move direction
        moveDirection.Normalize();

        // Use the kinematic character controller's Move function to update the character's position based on the move direction and time step
        kinematicCharacterController_->Move(moveDirection * timeStep);
    }

private:
    KinematicCharacterController* kinematicCharacterController_;
};

Nesse código, a função Update obtém a direção do movimento da entrada e a normaliza para garantir que o personagem se mova em uma velocidade consistente. A função Mover do controlador de caractere cinemático é chamada e passa a direção do movimento multiplicada pelo intervalo de tempo. Isso move a posição do personagem com base na direção do movimento e no intervalo de tempo.

É importante observar que a função de movimento do controlador de personagem cinemático usa a forma de colisão do personagem e as informações de colisão do mundo da física para mover o personagem. Dessa forma, o personagem responderá corretamente às colisões com o ambiente.

Adicione a câmera em primeira pessoa

  • Crie um novo componente Camera e adicione-o à cena.
  • Posicione a câmera na cabeça do personagem e aponte-a na mesma direção do vetor de avanço do personagem.
  • Defina as distâncias de clipe próximo e clipe distante da câmera para valores apropriados para uma câmera em primeira pessoa.
        // Create a camera component and set it as the viewport's camera
        camera_ = GetScene()->CreateChild("Camera")->CreateComponent<Camera>();
        GetSubsystem<Renderer>()->SetViewport(0, new Viewport(context_, GetScene(), camera_));

        // Position the camera at the character's head
        camera_->SetPosition(node_->GetPosition() + Vector3(0.0f, 1.0f, 0.0f));

        // Point the camera in the same direction as the character's forward vector
        camera_->SetDirection(node_->GetDirection());

        // Set the camera's near clip distance
        camera_->SetNearClip(0.1f);

        // Set the camera's far clip distance
        camera_->SetFarClip(100.0f);

Configure o tratamento de entrada para a câmera e o personagem

  • Adicione manipulação de entrada para o movimento do personagem e o movimento da câmera na classe Application.
  • Vincule os eventos de entrada às funções apropriadas nos componentes CharacterController e Camera.

    virtual void Start()
    {
        //... previous code for creating the scene, physics world, and character controller

        // Subscribe to the key down event to handle character movement
        SubscribeToEvent(E_KEYDOWN, URHO3D_HANDLER(MyApp, HandleKeyDown));

        // Subscribe to the mouse move event to handle camera movement
        SubscribeToEvent(E_MOUSEMOVE, URHO3D_HANDLER(MyApp, HandleMouseMove));

        // Subscribe to the mouse button down event to handle mouse inputs
        SubscribeToEvent(E_MOUSEBUTTONDOWN, URHO3D_HANDLER(MyApp, HandleMouseButtonDown));

    }

    void HandleKeyDown(StringHash eventType, VariantMap& eventData)
    {
        using namespace KeyDown;

        int key = eventData[P_KEY].GetInt();

        // Send the key down event to the character controller
        characterController_->HandleKeyDown(key);
    }

    void HandleMouseMove(StringHash eventType, VariantMap& eventData)
    {
        using namespace MouseMove;

        int dx = eventData[P_DX].GetInt();
        int dy = eventData[P_DY].GetInt();

        // Send the mouse move event to the camera component
        camera_->HandleMouseMove(dx, dy);
    }

    void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
    {
        using namespace MouseButtonDown;

        int button = eventData[P_BUTTON].GetInt();

        // Send the mouse button down event to the camera component
        camera_->HandleMouseButtonDown(button);
    }

Adicione a forma de colisão para o ambiente, se você quiser andar por aí.

  • Crie um componente CollisionShape para o ambiente e anexe-o ao nó raiz da cena.
        // Get the root node of the scene
        Node* rootNode = GetScene()->GetChild("Environment", true);

        // Create a collision shape for the environment
        CollisionShape* environmentShape = rootNode->CreateComponent<CollisionShape>();
        //... previous code for setting the shape and size of the collision shape
  • Adicione as propriedades físicas necessárias ao seu ambiente, como fricção, ressalto, etc.
        // Get the rigid body of the environment
        RigidBody* environmentBody = rootNode->GetComponent<RigidBody>();
        // Set the physics properties of the environment
        environmentBody->SetFriction(0.8f);
        environmentBody->SetRestitution(0.1f);
        environmentBody->SetRollingFriction(0.1f);
        environmentBody->SetAnisotropicFriction(Vector3(1.0f, 1.0f, 1.0f));

Com este tutorial, você tem a estrutura básica para um jogo em primeira pessoa com um personagem jogável usando a física do Quake3 em U3D. Você pode adicionar mais recursos, como pular, agachar, atirar e muito mais adicionando mais funcionalidade ao CharacterController e ao ambiente.

Com informações de GameDev.net.

antonio-cesar-150x150
António César de Andrade

Apaixonado por tecnologia e inovação, traz notícias do seguimento que atua com paixão há mais de 15 anos.