💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
8.0 KiB

  1. /*
  2. * Copyright (C) 2017 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper Source Code.
  5. *
  6. * Antkeeper Source Code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper Source Code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "ant.hpp"
  20. #include "colony.hpp"
  21. #include "pheromone-matrix.hpp"
  22. #include <cmath>
  23. float FRAMES_PER_SECOND = 60;
  24. float TIMESTEP = 1.0f / FRAMES_PER_SECOND;
  25. float ANT_LENGTH = 0.5f; // 0.5 cm, head to abdomen (not including legs / antennae)
  26. float ANT_COLLISION_RADIUS = ANT_LENGTH * 1.25f;
  27. float RECEPTOR_RADIUS = 0.4f;
  28. float RECEPTOR_SEPARATION = 0.882f;
  29. float RECEPTOR_DISTANCE = 0.588f;
  30. float MOUTH_DISTANCE = 0.2646f;
  31. float BITE_RADIUS = 0.0294f;
  32. float FOOD_PARTICLE_RADIUS = 0.1176f;
  33. float MAX_RECEPTOR_NOISE = 0.05f; // essentially an epsilon
  34. float MAX_EXCITEMENT = 1.0f;
  35. float MAX_PHEROMONE_TURNING_ANGLE = glm::radians(8.5f);
  36. float MIN_WALK_TIME = 0.5f; // seconds
  37. float MAX_WALK_TIME = 8.0f; // seconds
  38. float MIN_REST_TIME = 0.15f;
  39. float MAX_REST_TIME = 0.7f;
  40. float MIN_CHEW_TIME = 0.25f;
  41. float MAX_CHEW_TIME = 0.5f;
  42. float DEEXCITEMENT_FACTOR = 0.999f; // This should probably always be less than the evaporation factor
  43. float CALM_FACTOR = 0.995f;
  44. float MAX_WALK_FORCE = 1.5;
  45. float MAX_PANIC_FORCE = 0.1029f;
  46. float MAX_WALK_SPEED = 3.0f; // cm/s
  47. float MAX_PANIC_SPEED = 8.82f; // cm/s
  48. float PANIC_RADIUS = 7.35f;
  49. float WANDER_CIRCLE_DISTANCE = 0.441f;
  50. float WANDER_CIRCLE_RADIUS = 0.0294f;
  51. float MAX_WANDER_ANGLE = 0.15f;
  52. inline float fwrap(float angle, float limit)
  53. {
  54. return angle - std::floor(angle / limit) * limit;
  55. }
  56. Ant::Ant(Colony* colony):
  57. colony(colony),
  58. state(Ant::State::IDLE),
  59. transform(Transform::getIdentity()),
  60. pose(nullptr)
  61. {
  62. pose = new Pose(colony->getAntModel()->getSkeleton());
  63. pose->reset();
  64. pose->concatenate();
  65. modelInstance.setModel(colony->getAntModel());
  66. modelInstance.setPose(pose);
  67. animationTime = frand(0.0f, 60.0f);
  68. velocity = Vector3(0);
  69. acceleration = Vector3(0);
  70. wanderDirection = getForward();
  71. excitement = MAX_EXCITEMENT;
  72. }
  73. Ant::~Ant()
  74. {
  75. delete pose;
  76. }
  77. void Ant::animate()
  78. {
  79. colony->getTripodGaitAnimation()->animate(pose, animationTime);
  80. pose->concatenate();
  81. animationTime = fwrap(animationTime + 4.0f, colony->getTripodGaitAnimation()->getEndTime());
  82. }
  83. void Ant::suspend(const Vector3& suspensionPoint, const Quaternion& suspensionRotation)
  84. {
  85. transform.translation = suspensionPoint;
  86. transform.rotation = suspensionRotation;
  87. modelInstance.setTransform(transform);
  88. }
  89. void Ant::move(const Vector3& velocity)
  90. {
  91. std::vector<Navmesh::Step> traversal;
  92. Navmesh::traverse(getNavmeshTriangle(), getBarycentricPosition(), velocity, &traversal);
  93. if (!traversal.empty())
  94. {
  95. const Navmesh::Step& step = traversal.back();
  96. if (step.start != step.end)
  97. {
  98. if (step.triangle != getNavmeshTriangle())
  99. {
  100. Quaternion alignment = glm::rotation(getNavmeshTriangle()->normal, step.triangle->normal);
  101. Vector3 newForward = glm::normalize(project_on_plane(alignment * getForward(), Vector3(0.0f), step.triangle->normal));
  102. setOrientation(newForward, step.triangle->normal);
  103. }
  104. }
  105. setPosition(step.triangle, step.end);
  106. }
  107. }
  108. void Ant::turn(float angle)
  109. {
  110. // Rotate forward vector
  111. Vector3 newForward = glm::normalize(glm::angleAxis(angle, getUp()) * getForward());
  112. setOrientation(newForward, getUp());
  113. }
  114. void Ant::update(float dt)
  115. {
  116. float probeLateralOffset = 0.1f;
  117. float probeForwardOffset = 0.3f;
  118. animate();
  119. // Calculate positions of receptors
  120. receptorL = getPosition() + getForward() * RECEPTOR_DISTANCE;
  121. receptorR = receptorL;
  122. receptorL -= getRight() * RECEPTOR_SEPARATION * 0.5f;
  123. receptorR += getRight() * RECEPTOR_SEPARATION * 0.5f;
  124. // Steering
  125. if (state == Ant::State::WANDER)
  126. {
  127. //setWanderCircleDistance(4.0f);
  128. //setWanderCircleRadius(0.3f);
  129. //setWanderRate(glm::radians(90.0f));
  130. //setSeparationRadius(0.5f);
  131. //setMaxSpeed(0.025f);
  132. // Calculate wander force
  133. Vector3 wanderForce = wander() * 1.5f;
  134. Vector3 followForce = follow() * 3.0f;
  135. // Setup containment probes
  136. //Vector3 leftProbe = getForward() * probeForwardOffset - getRight() * probeLateralOffset;
  137. //Vector3 rightProbe = getForward() * probeForwardOffset + getRight() * probeLateralOffset;
  138. // Calculate containment force
  139. //Vector3 containmentForce = containment(leftProbe) + containment(rightProbe);
  140. // Determine neighbors
  141. //float neighborhoodSize = 2.0f;
  142. //AABB neighborhoodAABB(getPosition() - Vector3(neighborhoodSize * 0.5f), getPosition() + Vector3(neighborhoodSize * 0.5f));
  143. //std::list<Agent*> neighbors;
  144. //colony->queryAnts(neighborhoodAABB, &neighbors);
  145. // Calculate separation force
  146. //Vector3 separationForce = separation(neighbors);
  147. applyForce(wanderForce);
  148. applyForce(followForce);
  149. float maxSpeed = MAX_WALK_SPEED * TIMESTEP;
  150. // Limit acceleration
  151. float accelerationMagnitudeSquared = glm::dot(acceleration, acceleration);
  152. if (accelerationMagnitudeSquared > MAX_WALK_FORCE * MAX_WALK_FORCE)
  153. {
  154. acceleration = glm::normalize(acceleration) * MAX_WALK_FORCE;
  155. }
  156. // Accelerate
  157. velocity += acceleration;
  158. // Limit speed
  159. float speedSquared = glm::dot(velocity, velocity);
  160. if (speedSquared > maxSpeed * maxSpeed)
  161. {
  162. velocity = glm::normalize(velocity) * maxSpeed;
  163. }
  164. Vector3 direction = glm::normalize(velocity);
  165. setOrientation(direction, getUp());
  166. // Deposit pheromones
  167. Vector2 position2D = Vector2(getPosition().x, getPosition().z);
  168. colony->getHomingMatrix()->deposit(position2D, excitement);
  169. excitement *= DEEXCITEMENT_FACTOR;
  170. // Move ant
  171. move(velocity);
  172. }
  173. else if (state == Ant::State::IDLE)
  174. {
  175. velocity = Vector3(0.0f);
  176. // Move ant
  177. move(velocity);
  178. }
  179. // Update transform
  180. if (state == Ant::State::WANDER || state == Ant::State::IDLE)
  181. {
  182. transform.translation = getPosition();
  183. transform.rotation = getRotation();
  184. // Update model instance
  185. modelInstance.setTransform(transform);
  186. }
  187. }
  188. void Ant::setState(Ant::State state)
  189. {
  190. this->state = state;
  191. }
  192. Vector3 Ant::seek(const Vector3& target)
  193. {
  194. Vector3 steer(0.0f);
  195. Vector3 difference = target - getPosition();
  196. float distanceSquared = glm::dot(difference, difference);
  197. if (distanceSquared > 0.0f)
  198. {
  199. float maxForce = MAX_WALK_FORCE;
  200. steer = glm::normalize(difference) * maxForce - velocity;
  201. }
  202. return steer;
  203. }
  204. Vector3 Ant::flee(const Vector3& target)
  205. {
  206. return -seek(target);
  207. }
  208. Vector3 Ant::wander()
  209. {
  210. // Determine center of wander circle
  211. Vector3 center = getPosition() + getForward() * WANDER_CIRCLE_DISTANCE;
  212. // Calculate wander target
  213. Vector3 target = center + wanderDirection * WANDER_CIRCLE_RADIUS;
  214. // Rotate wander direction by a random displacement angle
  215. float displacement = frand(-MAX_WANDER_ANGLE, MAX_WANDER_ANGLE);
  216. wanderDirection = glm::normalize(glm::angleAxis(displacement, getUp()) * wanderDirection);
  217. return seek(target);
  218. }
  219. Vector3 Ant::follow()
  220. {
  221. const PheromoneMatrix* pheromoneMatrix = colony->getRecruitmentMatrix();
  222. Vector2 receptorL2D = Vector2(receptorL.x, receptorL.z);
  223. Vector2 receptorR2D = Vector2(receptorR.x, receptorR.z);
  224. float signalL = pheromoneMatrix->query(receptorL2D, RECEPTOR_RADIUS);
  225. signalL += frand(0.0f, MAX_RECEPTOR_NOISE);
  226. float signalR = pheromoneMatrix->query(receptorR2D, RECEPTOR_RADIUS);
  227. signalR += frand(0.0f, MAX_RECEPTOR_NOISE);
  228. if (signalL + signalR > 0.0f)
  229. {
  230. float angle = -MAX_PHEROMONE_TURNING_ANGLE * ((signalL - signalR) / (signalL + signalR));
  231. Vector3 steer = glm::normalize(glm::angleAxis(angle, getUp()) * getForward());
  232. return steer;
  233. }
  234. return Vector3(0.0f);
  235. }
  236. void Ant::applyForce(const Vector3& force)
  237. {
  238. acceleration += force;
  239. }