From 4b4f2439c0110367e197ac94f6219a8f8421eb95 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 11 Mar 2026 22:08:40 +0300 Subject: [PATCH] add more reason to physics simulation substeps --- src/objects/Entities.cpp | 72 +++++++++----------- src/physics/Hitbox.cpp | 17 +++-- src/physics/Hitbox.hpp | 12 ++-- src/physics/PhysicsSolver.cpp | 122 ++++++++++++++++++---------------- src/physics/PhysicsSolver.hpp | 10 +-- 5 files changed, 119 insertions(+), 114 deletions(-) diff --git a/src/objects/Entities.cpp b/src/objects/Entities.cpp index c81b01a38..259e9e3c6 100644 --- a/src/objects/Entities.cpp +++ b/src/objects/Entities.cpp @@ -80,7 +80,7 @@ entityid_t Entities::spawn( entities[id] = entity; uids[entity] = id; - registry->emplace(entity, static_cast(id), def); + registry->emplace(entity, id, def); const auto& tsf = registry->emplace( entity, position, @@ -92,7 +92,7 @@ entityid_t Entities::spawn( auto& body = registry->emplace( entity, true, - Hitbox {def.bodyType, position, def.hitbox * 0.5f}, + Hitbox {id, def.bodyType, position, def.hitbox * 0.5f}, std::vector {} ); body.initialize(def, id, *this); @@ -280,6 +280,7 @@ void Entities::updateSensors( void Entities::preparePhysics(float delta) { auto& physics = *level.physics; + auto& hitboxes = physics.getHitboxesWriteable(); auto& solidHitboxes = physics.getSolidHitboxesWriteable(); if (sensorsTickClock.update(delta)) { @@ -301,11 +302,16 @@ void Entities::preparePhysics(float delta) { } } + hitboxes.clear(); solidHitboxes.clear(); auto view = registry->view(); for (auto [entity, eid, rigidbody] : view.each()) { - if (!eid.def.solid || eid.destroyFlag || !rigidbody.enabled) { + if (eid.destroyFlag || !rigidbody.enabled) { + continue; + } + hitboxes.emplace_back(&rigidbody.hitbox); + if (!eid.def.solid) { continue; } solidHitboxes.emplace_back(&rigidbody.hitbox); @@ -318,43 +324,31 @@ void Entities::updatePhysics(float delta) { auto view = registry->view(); auto physics = level.physics.get(); - for (int solid = false; solid <= true; solid++) { - for (auto [entity, eid, transform, rigidbody] : view.each()) { - if (!rigidbody.enabled || - rigidbody.hitbox.type == BodyType::STATIC) { - continue; - } - if (eid.def.solid == solid) { - continue; - } - auto& hitbox = rigidbody.hitbox; - auto prevVel = hitbox.velocity; - bool grounded = hitbox.grounded; + int substeps = std::max(std::min(delta * 1000, 200), 8); + physics->step(*level.chunks, delta, substeps); - float vel = glm::length(prevVel); - int substeps = static_cast(delta * (vel + 2.0f) * 20); - substeps = std::min(100, std::max(2, substeps)); - physics->step(*level.chunks, hitbox, delta, substeps, eid.uid); - hitbox.friction = glm::abs(hitbox.gravityScale <= 1e-7f) - ? 8.0f - : (!grounded ? 2.0f : 10.0f); - hitbox.scale = transform.size; - if (util::is_nan_or_inf(hitbox.position)) { - logger.error() - << "physics simulation produced nan or inf (entity " - << eid.def.name << "#" << eid.uid << ")"; - hitbox.position = transform.pos; - } else { - transform.setPos(hitbox.position); - } - if (hitbox.grounded && !grounded) { - scripting::on_entity_grounded( - *get(eid.uid), glm::length(prevVel - hitbox.velocity) - ); - } - if (!hitbox.grounded && grounded) { - scripting::on_entity_fall(*get(eid.uid)); - } + for (auto [entity, eid, transform, rigidbody] : view.each()) { + if (!rigidbody.enabled || + rigidbody.hitbox.type == BodyType::STATIC) { + continue; + } + auto& hitbox = rigidbody.hitbox; + hitbox.scale = transform.size; + if (util::is_nan_or_inf(hitbox.position)) { + logger.error() + << "physics simulation produced nan or inf (entity " + << eid.def.name << "#" << eid.uid << ")"; + hitbox.position = transform.pos; + } else { + transform.setPos(hitbox.position); + } + if (hitbox.grounded && !hitbox.prevGrounded) { + scripting::on_entity_grounded( + *get(eid.uid), glm::length(hitbox.prevVelocity - hitbox.velocity) + ); + } + if (!hitbox.grounded && hitbox.prevGrounded) { + scripting::on_entity_fall(*get(eid.uid)); } } } diff --git a/src/physics/Hitbox.cpp b/src/physics/Hitbox.cpp index a72bdd939..e9e18ce58 100644 --- a/src/physics/Hitbox.cpp +++ b/src/physics/Hitbox.cpp @@ -2,10 +2,13 @@ #include -Hitbox::Hitbox(BodyType type, glm::vec3 position, glm::vec3 halfsize) - : type(type), - position(position), - halfsize(halfsize), - velocity(0.0f,0.0f,0.0f), - prevPosition(position) -{} +Hitbox::Hitbox( + entityid_t entity, BodyType type, glm::vec3 position, glm::vec3 halfsize +) + : entity(entity), + type(type), + position(position), + halfsize(halfsize), + velocity(0.0f, 0.0f, 0.0f), + prevPosition(position) { +} diff --git a/src/physics/Hitbox.hpp b/src/physics/Hitbox.hpp index 15b7acc89..9d2213572 100644 --- a/src/physics/Hitbox.hpp +++ b/src/physics/Hitbox.hpp @@ -51,6 +51,7 @@ VC_ENUM_METADATA(BodyType) VC_ENUM_END struct Hitbox { + entityid_t entity; BodyType type; glm::vec3 position; glm::vec3 halfsize; @@ -65,17 +66,18 @@ struct Hitbox { bool crouching = false; float stepHeight = 0.5f; std::string material; - - glm::vec3 groundVelocity {}; std::string groundMaterial; + glm::vec3 groundVelocity {}; - // garbage tbh glm::vec3 prevPosition {}; - float delta = 0.0f; + glm::vec3 prevVelocity {}; + bool prevGrounded = false; static inline constexpr float TELEPORT_THRESOLD_SQR = 0.5f; - Hitbox(BodyType type, glm::vec3 position, glm::vec3 halfsize); + Hitbox( + entityid_t entity, BodyType type, glm::vec3 position, glm::vec3 halfsize + ); AABB getAABB() const { return AABB(position - halfsize, position + halfsize); diff --git a/src/physics/PhysicsSolver.cpp b/src/physics/PhysicsSolver.cpp index c9947c299..cf44024f1 100644 --- a/src/physics/PhysicsSolver.cpp +++ b/src/physics/PhysicsSolver.cpp @@ -141,13 +141,10 @@ static bool calc_collision_neg_y( if (pos.y < newy && glm::abs(pos.y - newy) < boxhalf.y) { pos.y = newy; } - if (glm::abs(box->delta) > 1e-5f) { - hitbox.groundVelocity = - (box->position - box->prevPosition) / box->delta; - } + hitbox.groundVelocity = box->position - box->prevPosition; if (vel.y < 0.0f) { vel.y = 0.0f; - if (hitbox.groundMaterial.empty()) { + if (hitbox.groundMaterial.empty() && !box->material.empty()) { hitbox.groundMaterial = box->material; } return true; @@ -297,16 +294,15 @@ void PhysicsSolver::calcSubstep( Hitbox& hitbox, glm::vec3& vel, glm::vec3& pos, - bool prevGrounded, float dt, int substeps ) { - if (hitbox.grounded) { - pos.x += hitbox.groundVelocity.x * dt * substeps; + if (glm::length2(hitbox.groundVelocity) > 1e-6f) { + pos.x += hitbox.groundVelocity.x; if (hitbox.groundVelocity.y < 0.0f) { - pos.y += hitbox.groundVelocity.y * dt * substeps; + pos.y += hitbox.groundVelocity.y; } - pos.z += hitbox.groundVelocity.z * dt * substeps; + pos.z += hitbox.groundVelocity.z; } auto initpos = pos; @@ -320,7 +316,7 @@ void PhysicsSolver::calcSubstep( vel, pos, half, - (prevGrounded && gravityScale > 0.0f) ? hitbox.stepHeight : 0.0f + (hitbox.prevGrounded && gravityScale > 0.0f) ? hitbox.stepHeight : 0.0f ); } @@ -374,64 +370,72 @@ void PhysicsSolver::calcSubstep( void PhysicsSolver::step( const GlobalChunks& chunks, - Hitbox& hitbox, float delta, - uint substeps, - entityid_t entity + uint substeps ) { - hitbox.prevPosition = hitbox.position; - hitbox.delta = delta; - hitbox.groundMaterial.clear(); + for (auto hitbox : hitboxes) { + hitbox->groundMaterial.clear(); + hitbox->prevGrounded = hitbox->grounded; + hitbox->grounded = false; + hitbox->prevVelocity = hitbox->velocity; + } float dt = delta / static_cast(substeps); - float linearDamping = hitbox.linearDamping * hitbox.friction; - - glm::vec3& pos = hitbox.position; - glm::vec3& vel = hitbox.velocity; - - bool prevGrounded = hitbox.grounded; - hitbox.grounded = false; for (uint i = 0; i < substeps; i++) { - calcSubstep(chunks, hitbox, vel, pos, prevGrounded, dt, substeps); - } - - vel.x /= 1.0f + delta * linearDamping; - vel.z /= 1.0f + delta * linearDamping; - if (hitbox.verticalDamping > 0.0f) { - vel.y /= 1.0f + delta * linearDamping * hitbox.verticalDamping; - } - if (prevGrounded && !hitbox.grounded) { - auto appliedVelocity = hitbox.groundVelocity; - vel += appliedVelocity; - hitbox.groundVelocity = {}; - } - - AABB aabb; - aabb.a = pos - hitbox.getHalfSize(); - aabb.b = pos + hitbox.getHalfSize(); - for (size_t i = 0; i < sensors.size(); i++) { - auto& sensor = *sensors[i]; - if (sensor.entity == entity) { - continue; + for (auto hitbox : hitboxes) { + glm::vec3& pos = hitbox->position; + glm::vec3& vel = hitbox->velocity; + hitbox->prevPosition = hitbox->position; + calcSubstep(chunks, *hitbox, vel, pos, dt, substeps); } + } - bool triggered = false; - switch (sensor.type) { - case SensorType::AABB: - triggered = aabb.intersects(sensor.calculated.aabb); - break; - case SensorType::RADIUS: - triggered = glm::distance2( - pos, glm::vec3(sensor.calculated.radial)) - < sensor.calculated.radial.w; - break; + for (auto hitbox : hitboxes) { + float linearDamping = hitbox->linearDamping * hitbox->friction; + glm::vec3& pos = hitbox->position; + glm::vec3& vel = hitbox->velocity; + + vel.x /= 1.0f + delta * linearDamping; + vel.z /= 1.0f + delta * linearDamping; + if (hitbox->verticalDamping > 0.0f) { + vel.y /= 1.0f + delta * linearDamping * hitbox->verticalDamping; } - if (triggered) { - if (sensor.prevEntered.find(entity) == sensor.prevEntered.end()) { - sensor.enterCallback(sensor.entity, sensor.index, entity); + if (hitbox->prevGrounded && !hitbox->grounded) { + auto appliedVelocity = hitbox->groundVelocity / dt; + vel += appliedVelocity; + hitbox->groundVelocity = {}; + } + + AABB aabb; + aabb.a = pos - hitbox->getHalfSize(); + aabb.b = pos + hitbox->getHalfSize(); + for (size_t i = 0; i < sensors.size(); i++) { + auto& sensor = *sensors[i]; + if (sensor.entity == hitbox->entity) { + continue; } - sensor.nextEntered.insert(entity); + bool triggered = false; + switch (sensor.type) { + case SensorType::AABB: + triggered = aabb.intersects(sensor.calculated.aabb); + break; + case SensorType::RADIUS: + triggered = glm::distance2( + pos, glm::vec3(sensor.calculated.radial)) + < sensor.calculated.radial.w; + break; + } + if (!triggered) { + continue; + } + if (sensor.prevEntered.find(hitbox->entity) == sensor.prevEntered.end()) { + sensor.enterCallback(sensor.entity, sensor.index, hitbox->entity); + } + sensor.nextEntered.insert(hitbox->entity); } + hitbox->friction = glm::abs(hitbox->gravityScale <= 1e-7f) + ? 8.0f + : (!hitbox->prevGrounded ? 2.0f : 10.0f); } } diff --git a/src/physics/PhysicsSolver.hpp b/src/physics/PhysicsSolver.hpp index 419b37ecc..ee02f052b 100644 --- a/src/physics/PhysicsSolver.hpp +++ b/src/physics/PhysicsSolver.hpp @@ -18,10 +18,8 @@ public: PhysicsSolver(glm::vec3 gravity); void step( const GlobalChunks& chunks, - Hitbox& hitbox, float delta, - uint substeps, - entityid_t entity + uint substeps ); auto& getSensorsWriteable() { @@ -32,11 +30,16 @@ public: return solidHitboxes; } + auto& getHitboxesWriteable() { + return hitboxes; + } + void removeSensor(Sensor* sensor); private: glm::vec3 gravity; std::vector sensors; std::vector solidHitboxes; + std::vector hitboxes; void calcCollisions( const GlobalChunks& chunks, @@ -52,7 +55,6 @@ private: Hitbox& hitbox, glm::vec3& vel, glm::vec3& pos, - bool prevGrounded, float dt, int substeps );