From b7f4f0e4bf12321c030b4b6e5f82aa748e04e88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Fonseca?= Date: Sun, 18 Jun 2023 11:17:48 +0100 Subject: [PATCH] feat(engine): add collisions sample --- engine/samples/CMakeLists.txt | 1 + engine/samples/collisions/main.cpp | 163 +++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 engine/samples/collisions/main.cpp diff --git a/engine/samples/CMakeLists.txt b/engine/samples/CMakeLists.txt index 9845cb5b7..657149659 100644 --- a/engine/samples/CMakeLists.txt +++ b/engine/samples/CMakeLists.txt @@ -43,5 +43,6 @@ make_sample(DIR "input" ASSETS) make_sample(DIR "assets/json" ASSETS) make_sample(DIR "assets/bridge" ASSETS) make_sample(DIR "renderer") +make_sample(DIR "collisions" COMPONENTS) make_sample(DIR "scene" COMPONENTS ASSETS) make_sample(DIR "cars" COMPONENTS ASSETS) diff --git a/engine/samples/collisions/main.cpp b/engine/samples/collisions/main.cpp new file mode 100644 index 000000000..a36598db8 --- /dev/null +++ b/engine/samples/collisions/main.cpp @@ -0,0 +1,163 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using cubos::core::Settings; +using cubos::core::ecs::Commands; +using cubos::core::ecs::Entity; +using cubos::core::ecs::Query; +using cubos::core::ecs::Read; +using cubos::core::ecs::Write; +using cubos::core::geom::Box; +using cubos::core::io::Key; +using cubos::core::io::Modifiers; + +using cubos::engine::BoxCollider; +using cubos::engine::BroadPhaseCollisions; +using cubos::engine::ColliderAABB; +using cubos::engine::InputAction; +using cubos::engine::InputBindings; + +using namespace cubos::engine; + +struct State +{ + bool collided = false; + + Entity a; + Entity b; + + glm::vec3 aRotationAxis; + glm::vec3 bRotationAxis; +}; + +static void settings(Write settings) +{ + settings->setBool("assets.io.enabled", false); +} + +static void init(Commands commands, Write input, Write camera) +{ + // Add procedural asset for detecting a reset action on a space key press. + auto bindings = InputBindings{}; + bindings.actions()["reset"].keys().push_back({Key::Space, Modifiers::None}); + input->bind(bindings); + + // Spawn the camera. + camera->entities[0] = + commands.create() + .add(Camera{.fovY = 60.0, .zNear = 0.1F, .zFar = 100.0F}) + .add(LocalToWorld{}) + .add(Position{{-4.0, 1.5, 0}}) + .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{3.0, -1.0, 0.0}), glm::vec3{0.0, 1.0, 0.0})}) + .entity(); +} + +static void addColliders(Write state, Write collisions, Commands commands) +{ + state->a = commands.create() + .add(BoxCollider{}) + .add(LocalToWorld{}) + .add(Position{glm::vec3{0.0F, 0.0F, -2.0F}}) + .add(Rotation{}) + .entity(); + state->aRotationAxis = glm::sphericalRand(1.0F); + collisions->addEntity(state->a); + + state->b = commands.create() + .add(BoxCollider{}) + .add(LocalToWorld{}) + .add(Position{glm::vec3{0.0F, 0.0F, 2.0F}}) + .add(Rotation{}) + .entity(); + state->bRotationAxis = glm::sphericalRand(1.0F); + collisions->addEntity(state->b); +} + +static void updateTransform(Write state, Read input, Query, Write> query) +{ + auto [aPos, aRot] = query[state->a].value(); + auto [bPos, bRot] = query[state->b].value(); + + if (state->collided) + { + if (input->pressed("reset")) + { + state->collided = false; + + aPos->vec = glm::vec3{0.0F, 0.0F, -2.0F}; + aRot->quat = glm::quat{1.0F, 0.0F, 0.0F, 0.0F}; + state->aRotationAxis = glm::sphericalRand(1.0F); + + bPos->vec = glm::vec3{0.0F, 0.0F, 2.0F}; + bRot->quat = glm::quat{1.0F, 0.0F, 0.0F, 0.0F}; + state->bRotationAxis = glm::sphericalRand(1.0F); + } + return; + } + + aRot->quat = glm::rotate(aRot->quat, 0.01F, state->aRotationAxis); + aPos->vec += glm::vec3{0.0F, 0.0F, 0.01F}; + + bRot->quat = glm::rotate(bRot->quat, 0.01F, state->bRotationAxis); + bPos->vec += glm::vec3{0.0F, 0.0F, -0.01F}; +} + +static void updateCollided(Query> query, Write state, Read collisions) +{ + for (auto [entity, collider] : query) + { + for (auto& [collider1, collider2] : collisions->candidates(BroadPhaseCollisions::CollisionType::BoxBox)) + { + if (collider1 == entity || collider2 == entity) + { + state->collided = true; + break; + } + } + } +} + +static void render(Query, Read, Read> query) +{ + for (auto [entity, localToWorld, collider, aabb] : query) + { + cubos::core::gl::Debug::drawWireBox(collider->shape, localToWorld->mat * collider->transform); + cubos::core::gl::Debug::drawWireBox(aabb->box(), glm::translate(glm::mat4{1.0}, aabb->center()), + glm::vec3{1.0, 0.0, 0.0}); + } +} + +int main() +{ + auto cubos = Cubos(); + + cubos.addPlugin(collisionsPlugin); + cubos.addPlugin(rendererPlugin); + cubos.addPlugin(inputPlugin); + + cubos.addResource(); + + cubos.startupSystem(settings).tagged("cubos.settings"); + cubos.startupSystem(init); + + cubos.startupSystem(addColliders); + + cubos.system(updateTransform).beforeTag("cubos.transform.update"); + cubos.system(updateCollided).tagged("updated").afterTag("cubos.collisions"); + cubos.system(render).afterTag("updated"); + + cubos.run(); + return 0; +} \ No newline at end of file