);
state.pos += f.vel * dt;
state.vel += f.acc * dt;
+ situation.EnforceConstraints(state);
if (length2(state.vel) > 0.000001) {
glm::dvec3 nvel(normalize(state.vel));
double ang = angle(nvel, state.dir);
- double turn_rate = PI * 0.5 * dt;
+ double turn_rate = PI * 0.75 * dt;
if (ang < turn_rate) {
state.dir = normalize(state.vel);
} else if (std::abs(ang - PI) < 0.001) {
}
}
situation.SetState(state);
- stats.Exhaustion().Add(length(f.acc) * Mass() / Stamina() * dt);
+ stats.Exhaustion().Add(length(f.acc) * Mass() / Stamina() * 0.5 * dt);
}
Situation::Derivative Creature::Step(const Situation::Derivative &ds, double dt) const noexcept {
Situation::State s = situation.GetState();
s.pos += ds.vel * dt;
s.vel += ds.acc * dt;
+ glm::dvec3 force(steering.Force(s));
+ // gravity = antinormal * mass * Gm / r²
+ double elevation = s.pos[(situation.Surface() + 2) % 3];
+ glm::dvec3 normal(world::Planet::SurfaceNormal(situation.Surface()));
+ force += glm::dvec3(
+ -normal
+ * Mass() * situation.GetPlanet().GravitationalParameter()
+ / (elevation * elevation));
+ // if net force is applied and in contact with surface
+ if (!allzero(force) && std::abs(std::abs(elevation) - situation.GetPlanet().Radius()) < 0.001) {
+ // apply friction = -|normal force| * tangential force * coefficient
+ glm::dvec3 fn(normal * dot(force, normal));
+ glm::dvec3 ft(force - fn);
+ double u = 0.4;
+ glm::dvec3 friction(-length(fn) * ft * u);
+ force += friction;
+ }
return {
s.vel,
- steering.Force(s) / Mass()
+ force / Mass()
};
}
// TODO: duplicate situation somehow
a->GetSituation().SetPlanetSurface(
s.GetPlanet(), s.Surface(),
- s.Position() + glm::dvec3(0.0, a->Size() + 0.1, 0.0));
+ s.Position() + glm::dvec3(0.0, 0.55 * a->Size(), 0.0));
a->BuildVAO();
std::cout << "[" << int(c.GetSimulation().Time()) << "s] "
<< a->Name() << " was born" << std::endl;
s.GetPlanet().AddCreature(b);
b->GetSituation().SetPlanetSurface(
s.GetPlanet(), s.Surface(),
- s.Position() + glm::dvec3(0.0, b->Size() - 0.1, 0.0));
+ s.Position() - glm::dvec3(0.0, 0.55 * b->Size(), 0.0));
b->BuildVAO();
std::cout << "[" << int(c.GetSimulation().Time()) << "s] "
<< b->Name() << " was born" << std::endl;
void Situation::Move(const glm::dvec3 &dp) noexcept {
state.pos += dp;
+ EnforceConstraints(state);
+}
+
+void Situation::Accelerate(const glm::dvec3 &dv) noexcept {
+ state.vel += dv;
+ EnforceConstraints(state);
+}
+
+void Situation::EnforceConstraints(State &s) noexcept {
if (OnSurface()) {
- // enforce ground constraint
if (Surface() < 3) {
- state.pos[(Surface() + 2) % 3] = std::max(0.0, state.pos[(Surface() + 2) % 3]);
+ if (s.pos[(Surface() + 2) % 3] < GetPlanet().Radius()) {
+ s.pos[(Surface() + 2) % 3] = GetPlanet().Radius();
+ s.vel[(Surface() + 2) % 3] = std::max(0.0, s.vel[(Surface() + 2) % 3]);
+ }
} else {
- state.pos[(Surface() + 2) % 3] = std::min(0.0, state.pos[(Surface() + 2) % 3]);
+ if (s.pos[(Surface() + 2) % 3] > -GetPlanet().Radius()) {
+ s.pos[(Surface() + 2) % 3] = -GetPlanet().Radius();
+ s.vel[(Surface() + 2) % 3] = std::min(0.0, s.vel[(Surface() + 2) % 3]);
+ }
}
}
}
planet = &p;
surface = srf;
state.pos = pos;
+ EnforceConstraints(state);
}
}
void Steering::ResumeSeparate() noexcept {
- separating = false;
+ separating = true;
}
void Steering::Halt() noexcept {
, age(new Label(assets.fonts.medium))
, mass(new Label(assets.fonts.medium))
, pos(new Label(assets.fonts.medium))
+, vel(new Label(assets.fonts.medium))
+, dir(new Label(assets.fonts.medium))
, tile(new Label(assets.fonts.medium))
, goal(new Label(assets.fonts.medium))
, stats{nullptr}
->Spacing(10.0f)
->Direction(Panel::HORIZONTAL);
+ vel->Text("<00.0, 00.0, 00.0>");
+ Label *vel_label = new Label(assets.fonts.medium);
+ vel_label->Text("Vel");
+ Panel *vel_panel = new Panel;
+ vel_panel
+ ->Add(vel_label)
+ ->Add(vel)
+ ->Spacing(10.0f)
+ ->Direction(Panel::HORIZONTAL);
+
+ dir->Text("<0.00, 0.00, 0.00>");
+ Label *dir_label = new Label(assets.fonts.medium);
+ dir_label->Text("Dir");
+ Panel *dir_panel = new Panel;
+ dir_panel
+ ->Add(dir_label)
+ ->Add(dir)
+ ->Spacing(10.0f)
+ ->Direction(Panel::HORIZONTAL);
+
tile->Text("<00, 00> (mountains)");
Label *tile_label = new Label(assets.fonts.medium);
tile_label->Text("Tile");
->Add(born_panel)
->Add(mass_panel)
->Add(pos_panel)
+ ->Add(vel_panel)
+ ->Add(dir_panel)
->Add(tile_panel)
->Add(goal_panel)
->Add(stat_panel)
<< "<" << p.x << ", " << p.y << ", " << p.z << ">";
pos->Text(ss.str());
}
+ {
+ const glm::dvec3 &v = c->GetSituation().Velocity();
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(1)
+ << "<" << v.x << ", " << v.y << ", " << v.z << ">";
+ vel->Text(ss.str());
+ }
+ {
+ const glm::dvec3 &d = c->GetSituation().GetState().dir;
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(2)
+ << "<" << d.x << ", " << d.y << ", " << d.z << ">";
+ dir->Text(ss.str());
+ }
{
glm::ivec2 t = c->GetSituation().SurfacePosition();
std::stringstream ss;
for (auto &c : collisions) {
c.A().GetSituation().Move(c.Normal() * (c.Depth() * -0.5));
c.B().GetSituation().Move(c.Normal() * (c.Depth() * 0.5));
- // TODO: adjust velocities as well
+ c.A().GetSituation().Accelerate(c.Normal() * -dot(c.Normal(), c.AVel()));
+ c.B().GetSituation().Accelerate(c.Normal() * -dot(c.Normal(), c.BVel()));
// TODO: notify participants so they can be annoyed
}
}
return a->GetSituation().Position();
}
+const glm::dvec3 &CreatureCreatureCollision::AVel() const noexcept {
+ return a->GetSituation().Velocity();
+}
+
const glm::dvec3 &CreatureCreatureCollision::BPos() const noexcept {
return b->GetSituation().Position();
}
+const glm::dvec3 &CreatureCreatureCollision::BVel() const noexcept {
+ return b->GetSituation().Velocity();
+}
+
Orbit::Orbit()
: sma(1.0)