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

138 lines
3.4 KiB

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<Navmesh::Step> 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;
}