X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fcreature%2Fcreature.cpp;h=1cf4a3a5c511aa16e9874fd30b71dce9215c10f7;hb=7e02b21428efa3ebec14a34d0c1f81e81d362bfc;hp=72d0b3f348e3c548ba55f6dcc00c52c6694408af;hpb=00f55d5b55ff993d2516f00f8d635887562983c7;p=blobs.git diff --git a/src/creature/creature.cpp b/src/creature/creature.cpp index 72d0b3f..1cf4a3a 100644 --- a/src/creature/creature.cpp +++ b/src/creature/creature.cpp @@ -139,6 +139,11 @@ Creature::Creature(world::Simulation &sim) , goals() , situation() , steering(*this) +, perception_range(1.0) +, perception_range_squared(1.0) +, perception_omni_range(1.0) +, perception_omni_range_squared(1.0) +, perception_field(1.0) , vao() { sim.SetAlive(this); // all creatures avoid each other for now @@ -331,7 +336,8 @@ double Creature::Strength() const noexcept { } double Creature::StrengthFactor() const noexcept { - return Strength() / (Strength() + 1.0); + double str = Strength(); + return str / (str + 1.0); } double Creature::Stamina() const noexcept { @@ -339,7 +345,8 @@ double Creature::Stamina() const noexcept { } double Creature::StaminaFactor() const noexcept { - return Stamina() / (Stamina() + 1.0); + double stm = Stamina(); + return stm / (stm + 1.0); } double Creature::Dexerty() const noexcept { @@ -347,7 +354,8 @@ double Creature::Dexerty() const noexcept { } double Creature::DexertyFactor() const noexcept { - return Dexerty() / (Dexerty() + 1.0); + double dex = Dexerty(); + return dex / (dex + 1.0); } double Creature::Intelligence() const noexcept { @@ -355,7 +363,8 @@ double Creature::Intelligence() const noexcept { } double Creature::IntelligenceFactor() const noexcept { - return Intelligence() / (Intelligence() + 1.0); + double intl = Intelligence(); + return intl / (intl + 1.0); } double Creature::Lifetime() const noexcept { @@ -379,25 +388,23 @@ double Creature::OffspringMass() const noexcept { } double Creature::PerceptionRange() const noexcept { - return 3.0 * DexertyFactor() + Size(); + return perception_range; } double Creature::PerceptionOmniRange() const noexcept { - return 0.5 * DexertyFactor() + Size(); + return perception_omni_range; } double Creature::PerceptionField() const noexcept { - // this is the cosine of half the angle, so 1.0 is none, -1.0 is perfect - return 0.8 - DexertyFactor(); + return perception_field; } bool Creature::PerceptionTest(const glm::dvec3 &p) const noexcept { const glm::dvec3 diff(p - situation.Position()); - double omni_range = PerceptionOmniRange(); - if (glm::length2(diff) < omni_range * omni_range) return true; - double range = PerceptionRange(); - if (glm::length2(diff) > range * range) return false; - return glm::dot(glm::normalize(diff), situation.Heading()) > PerceptionField(); + double ldiff = glm::length2(diff); + if (ldiff < perception_omni_range_squared) return true; + if (ldiff > perception_range_squared) return false; + return glm::dot(diff / std::sqrt(ldiff), situation.Heading()) > perception_field; } double Creature::OffspringChance() const noexcept { @@ -429,11 +436,22 @@ bool GoalCompare(const std::unique_ptr &a, const std::unique_ptr &b) } void Creature::Tick(double dt) { + Cache(); TickState(dt); TickStats(dt); TickBrain(dt); } +void Creature::Cache() noexcept { + double dex_fact = DexertyFactor(); + perception_range = 3.0 * dex_fact + size; + perception_range_squared = perception_range * perception_range; + perception_omni_range = 0.5 * dex_fact + size; + perception_omni_range_squared = perception_omni_range * perception_omni_range; + // this is the cosine of half the angle, so 1.0 is none, -1.0 is perfect + perception_field = 0.8 - dex_fact; +} + void Creature::TickState(double dt) { steering.MaxSpeed(Dexerty()); steering.MaxForce(Strength()); @@ -463,28 +481,31 @@ void Creature::TickState(double dt) { } situation.SetState(state); // work is force times distance - DoWork(glm::length(f.acc) * Mass() * glm::length(f.vel) * dt); + // exclude gravity for no apparent reason + // actually, this should solely be based on steering force + DoWork(glm::length(f.acc - situation.GetPlanet().GravityAt(state.pos)) * Mass() * glm::length(f.vel) * 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; + situation.EnforceConstraints(s); glm::dvec3 force(steering.Force(s)); // gravity = antinormal * mass * Gm / r² - double elevation = situation.GetPlanet().DistanceAt(s.pos); glm::dvec3 normal(situation.GetPlanet().NormalAt(s.pos)); force += glm::dvec3( -normal - * Mass() * situation.GetPlanet().GravitationalParameter() - / (elevation * elevation)); + * (Mass() * situation.GetPlanet().GravitationalParameter() + / glm::length2(s.pos))); // 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 + if (!allzero(force) && !allzero(s.vel) && glm::length2(s.pos) < (situation.GetPlanet().Radius() + 0.01) * (situation.GetPlanet().Radius() + 0.01)) { + // apply friction glm::dvec3 fn(normal * glm::dot(force, normal)); + // TODO: friction somehow bigger than force? glm::dvec3 ft(force - fn); double u = 0.4; - glm::dvec3 friction(-glm::length(fn) * ft * u); + glm::dvec3 friction(-glm::clamp(glm::length(ft), 0.0, glm::length(fn) * u) * glm::normalize(s.vel)); force += friction; } return { @@ -550,7 +571,7 @@ void Creature::TickBrain(double dt) { } } -math::AABB Creature::CollisionBox() const noexcept { +math::AABB Creature::CollisionBounds() const noexcept { return { glm::dvec3(size * -0.5), glm::dvec3(size * 0.5) }; } @@ -848,7 +869,7 @@ bool Memory::RememberLocation(const Composition &accept, glm::dvec3 &pos) const c.GetSimulation().Assets().random.SNorm(), c.GetSimulation().Assets().random.SNorm(), c.GetSimulation().Assets().random.SNorm()); - pos += error * (2.0 * (1.0 - c.IntelligenceFactor())); + pos += error * (4.0 * (1.0 - c.IntelligenceFactor())); pos = glm::normalize(pos) * c.GetSituation().GetPlanet().Radius(); return true; } else { @@ -927,6 +948,10 @@ bool Situation::OnSurface() const noexcept { return type == PLANET_SURFACE; } +bool Situation::OnGround() const noexcept { + return OnSurface() && glm::length2(state.pos) < (planet->Radius() + 0.05) * (planet->Radius() + 0.05); +} + glm::dvec3 Situation::SurfaceNormal() const noexcept { return planet->NormalAt(state.pos); } @@ -949,11 +974,13 @@ void Situation::Accelerate(const glm::dvec3 &dv) noexcept { EnforceConstraints(state); } -void Situation::EnforceConstraints(State &s) noexcept { +void Situation::EnforceConstraints(State &s) const noexcept { if (OnSurface()) { double r = GetPlanet().Radius(); if (glm::length2(s.pos) < r * r) { - s.pos = glm::normalize(s.pos) * r; + const glm::dvec3 normal(GetPlanet().NormalAt(s.pos)); + s.pos = normal * r; + s.vel -= normal * glm::dot(normal, s.vel); } } } @@ -1059,6 +1086,10 @@ glm::dvec3 Steering::Force(const Situation::State &s) const noexcept { result += TargetVelocity(s, diff * std::min(dist * force, speed) / dist, force); } } + // remove vertical component, if any + const glm::dvec3 normal(c.GetSituation().GetPlanet().NormalAt(s.pos)); + result -= normal * glm::dot(normal, result); + // clamp to max if (glm::length2(result) > max_force * max_force) { result = glm::normalize(result) * max_force; }