Jump to content

Player Physics Controller


SpiderPig
 Share

Recommended Posts

In Leadwerks I used to be able to make a player controller and turn off gravity for that entity and just use AddForce() for my own gravity system.  I didn't see a problem with doing it this way for rigid bodies, but I never did think it was a good idea for the character controller.  Doesn't seem to work in Ultra anyway and in all fairness that's okay because I am going to have to make my own controller I think.

I'm going to post a few attempts here and see if I can't finally get this to work the way I want!

This used to work in Leadwerks:

#include "UltraEngine.h"
using namespace UltraEngine;


int main(int argc, const char* argv[])
{
    auto displays = GetDisplays();
    auto window = CreateWindow("Ultra Engine", 0, 0, 800, 600, displays[0]);
    auto framebuffer = CreateFramebuffer(window);
    auto world = CreateWorld();

    auto camera = CreateCamera(world);
    camera->Move(0, 2, -3);
    camera->SetClearColor(1, 0, 0);

    auto light = CreateDirectionalLight(world);
    light->SetRotation(35, 35, 35);

    auto floor = CreateBox(world, 100.0f, 0.5f, 100.0f);

    auto default_font = LoadFont("Fonts\\arial.ttf");
    auto ui = CreateInterface(world, default_font, framebuffer->size);
    ui->SetRenderLayers(2);
    ui->root->SetColor(0.0f, 0.0f, 0.0f, 0.0f);

    auto ui_camera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC);
    ui_camera->SetPosition((float)framebuffer->size.x * 0.5f, (float)framebuffer->size.y * 0.5f, 0);
    ui_camera->SetRenderLayers(2);
    ui_camera->SetClearMode(CLEAR_DEPTH);

    auto m = CreateCylinder(world, 0.5f, 1.8f);
    m->SetPhysicsMode(PHYSICS_PLAYER);
    m->SetPosition(0, 5, 0);
    m->SetMass(1.0f);
    m->SetGravityMode(false);


    while (true)
    {
        m->AddForce(0.0f, -9.8f, 0.0f);

        world->Update();
        world->Render(framebuffer);
    }
    return 0;
}

 

Link to comment
Share on other sites

The idea here is to switch between a rigid body when physics is needed and a kinematic joint when control is needed.  This might end up working but right now the Collide method in the CallbackCollision component is not being called a second time round...

If you wait for the player to fall, is_rigid_body will set to False, then hit space to jump, the player will jump and fall again but this time will not trigger the collide method.  The component is still attached and is still calling the update method.  A bug perhaps or bad coding by me?

#include "UltraEngine.h"
#include "ComponentSystem.h"

using namespace UltraEngine;


class Player {
public:
    shared_ptr<World> world = nullptr;
    shared_ptr<Model> model = nullptr;
    shared_ptr<Entity> rigid_body, controller_body;
    shared_ptr<Actor> actor = nullptr;
    shared_ptr<CollisionCallback> callback = nullptr;
    shared_ptr<Joint> joint = nullptr;

    bool is_controlable = false;
    bool is_rigid_body = false;
    bool is_airborne = false;

    Player(shared_ptr<World> world) {
        this->world = world;

        model = CreateCylinder(world, 0.5f, 1.8f);
        model->SetCollider(nullptr);
        model->SetColor(1, 0, 0);

        EnableRidgedBody(true);
    }

    ~Player() {}

    void SetPosition(float x, float y, float z) {
        if (is_rigid_body) {
            rigid_body->SetPosition(x, y, z);
        }
    }

    void EnableRidgedBody(bool state) {
        if (state == true) {
            is_rigid_body = true;
            is_airborne = true;

            auto collider = CreateCylinderCollider(0.5f, 1.8f);

            if (rigid_body == nullptr) {
                rigid_body = CreatePivot(world);
                rigid_body->SetShadows(true);
                rigid_body->SetCollider(collider);
                rigid_body->SetCollisionType(COLLISION_PLAYER);
                rigid_body->SetMass(1.0f);

                actor = CreateActor(rigid_body);
                callback = actor->AddComponent<CollisionCallback>();
            }

            model->SetParent(rigid_body);
        }
        else {
            is_rigid_body = false;
            is_airborne = false;

            model->SetParent(nullptr);
            model->SetRotation(0.0f, 0.0f, 0.0f);

           // callback = nullptr;
           // actor = nullptr;
            //rigid_body = nullptr;
        }
    }

    void EnableController(bool state) {
        if (state == true) {
            is_controlable = true;

            if (joint == nullptr) {
                auto pos = model->GetPosition(true);
                auto col = CreateCylinderCollider(0.5f, 1.8f);

                controller_body = CreatePivot(world);
                controller_body->SetShadows(true);
                controller_body->SetCollider(col);
                controller_body->SetCollisionType(COLLISION_NONE);
                controller_body->SetMass(1.0f);
                controller_body->SetPosition(pos, true);

                joint = CreateKinematicJoint(pos, controller_body);
            }

            model->SetParent(controller_body);
        }
        else {
           // joint = nullptr;
           // controller_body = nullptr;
            is_controlable = false;
        }
    }

