#pragma once #include #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include #include // std #include #include #include namespace hk { class GravityPhysicsSystem { public: GravityPhysicsSystem(float strength) :m_strengthGravity(strength) {} void update(std::vector &objs, float dt, unsigned int substeps = 1) { const float stepDelta = dt / substeps; for (int i = 0; i < substeps; i++) { stepSimulation(objs, stepDelta); } } glm::vec2 computeForce(GameObject &fromObj, GameObject &toObj) const { auto offset = fromObj.m_transform2d.translation - toObj.m_transform2d.translation; float distanceSquared = glm::dot(offset, offset); if (glm::abs(distanceSquared < 1e-10f)) { return {.0f, .0f}; } float force = m_strengthGravity * toObj.m_rigidBody2d.mass * fromObj.m_rigidBody2d.mass / distanceSquared; return force * offset / glm::sqrt(distanceSquared); } const float m_strengthGravity; private: void stepSimulation(std::vector &physicsObjs, float dt) { // Loops throught all pairs of objects and applies attractive force between them for (auto iterA = physicsObjs.begin(); iterA != physicsObjs.end(); ++iterA) { auto &objA = *iterA; for (auto iterB = iterA; iterB != physicsObjs.end(); ++iterB) { if (iterA == iterB) continue; auto &objB = *iterB; auto force = computeForce(objA, objB); objA.m_rigidBody2d.velocity += dt * -force / objA.m_rigidBody2d.mass; objB.m_rigidBody2d.velocity += dt * force / objB.m_rigidBody2d.mass; } } // update each objects position based on its final velocity for (auto &obj : physicsObjs) { obj.m_transform2d.translation += dt * obj.m_rigidBody2d.velocity; } } }; class Vec2FieldSystem { public: void update(const GravityPhysicsSystem &physicsSystem, std::vector &physicsObjs, std::vector &vectorField) { for (auto &vf : vectorField) { glm::vec2 direction{}; for (auto &obj : physicsObjs) { direction += physicsSystem.computeForce(obj, vf); } vf.m_transform2d.scale.x = 0.005f + 0.045f * glm::clamp(glm::log(glm::length(direction) + 1) / 3.f, 0.f, 1.f); vf.m_transform2d.rotation = atan2(direction.y, direction.x); } } }; std::unique_ptr createSquareModel(Device &device, glm::vec2 offset) { std::vector vertices = { {{-0.5f, -0.5f}}, {{0.5f, 0.5f}}, {{-0.5f, 0.5f}}, {{-0.5f, -0.5f}}, {{0.5f, -0.5f}}, {{0.5f, 0.5f}}, }; for (auto &v : vertices) { v.posision += offset; } return std::make_unique(device, vertices); } std::unique_ptr createCircleModel(Device &device, unsigned int numSides) { std::vector uniqueVertices{}; for(int i = 0; i < numSides; i++) { float angle = i * glm::two_pi() / numSides; uniqueVertices.push_back({{glm::cos(angle), glm::sin(angle)}}); } uniqueVertices.push_back({}); std::vector vertices{}; for(int i = 0; i < numSides; i++) { vertices.push_back(uniqueVertices[i]); vertices.push_back(uniqueVertices[(i+1) % numSides]); vertices.push_back(uniqueVertices[numSides]); } return std::make_unique(device, vertices); } }