mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-14 07:21:51 +00:00
add more reason to physics simulation substeps
This commit is contained in:
parent
794ce07bd5
commit
4b4f2439c0
5 changed files with 119 additions and 114 deletions
|
|
@ -80,7 +80,7 @@ entityid_t Entities::spawn(
|
||||||
entities[id] = entity;
|
entities[id] = entity;
|
||||||
uids[entity] = id;
|
uids[entity] = id;
|
||||||
|
|
||||||
registry->emplace<EntityId>(entity, static_cast<entityid_t>(id), def);
|
registry->emplace<EntityId>(entity, id, def);
|
||||||
const auto& tsf = registry->emplace<Transform>(
|
const auto& tsf = registry->emplace<Transform>(
|
||||||
entity,
|
entity,
|
||||||
position,
|
position,
|
||||||
|
|
@ -92,7 +92,7 @@ entityid_t Entities::spawn(
|
||||||
auto& body = registry->emplace<Rigidbody>(
|
auto& body = registry->emplace<Rigidbody>(
|
||||||
entity,
|
entity,
|
||||||
true,
|
true,
|
||||||
Hitbox {def.bodyType, position, def.hitbox * 0.5f},
|
Hitbox {id, def.bodyType, position, def.hitbox * 0.5f},
|
||||||
std::vector<Sensor> {}
|
std::vector<Sensor> {}
|
||||||
);
|
);
|
||||||
body.initialize(def, id, *this);
|
body.initialize(def, id, *this);
|
||||||
|
|
@ -280,6 +280,7 @@ void Entities::updateSensors(
|
||||||
|
|
||||||
void Entities::preparePhysics(float delta) {
|
void Entities::preparePhysics(float delta) {
|
||||||
auto& physics = *level.physics;
|
auto& physics = *level.physics;
|
||||||
|
auto& hitboxes = physics.getHitboxesWriteable();
|
||||||
auto& solidHitboxes = physics.getSolidHitboxesWriteable();
|
auto& solidHitboxes = physics.getSolidHitboxesWriteable();
|
||||||
|
|
||||||
if (sensorsTickClock.update(delta)) {
|
if (sensorsTickClock.update(delta)) {
|
||||||
|
|
@ -301,11 +302,16 @@ void Entities::preparePhysics(float delta) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hitboxes.clear();
|
||||||
solidHitboxes.clear();
|
solidHitboxes.clear();
|
||||||
|
|
||||||
auto view = registry->view<EntityId, Rigidbody>();
|
auto view = registry->view<EntityId, Rigidbody>();
|
||||||
for (auto [entity, eid, rigidbody] : view.each()) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
solidHitboxes.emplace_back(&rigidbody.hitbox);
|
solidHitboxes.emplace_back(&rigidbody.hitbox);
|
||||||
|
|
@ -318,43 +324,31 @@ void Entities::updatePhysics(float delta) {
|
||||||
auto view = registry->view<EntityId, Transform, Rigidbody>();
|
auto view = registry->view<EntityId, Transform, Rigidbody>();
|
||||||
auto physics = level.physics.get();
|
auto physics = level.physics.get();
|
||||||
|
|
||||||
for (int solid = false; solid <= true; solid++) {
|
int substeps = std::max<int>(std::min<int>(delta * 1000, 200), 8);
|
||||||
for (auto [entity, eid, transform, rigidbody] : view.each()) {
|
physics->step(*level.chunks, delta, substeps);
|
||||||
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;
|
|
||||||
|
|
||||||
float vel = glm::length(prevVel);
|
for (auto [entity, eid, transform, rigidbody] : view.each()) {
|
||||||
int substeps = static_cast<int>(delta * (vel + 2.0f) * 20);
|
if (!rigidbody.enabled ||
|
||||||
substeps = std::min(100, std::max(2, substeps));
|
rigidbody.hitbox.type == BodyType::STATIC) {
|
||||||
physics->step(*level.chunks, hitbox, delta, substeps, eid.uid);
|
continue;
|
||||||
hitbox.friction = glm::abs(hitbox.gravityScale <= 1e-7f)
|
}
|
||||||
? 8.0f
|
auto& hitbox = rigidbody.hitbox;
|
||||||
: (!grounded ? 2.0f : 10.0f);
|
hitbox.scale = transform.size;
|
||||||
hitbox.scale = transform.size;
|
if (util::is_nan_or_inf(hitbox.position)) {
|
||||||
if (util::is_nan_or_inf(hitbox.position)) {
|
logger.error()
|
||||||
logger.error()
|
<< "physics simulation produced nan or inf (entity "
|
||||||
<< "physics simulation produced nan or inf (entity "
|
<< eid.def.name << "#" << eid.uid << ")";
|
||||||
<< eid.def.name << "#" << eid.uid << ")";
|
hitbox.position = transform.pos;
|
||||||
hitbox.position = transform.pos;
|
} else {
|
||||||
} else {
|
transform.setPos(hitbox.position);
|
||||||
transform.setPos(hitbox.position);
|
}
|
||||||
}
|
if (hitbox.grounded && !hitbox.prevGrounded) {
|
||||||
if (hitbox.grounded && !grounded) {
|
scripting::on_entity_grounded(
|
||||||
scripting::on_entity_grounded(
|
*get(eid.uid), glm::length(hitbox.prevVelocity - hitbox.velocity)
|
||||||
*get(eid.uid), glm::length(prevVel - hitbox.velocity)
|
);
|
||||||
);
|
}
|
||||||
}
|
if (!hitbox.grounded && hitbox.prevGrounded) {
|
||||||
if (!hitbox.grounded && grounded) {
|
scripting::on_entity_fall(*get(eid.uid));
|
||||||
scripting::on_entity_fall(*get(eid.uid));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
Hitbox::Hitbox(BodyType type, glm::vec3 position, glm::vec3 halfsize)
|
Hitbox::Hitbox(
|
||||||
: type(type),
|
entityid_t entity, BodyType type, glm::vec3 position, glm::vec3 halfsize
|
||||||
position(position),
|
)
|
||||||
halfsize(halfsize),
|
: entity(entity),
|
||||||
velocity(0.0f,0.0f,0.0f),
|
type(type),
|
||||||
prevPosition(position)
|
position(position),
|
||||||
{}
|
halfsize(halfsize),
|
||||||
|
velocity(0.0f, 0.0f, 0.0f),
|
||||||
|
prevPosition(position) {
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ VC_ENUM_METADATA(BodyType)
|
||||||
VC_ENUM_END
|
VC_ENUM_END
|
||||||
|
|
||||||
struct Hitbox {
|
struct Hitbox {
|
||||||
|
entityid_t entity;
|
||||||
BodyType type;
|
BodyType type;
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
glm::vec3 halfsize;
|
glm::vec3 halfsize;
|
||||||
|
|
@ -65,17 +66,18 @@ struct Hitbox {
|
||||||
bool crouching = false;
|
bool crouching = false;
|
||||||
float stepHeight = 0.5f;
|
float stepHeight = 0.5f;
|
||||||
std::string material;
|
std::string material;
|
||||||
|
|
||||||
glm::vec3 groundVelocity {};
|
|
||||||
std::string groundMaterial;
|
std::string groundMaterial;
|
||||||
|
glm::vec3 groundVelocity {};
|
||||||
|
|
||||||
// garbage tbh
|
|
||||||
glm::vec3 prevPosition {};
|
glm::vec3 prevPosition {};
|
||||||
float delta = 0.0f;
|
glm::vec3 prevVelocity {};
|
||||||
|
bool prevGrounded = false;
|
||||||
|
|
||||||
static inline constexpr float TELEPORT_THRESOLD_SQR = 0.5f;
|
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 {
|
AABB getAABB() const {
|
||||||
return AABB(position - halfsize, position + halfsize);
|
return AABB(position - halfsize, position + halfsize);
|
||||||
|
|
|
||||||
|
|
@ -141,13 +141,10 @@ static bool calc_collision_neg_y(
|
||||||
if (pos.y < newy && glm::abs(pos.y - newy) < boxhalf.y) {
|
if (pos.y < newy && glm::abs(pos.y - newy) < boxhalf.y) {
|
||||||
pos.y = newy;
|
pos.y = newy;
|
||||||
}
|
}
|
||||||
if (glm::abs(box->delta) > 1e-5f) {
|
hitbox.groundVelocity = box->position - box->prevPosition;
|
||||||
hitbox.groundVelocity =
|
|
||||||
(box->position - box->prevPosition) / box->delta;
|
|
||||||
}
|
|
||||||
if (vel.y < 0.0f) {
|
if (vel.y < 0.0f) {
|
||||||
vel.y = 0.0f;
|
vel.y = 0.0f;
|
||||||
if (hitbox.groundMaterial.empty()) {
|
if (hitbox.groundMaterial.empty() && !box->material.empty()) {
|
||||||
hitbox.groundMaterial = box->material;
|
hitbox.groundMaterial = box->material;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -297,16 +294,15 @@ void PhysicsSolver::calcSubstep(
|
||||||
Hitbox& hitbox,
|
Hitbox& hitbox,
|
||||||
glm::vec3& vel,
|
glm::vec3& vel,
|
||||||
glm::vec3& pos,
|
glm::vec3& pos,
|
||||||
bool prevGrounded,
|
|
||||||
float dt,
|
float dt,
|
||||||
int substeps
|
int substeps
|
||||||
) {
|
) {
|
||||||
if (hitbox.grounded) {
|
if (glm::length2(hitbox.groundVelocity) > 1e-6f) {
|
||||||
pos.x += hitbox.groundVelocity.x * dt * substeps;
|
pos.x += hitbox.groundVelocity.x;
|
||||||
if (hitbox.groundVelocity.y < 0.0f) {
|
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;
|
auto initpos = pos;
|
||||||
|
|
@ -320,7 +316,7 @@ void PhysicsSolver::calcSubstep(
|
||||||
vel,
|
vel,
|
||||||
pos,
|
pos,
|
||||||
half,
|
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(
|
void PhysicsSolver::step(
|
||||||
const GlobalChunks& chunks,
|
const GlobalChunks& chunks,
|
||||||
Hitbox& hitbox,
|
|
||||||
float delta,
|
float delta,
|
||||||
uint substeps,
|
uint substeps
|
||||||
entityid_t entity
|
|
||||||
) {
|
) {
|
||||||
hitbox.prevPosition = hitbox.position;
|
for (auto hitbox : hitboxes) {
|
||||||
hitbox.delta = delta;
|
hitbox->groundMaterial.clear();
|
||||||
hitbox.groundMaterial.clear();
|
hitbox->prevGrounded = hitbox->grounded;
|
||||||
|
hitbox->grounded = false;
|
||||||
|
hitbox->prevVelocity = hitbox->velocity;
|
||||||
|
}
|
||||||
|
|
||||||
float dt = delta / static_cast<float>(substeps);
|
float dt = delta / static_cast<float>(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++) {
|
for (uint i = 0; i < substeps; i++) {
|
||||||
calcSubstep(chunks, hitbox, vel, pos, prevGrounded, dt, substeps);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vel.x /= 1.0f + delta * linearDamping;
|
for (auto hitbox : hitboxes) {
|
||||||
vel.z /= 1.0f + delta * linearDamping;
|
float linearDamping = hitbox->linearDamping * hitbox->friction;
|
||||||
if (hitbox.verticalDamping > 0.0f) {
|
glm::vec3& pos = hitbox->position;
|
||||||
vel.y /= 1.0f + delta * linearDamping * hitbox.verticalDamping;
|
glm::vec3& vel = hitbox->velocity;
|
||||||
}
|
|
||||||
if (prevGrounded && !hitbox.grounded) {
|
|
||||||
auto appliedVelocity = hitbox.groundVelocity;
|
|
||||||
vel += appliedVelocity;
|
|
||||||
hitbox.groundVelocity = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
AABB aabb;
|
vel.x /= 1.0f + delta * linearDamping;
|
||||||
aabb.a = pos - hitbox.getHalfSize();
|
vel.z /= 1.0f + delta * linearDamping;
|
||||||
aabb.b = pos + hitbox.getHalfSize();
|
if (hitbox->verticalDamping > 0.0f) {
|
||||||
for (size_t i = 0; i < sensors.size(); i++) {
|
vel.y /= 1.0f + delta * linearDamping * hitbox->verticalDamping;
|
||||||
auto& sensor = *sensors[i];
|
}
|
||||||
if (sensor.entity == entity) {
|
if (hitbox->prevGrounded && !hitbox->grounded) {
|
||||||
continue;
|
auto appliedVelocity = hitbox->groundVelocity / dt;
|
||||||
|
vel += appliedVelocity;
|
||||||
|
hitbox->groundVelocity = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool triggered = false;
|
AABB aabb;
|
||||||
switch (sensor.type) {
|
aabb.a = pos - hitbox->getHalfSize();
|
||||||
case SensorType::AABB:
|
aabb.b = pos + hitbox->getHalfSize();
|
||||||
triggered = aabb.intersects(sensor.calculated.aabb);
|
for (size_t i = 0; i < sensors.size(); i++) {
|
||||||
break;
|
auto& sensor = *sensors[i];
|
||||||
case SensorType::RADIUS:
|
if (sensor.entity == hitbox->entity) {
|
||||||
triggered = glm::distance2(
|
continue;
|
||||||
pos, glm::vec3(sensor.calculated.radial))
|
|
||||||
< sensor.calculated.radial.w;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (triggered) {
|
|
||||||
if (sensor.prevEntered.find(entity) == sensor.prevEntered.end()) {
|
|
||||||
sensor.enterCallback(sensor.entity, sensor.index, entity);
|
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,8 @@ public:
|
||||||
PhysicsSolver(glm::vec3 gravity);
|
PhysicsSolver(glm::vec3 gravity);
|
||||||
void step(
|
void step(
|
||||||
const GlobalChunks& chunks,
|
const GlobalChunks& chunks,
|
||||||
Hitbox& hitbox,
|
|
||||||
float delta,
|
float delta,
|
||||||
uint substeps,
|
uint substeps
|
||||||
entityid_t entity
|
|
||||||
);
|
);
|
||||||
|
|
||||||
auto& getSensorsWriteable() {
|
auto& getSensorsWriteable() {
|
||||||
|
|
@ -32,11 +30,16 @@ public:
|
||||||
return solidHitboxes;
|
return solidHitboxes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& getHitboxesWriteable() {
|
||||||
|
return hitboxes;
|
||||||
|
}
|
||||||
|
|
||||||
void removeSensor(Sensor* sensor);
|
void removeSensor(Sensor* sensor);
|
||||||
private:
|
private:
|
||||||
glm::vec3 gravity;
|
glm::vec3 gravity;
|
||||||
std::vector<Sensor*> sensors;
|
std::vector<Sensor*> sensors;
|
||||||
std::vector<Hitbox*> solidHitboxes;
|
std::vector<Hitbox*> solidHitboxes;
|
||||||
|
std::vector<Hitbox*> hitboxes;
|
||||||
|
|
||||||
void calcCollisions(
|
void calcCollisions(
|
||||||
const GlobalChunks& chunks,
|
const GlobalChunks& chunks,
|
||||||
|
|
@ -52,7 +55,6 @@ private:
|
||||||
Hitbox& hitbox,
|
Hitbox& hitbox,
|
||||||
glm::vec3& vel,
|
glm::vec3& vel,
|
||||||
glm::vec3& pos,
|
glm::vec3& pos,
|
||||||
bool prevGrounded,
|
|
||||||
float dt,
|
float dt,
|
||||||
int substeps
|
int substeps
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue