void DynamicBody::CalcExternalForce() { // gravity if (!GetFrame()) return; // no external force if not in a frame Body *body = GetFrame()->GetBody(); if (body && !body->IsType(Object::SPACESTATION)) { // they ought to have mass though... vector3d b1b2 = GetPosition(); double m1m2 = GetMass() * body->GetMass(); double invrsqr = 1.0 / b1b2.LengthSqr(); double force = G*m1m2 * invrsqr; m_externalForce = -b1b2 * sqrt(invrsqr) * force; } else m_externalForce = vector3d(0.0); m_gravityForce = m_externalForce; // atmospheric drag if (body && GetFrame()->IsRotFrame() && body->IsType(Object::PLANET)) { Planet *planet = static_cast<Planet*>(body); double dist = GetPosition().Length(); double speed = m_vel.Length(); double pressure, density; planet->GetAtmosphericState(dist, &pressure, &density); const double radius = GetClipRadius(); // bogus, preserving behaviour const double AREA = radius; // ^^^ yes that is as stupid as it looks const double DRAG_COEFF = 0.1; // 'smooth sphere' vector3d dragDir = -m_vel.NormalizedSafe(); vector3d fDrag = 0.5*density*speed*speed*AREA*DRAG_COEFF*dragDir; // make this a bit less daft at high time accel // only allow atmosForce to increase by .1g per frame vector3d f1g = m_atmosForce + dragDir * GetMass(); if (fDrag.LengthSqr() > f1g.LengthSqr()) m_atmosForce = f1g; else m_atmosForce = fDrag; m_externalForce += m_atmosForce; } else m_atmosForce = vector3d(0.0); // centrifugal and coriolis forces for rotating frames if (GetFrame()->IsRotFrame()) { vector3d angRot(0, GetFrame()->GetAngSpeed(), 0); m_externalForce -= m_mass * angRot.Cross(angRot.Cross(GetPosition())); // centrifugal m_externalForce -= 2 * m_mass * angRot.Cross(GetVelocity()); // coriolis } }
void DynamicsSystem::update(ent_ptr<EntityManager> em, ent_ptr<EventManager> events, double dt) { for (auto entity : em->entities_with_components<DynamicsComponent>()) { ent_ptr<DynamicsComponent> dc = entity.component<DynamicsComponent>(); ent_ptr<PosOrientComponent> poc = entity.component<PosOrientComponent>(); ent_ptr<MassComponent> mc = entity.component<MassComponent>(); SDL_assert(poc); SDL_assert(mc); //save previous //poc->oldPos = poc->pos; //poc->oldAngDisplacement = dc->angVel * dt; dc->force += dc->externalForce; dc->vel += dt * dc->force * (1.0 / mc->mass); dc->angVel += dt * dc->torque * (1.0 / dc->angInertia); //update pos poc->pos += dc->vel * dt; //update orient double len = dc->angVel.Length(); if (len > 1e-16) { vector3d axis = dc->angVel * (1.0 / len); matrix3x3d r = matrix3x3d::Rotate(len * dt, axis); poc->orient = r * poc->orient; } dc->force = vector3d(0.0); dc->torque = vector3d(0.0); //calculate external forces //- gravity //- atmospheric drag //- centrifugal/coriolis force auto fc = entity.component<FrameComponent>(); if (fc) { if (fc->frame->IsRotFrame()) { vector3d angRot(0, fc->frame->GetAngSpeed(), 0); dc->externalForce -= mc->mass * angRot.Cross(angRot.Cross(poc->pos)); // centrifugal dc->externalForce -= 2 * mc->mass * angRot.Cross(dc->vel); // coriolis } } } }
void DynamicBody::CalcExternalForce() { // gravity if (!GetFrame()) return; // no external force if not in a frame Body *body = GetFrame()->GetBody(); if (body && !body->IsType(Object::SPACESTATION)) { // they ought to have mass though... vector3d b1b2 = GetPosition(); double m1m2 = GetMass() * body->GetMass(); double invrsqr = 1.0 / b1b2.LengthSqr(); double force = G*m1m2 * invrsqr; m_externalForce = -b1b2 * sqrt(invrsqr) * force; } else m_externalForce = vector3d(0.0); m_gravityForce = m_externalForce; // atmospheric drag if (body && GetFrame()->IsRotFrame() && body->IsType(Object::PLANET)) { vector3d dragDir = -m_vel.NormalizedSafe(); vector3d fDrag = CalcAtmosphericForce(m_dragCoeff)*dragDir; // make this a bit less daft at high time accel // only allow atmosForce to increase by .1g per frame vector3d f1g = m_atmosForce + dragDir * GetMass(); if (fDrag.LengthSqr() > f1g.LengthSqr()) m_atmosForce = f1g; else m_atmosForce = fDrag; m_externalForce += m_atmosForce; } else m_atmosForce = vector3d(0.0); // centrifugal and coriolis forces for rotating frames if (GetFrame()->IsRotFrame()) { vector3d angRot(0, GetFrame()->GetAngSpeed(), 0); m_externalForce -= m_mass * angRot.Cross(angRot.Cross(GetPosition())); // centrifugal m_externalForce -= 2 * m_mass * angRot.Cross(GetVelocity()); // coriolis } }