    void SetInput(float move, float angle) {

    }

    void Update() {
        if (is_airborne == true && callback->collided == true) {
            auto vel = rigid_body->GetVelocity(true);
            auto speed_sqr = (vel.x * vel.x) + (vel.y * vel.y) + (vel.z * vel.z);
            
            if (speed_sqr < FLT_EPSILON) {
                callback->collided = false;

                EnableRidgedBody(false);
                EnableController(true);
            }
        }
        
        if (is_controlable == true) {
            auto target_position = model->GetPosition(true);
            auto angle = 0.0f;
            auto up = Vec3(0.0f, 1.0f, 0.0f);

            auto window = ActiveWindow();
            if (window != nullptr) {
                if (window->KeyDown(KEY_UP)) {}
                if (window->KeyHit(KEY_SPACE)) {
                    EnableController(false);
                    EnableRidgedBody(true);
                    rigid_body->AddForce(up * 250.0f);
                }
                else {
                    joint->SetPose(target_position, Vec3(0.0f));
                }
            }
        }
    }
};

int main(int argc, const char* argv[])
{
    auto displays = GetDisplays();
    auto window = CreateWindow("Ultra Engine", 0, 0, 1440, 900, displays[0]);
    auto framebuffer = CreateFramebuffer(window);
    auto world = CreateWorld();

    auto camera = CreateCamera(world);
    camera->Move(0, 2, -3);
    camera->SetClearColor(1, 0, 0);

    auto light = CreateDirectionalLight(world);
    light->SetRotation(35, 35, 35);

    auto floor = CreateBox(world, 100.0f, 0.5f, 100.0f);

    auto default_font = LoadFont("Fonts\\arial.ttf");
    auto ui = CreateInterface(world, default_font, framebuffer->size);
    ui->SetRenderLayers(2);
    ui->root->SetColor(0.0f, 0.0f, 0.0f, 0.0f);

    auto ui_camera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC);
    ui_camera->SetPosition((float)framebuffer->size.x * 0.5f, (float)framebuffer->size.y * 0.5f, 0);
    ui_camera->SetRenderLayers(2);
    ui_camera->SetClearMode(CLEAR_DEPTH);

    auto label = CreateLabel("", 10, 10, 500, 200, ui->root);

    auto player = make_shared<Player>(world);
    player->SetPosition(0, 5, 0);

    while (window->KeyHit(KEY_ESCAPE) == false && window->Closed() == false)
    {
        while (PeekEvent()) {
            ui->ProcessEvent(WaitEvent());
        }

        player->Update();
        auto pos = player->model->GetPosition(true);
        auto rot = player->model->GetRotation();

        WString text = "Position : " + String(pos.x) + ", " + String(pos.y) + ", " + String(pos.z) + "\n" +
            "Rotation : " + String(rot.x) + ", " + String(rot.y) + ", " + String(rot.z) + "\n" +
            "Rigid Body : " + String(player->is_rigid_body == true ? "True" : "False") + "\n" +
            "Collide : " + String(player->callback->collided == true ? "True" : "False") + "\n" +
            "Collision Count : " + String(player->callback->collision_count) + "\n" +
            "Still Updating : " + String(player->callback->is_updating == true ? "True" : "False");
        label->SetText(text);
        player->callback->is_updating = false;

        world->Update();
        world->Render(framebuffer);
    }
    return 0;
}

Component:

#pragma once
#include "UltraEngine.h"
#include "../ComponentSystem.h"


class CollisionCallback : public Component {
private:
public:
    bool collided = false, is_updating = false;
    int collision_count = 0;

    virtual void Update() {
        is_updating = true;
    }

    virtual void Collide(shared_ptr<Actor> collidedactor, const Vec3& position, const Vec3& normal, const dFloat speed) {
        collided = true;
        collision_count++;
    }
};

 

Link to comment
Share on other sites

It works flawlessly if I delete the actor and component and then remake them.  So I'd say the above post shows a bug in the Collide method.

void EnableRidgedBody(bool state) {
        if (state == true) {
            is_rigid_body = true;
            is_airborne = true;

            auto collider = CreateCylinderCollider(0.5f, 1.8f);

            if (rigid_body == nullptr) {
                rigid_body = CreatePivot(world);
                rigid_body->SetShadows(true);
                rigid_body->SetCollider(collider);
                rigid_body->SetCollisionType(COLLISION_PLAYER);
                rigid_body->SetMass(1.0f);

            }
                
            actor = CreateActor(rigid_body);
            callback = actor->AddComponent<CollisionCallback>();
            model->SetParent(rigid_body);
        }
        else {
            is_rigid_body = false;
            is_airborne = false;

            model->SetParent(nullptr);
            model->SetRotation(0.0f, 0.0f, 0.0f);

            callback = nullptr;
            actor = nullptr;
        }
    }

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...