/* * Copyright (C) 2017 Christopher J. Howard * * This file is part of Antkeeper Source Code. * * Antkeeper Source Code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper Source Code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper Source Code. If not, see . */ #include "ant.hpp" Ant::Ant(Colony* colony): colony(colony), state(Ant::State::IDLE), transform(Transform::getIdentity()), skeletonPose(nullptr) { modelInstance.setModel(colony->getAntModel()); } void Ant::move(const Vector3& velocity) { std::vector traversal; Navmesh::traverse(getNavmeshTriangle(), getBarycentricPosition(), velocity, &traversal); if (!traversal.empty()) { const Navmesh::Step& step = traversal.back(); if (step.start != step.end) { if (step.triangle != getNavmeshTriangle()) { Quaternion alignment = glm::rotation(getNavmeshTriangle()->normal, step.triangle->normal); Vector3 newForward = glm::normalize(project_on_plane(alignment * getForward(), Vector3(0.0f), step.triangle->normal)); setOrientation(newForward, step.triangle->normal); } } setPosition(step.triangle, step.end); } } void Ant::turn(float angle) { // Rotate forward vector Vector3 newForward = glm::normalize(glm::angleAxis(angle, getUp()) * getForward()); setOrientation(newForward, getUp()); } void Ant::update(float dt) { if (state == Ant::State::WANDER) { setWanderCircleDistance(3.0f); setWanderCircleRadius(0.25f); setWanderRate(glm::radians(90.0f)); // Calculate wander force Vector3 wanderForce = wander(dt); // Setup containment probes float probeLateralOffset = 0.35f; Vector3 forwardProbe = getForward() * 0.5f; Vector3 leftProbe = getForward() * 0.1f - getRight() * probeLateralOffset; Vector3 rightProbe = getForward() * 0.1f + getRight() * probeLateralOffset; // Calculate containment force Vector3 containmentForce = containment(forwardProbe) + containment(leftProbe) + containment(rightProbe); // Calculate velocity Vector3 velocity(0.0f); velocity += wanderForce; velocity += containmentForce; velocity = limit(velocity, 0.025f); setOrientation(glm::normalize(velocity), getUp()); // Move ant move(velocity); } // Update transform transform.translation = getPosition(); transform.rotation = getRotation(); // Update model instance modelInstance.setTransform(transform); } void Ant::setState(Ant::State state) { this->state = state; } Colony::Colony(): antModel(nullptr) {} Ant* Colony::spawn(Navmesh* navmesh, Navmesh::Triangle* triangle, const Vector3& position) { // Allocate ant Ant* ant = new Ant(this); // Position it on the navmesh ant->setPosition(triangle, position); // Add ant to the colony ants.push_back(ant); return ant; } void Colony::update(float dt) { for (Ant* ant: ants) { ant->update(dt); } } void Colony::setAntModel(Model* model) { this->antModel = model; }