💿🐜 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.

240 lines
7.1 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.hpp"
  22. #include <cmath>
  23. inline float fwrap(float angle, float limit)
  24. {
  25. return angle - std::floor(angle / limit) * limit;
  26. }
  27. Ant::Ant(Colony* colony):
  28. colony(colony),
  29. state(Ant::State::IDLE),
  30. transform(Transform::getIdentity()),
  31. pose(nullptr)
  32. {
  33. pose = new Pose(colony->getAntModel()->getSkeleton());
  34. pose->reset();
  35. pose->concatenate();
  36. modelInstance.setModel(colony->getAntModel());
  37. modelInstance.setPose(pose);
  38. animationTime = frand(0.0f, 60.0f);
  39. }
  40. Ant::~Ant()
  41. {
  42. delete pose;
  43. }
  44. void Ant::animate()
  45. {
  46. colony->getTripodGaitAnimation()->animate(pose, animationTime);
  47. pose->concatenate();
  48. animationTime = fwrap(animationTime + 2.0f, colony->getTripodGaitAnimation()->getEndTime());
  49. }
  50. void Ant::suspend(const Vector3& suspensionPoint, const Quaternion& suspensionRotation)
  51. {
  52. transform.translation = suspensionPoint;
  53. transform.rotation = suspensionRotation;
  54. modelInstance.setTransform(transform);
  55. }
  56. void Ant::move(const Vector3& velocity)
  57. {
  58. std::vector<Navmesh::Step> traversal;
  59. Navmesh::traverse(getNavmeshTriangle(), getBarycentricPosition(), velocity, &traversal);
  60. if (!traversal.empty())
  61. {
  62. const Navmesh::Step& step = traversal.back();
  63. if (step.start != step.end)
  64. {
  65. if (step.triangle != getNavmeshTriangle())
  66. {
  67. Quaternion alignment = glm::rotation(getNavmeshTriangle()->normal, step.triangle->normal);
  68. Vector3 newForward = glm::normalize(project_on_plane(alignment * getForward(), Vector3(0.0f), step.triangle->normal));
  69. setOrientation(newForward, step.triangle->normal);
  70. }
  71. }
  72. setPosition(step.triangle, step.end);
  73. }
  74. }
  75. void Ant::turn(float angle)
  76. {
  77. // Rotate forward vector
  78. Vector3 newForward = glm::normalize(glm::angleAxis(angle, getUp()) * getForward());
  79. setOrientation(newForward, getUp());
  80. }
  81. void Ant::update(float dt)
  82. {
  83. float probeLateralOffset = 0.1f;
  84. float probeForwardOffset = 0.3f;
  85. animate();
  86. // Steering
  87. if (state == Ant::State::WANDER)
  88. {
  89. setWanderCircleDistance(4.0f);
  90. setWanderCircleRadius(0.3f);
  91. setWanderRate(glm::radians(90.0f));
  92. setSeparationRadius(0.5f);
  93. setMaxSpeed(0.025f);
  94. // Calculate wander force
  95. Vector3 wanderForce = wander(dt);
  96. // Setup containment probes
  97. Vector3 leftProbe = getForward() * probeForwardOffset - getRight() * probeLateralOffset;
  98. Vector3 rightProbe = getForward() * probeForwardOffset + getRight() * probeLateralOffset;
  99. // Calculate containment force
  100. Vector3 containmentForce = containment(leftProbe) + containment(rightProbe);
  101. // Determine neighbors
  102. float neighborhoodSize = 2.0f;
  103. AABB neighborhoodAABB(getPosition() - Vector3(neighborhoodSize * 0.5f), getPosition() + Vector3(neighborhoodSize * 0.5f));
  104. std::list<Agent*> neighbors;
  105. colony->queryAnts(neighborhoodAABB, &neighbors);
  106. // Calculate separation force
  107. Vector3 separationForce = separation(neighbors);
  108. // Calculate velocity
  109. Vector3 velocity = getVelocity();
  110. velocity += wanderForce;
  111. velocity += containmentForce * 0.0025f;
  112. velocity += separationForce * 0.01f;
  113. velocity = limit(velocity, 0.025f);
  114. setVelocity(velocity);
  115. setOrientation(glm::normalize(velocity), getUp());
  116. // Move ant
  117. move(velocity);
  118. }
  119. else if (state == Ant::State::IDLE)
  120. {
  121. Vector3 leftProbe = getForward() * probeForwardOffset - getRight() * probeLateralOffset;
  122. Vector3 rightProbe = getForward() * probeForwardOffset + getRight() * probeLateralOffset;
  123. Vector3 containmentForce = containment(leftProbe) + containment(rightProbe);
  124. Vector3 velocity = Vector3(0.0f);
  125. velocity += containmentForce;
  126. velocity = limit(velocity, 0.025f);
  127. setVelocity(velocity);
  128. //setOrientation(glm::normalize(velocity), getUp());
  129. // Move ant
  130. move(velocity);
  131. }
  132. // Update transform
  133. if (state == Ant::State::WANDER || state == Ant::State::IDLE)
  134. {
  135. transform.translation = getPosition();
  136. transform.rotation = getRotation();
  137. // Update model instance
  138. modelInstance.setTransform(transform);
  139. }
  140. // Locomotion
  141. /*
  142. As the ant moves forward, legs in the stance phase are kept grounded via IK. If IK constraints are violated, the swinging legs are grounded
  143. and the grounded legs begin swinging.
  144. Two poses are loaded from the model file: midswing and touchdown.
  145. touchdown is the pose in which all legs are at the end of their swing phases and need to be grounded
  146. midswing is the pose in which all legs are at the highest point in their swing phases
  147. when a grounded leg enters the swing phases, its current pose is saved as the liftoff pose, then an animation is created using the liftoff pose, midswing pose, and touchdown pose.
  148. */
  149. }
  150. Vector3 Ant::forage(const Vector3& leftReceptor, const Vector3& rightReceptor)
  151. {
  152. float leftSignal = 0.0f;
  153. float rightSignal = 0.0f;
  154. // Detect pheromones with left receptor
  155. std::list<Pheromone*> leftPheromones;
  156. colony->getPheromoneOctree()->query(AABB(leftReceptor, leftReceptor), &leftPheromones);
  157. for (Pheromone* pheromone: leftPheromones)
  158. {
  159. Vector3 difference = pheromone->getPosition() - rightReceptor;
  160. float distanceSquared = glm::dot(difference, difference);
  161. if (distanceSquared <= pheromone->getRadiusSquared())
  162. {
  163. // Calculate attenuated pheromone strength using inverse-square law
  164. float strength = pheromone->getStrength() / ((distanceSquared == 0.0f) ? 1.0f : distanceSquared);
  165. leftSignal += strength;
  166. }
  167. }
  168. // Detect pheromones with right receptor
  169. std::list<Pheromone*> rightPheromones;
  170. colony->getPheromoneOctree()->query(AABB(rightReceptor, rightReceptor), &rightPheromones);
  171. for (Pheromone* pheromone: rightPheromones)
  172. {
  173. Vector3 difference = pheromone->getPosition() - rightReceptor;
  174. float distanceSquared = glm::dot(difference, difference);
  175. if (distanceSquared <= pheromone->getRadiusSquared())
  176. {
  177. // Calculate attenuated pheromone strength using inverse-square law
  178. float strength = pheromone->getStrength() / ((distanceSquared == 0.0f) ? 1.0f : distanceSquared);
  179. rightSignal += strength;
  180. }
  181. }
  182. // Add noise
  183. const float maxNoise = 0.1f;
  184. leftSignal += frand(0.0f, maxNoise);
  185. rightSignal += frand(0.0f, maxNoise);
  186. if (leftSignal + rightSignal > 0.0f)
  187. {
  188. const float maxPheromoneTurningAngle = 0.1f;
  189. // Use Weber's law (Perna et al.) to calculate turning angle based on pheromone signals
  190. float turningAngle = maxPheromoneTurningAngle * ((leftSignal - rightSignal) / (leftSignal + rightSignal));
  191. }
  192. return Vector3(0.0f);
  193. }
  194. void Ant::setState(Ant::State state)
  195. {
  196. this->state = state;
  197. }