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

222 lines
5.8 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 "agent.hpp"
  20. Agent::Agent():
  21. navmeshTriangle(nullptr),
  22. barycentricPosition(0.0f),
  23. position(0.0f),
  24. forward(0, 0, -1),
  25. up(0, 1, 0),
  26. right(1, 0, 0),
  27. rotation(1, 0, 0, 0),
  28. wanderDirection(0, 0, -1),
  29. velocity(0.0f)
  30. {}
  31. void Agent::applyForce(const Vector3& force)
  32. {
  33. acceleration += force;
  34. }
  35. void Agent::updateVelocity()
  36. {
  37. // Limit acceleration
  38. acceleration = limit(acceleration / mass, maxAcceleration);
  39. // Add acceleration to velocity and limit
  40. velocity = limit(velocity + acceleration, maxSpeed);
  41. // Reset acceleration to zero
  42. acceleration = Vector3(0.0f);
  43. }
  44. Vector3 Agent::wander(float dt)
  45. {
  46. // Calculate center of wander circle
  47. Vector3 wanderCircleCenter = position + forward * wanderCircleDistance;
  48. // Calculate wander force
  49. Vector3 target = wanderCircleCenter + wanderDirection * wanderCircleRadius;
  50. // Rotate wander direction by a random displacement angle
  51. float displacement = frand(-wanderRate * 0.5f, wanderRate * 0.5f);
  52. wanderDirection = glm::normalize(glm::angleAxis(displacement, up) * wanderDirection);
  53. return seek(target);
  54. }
  55. Vector3 Agent::seek(const Vector3& target) const
  56. {
  57. Vector3 desiredVelocity = glm::normalize(target - position) * maxSpeed;
  58. return desiredVelocity - velocity;
  59. }
  60. Vector3 Agent::flee(const Vector3& target) const
  61. {
  62. Vector3 desiredVelocity = glm::normalize(position - target) * maxSpeed;
  63. return desiredVelocity - velocity;
  64. }
  65. Vector3 Agent::containment(const Vector3& probe) const
  66. {
  67. std::vector<Navmesh::Step> traversal;
  68. Navmesh::traverse(navmeshTriangle, barycentricPosition, probe, &traversal);
  69. if (traversal.empty())
  70. {
  71. return Vector3(0.0f);
  72. }
  73. const Navmesh::Step& step = traversal.back();
  74. // If not on edge or on connected edge
  75. if (step.edge == nullptr || step.edge->symmetric != nullptr)
  76. {
  77. return Vector3(0.0f);
  78. }
  79. /*
  80. // Calculate difference between probe position and position on edge
  81. Vector3 end = cartesian(step.end,
  82. step.triangle->edge->vertex->position,
  83. step.triangle->edge->next->vertex->position,
  84. step.triangle->edge->previous->vertex->position);
  85. Vector3 difference = probe - end;
  86. float depth = 0.0f;
  87. if (nonzero(difference))
  88. {
  89. depth = glm::length(difference);
  90. }
  91. */
  92. // Calculate edge normal
  93. const Vector3& a = step.edge->vertex->position;
  94. const Vector3& b = step.edge->next->vertex->position;
  95. Vector3 ab = glm::normalize(b - a);
  96. Vector3 edgeNormal = glm::cross(up, ab);
  97. // Calculate reflection vector of forward vector and edge normal
  98. //Vector3 reflection = glm::reflect(forward, edgeNormal);
  99. /*
  100. Vector3 target = cartesian(step.end,
  101. step.triangle->edge->vertex->position,
  102. step.triangle->edge->next->vertex->position,
  103. step.triangle->edge->previous->vertex->position) + reflection * 0.1f;
  104. */
  105. //std::cout << "reflection: " << reflection.x << ", " << reflection.y << ", " << reflection.z << std::endl;
  106. return edgeNormal;
  107. }
  108. Vector3 Agent::separation(const std::list<Agent*>& neighbors) const
  109. {
  110. Vector3 force(0.0f);
  111. for (Agent* neighbor: neighbors)
  112. {
  113. Vector3 difference = position - neighbor->position;
  114. float distanceSquared = glm::dot(difference, difference);
  115. if (distanceSquared > 0.0f && distanceSquared < separationRadiusSquared)
  116. {
  117. force += difference * (1.0f / distanceSquared);
  118. }
  119. }
  120. if (nonzero(force))
  121. {
  122. force = glm::normalize(force);
  123. }
  124. return force;
  125. }
  126. void Agent::setPosition(Navmesh::Triangle* triangle, const Vector3& position)
  127. {
  128. // Update navmesh triangle and position
  129. navmeshTriangle = triangle;
  130. barycentricPosition = position;
  131. // Convert navmesh-space barycentric position to world-space cartesian position
  132. const Vector3& a = triangle->edge->vertex->position;
  133. const Vector3& b = triangle->edge->next->vertex->position;
  134. const Vector3& c = triangle->edge->previous->vertex->position;
  135. this->position = cartesian(position, a, b, c);
  136. }
  137. void Agent::setOrientation(const Vector3& newForward, const Vector3& newUp)
  138. {
  139. // Calculate alignment quaternion
  140. Quaternion alignment = glm::rotation(up, newUp);
  141. // Rebuild vector basis
  142. forward = newForward;
  143. right = glm::normalize(glm::cross(newUp, forward));
  144. up = glm::cross(forward, right);
  145. // Calculate rotation quaternion from vector basis
  146. rotation = glm::normalize(glm::quat_cast(Matrix3(right, up, forward)));
  147. // Align wander direction
  148. wanderDirection = glm::normalize(project_on_plane(alignment * wanderDirection, Vector3(0.0f), up));
  149. }
  150. void Agent::setMaxSpeed(float speed)
  151. {
  152. maxSpeed = speed;
  153. }
  154. void Agent::setVelocity(const Vector3& velocity)
  155. {
  156. this->velocity = velocity;
  157. }
  158. void Agent::setWanderCircleDistance(float distance)
  159. {
  160. wanderCircleDistance = distance;
  161. }
  162. void Agent::setWanderCircleRadius(float radius)
  163. {
  164. wanderCircleRadius = radius;
  165. }
  166. void Agent::setWanderRate(float angle)
  167. {
  168. wanderRate = angle;
  169. }
  170. void Agent::setSeparationRadius(float radius)
  171. {
  172. separationRadius = radius;
  173. separationRadiusSquared = separationRadius * separationRadius;
  174. }
  175. /** EXAMPLE USAGE
  176. Vector3 wanderForce = wander(dt) * wanderWeight;
  177. Vector3 fleeForce = flee(mouse) * fleeWeight;
  178. Vector3 steerForce = wanderForce + fleeForce;
  179. steer(steerForce);
  180. **/