holesome/src/game/camera/tracking_view.cpp

183 lines
4.7 KiB
C++
Raw Normal View History

2023-05-23 23:38:37 +02:00
#include "tracking_view.h"
#include "../../utilities/vector_utils.hpp"
2023-05-09 20:50:50 +02:00
TrackingView::TrackingView(float freeMoveRadius, float dynamicFollowRadius) : freeMoveRadius(freeMoveRadius),
dynamicFollowRadius(dynamicFollowRadius),
view(nullptr),
hasViewChanged(false)
{
trackables = std::vector<ITrackable *>();
marker = new CircleObject(2, sf::Color::Yellow);
2023-05-24 14:00:51 +02:00
Game::getInstance()->registerView(this);
}
2023-05-23 23:38:37 +02:00
TrackingView::~TrackingView()
2023-05-09 20:50:50 +02:00
{
2023-05-10 11:03:14 +02:00
delete view;
delete marker;
2023-05-09 20:50:50 +02:00
}
2023-05-24 14:00:51 +02:00
void TrackingView::lateUpdate()
2023-05-09 20:50:50 +02:00
{
// Initialize if necessary
2023-05-10 11:03:14 +02:00
if (view == nullptr)
{
2023-05-24 14:00:51 +02:00
initializeView();
2023-05-10 11:03:14 +02:00
}
processTrackableStates();
2023-05-10 11:03:14 +02:00
// Update size
2023-05-24 15:21:53 +02:00
// TODO: Update size based on length of tracked objects
2023-05-24 14:00:51 +02:00
setSize(Game::getInstance()->window->getSize());
2023-05-09 20:50:50 +02:00
if (!trackables.empty())
{
followTarget();
}
// Update window if necessary
if (hasViewChanged)
2023-05-09 20:50:50 +02:00
{
2023-05-24 14:00:51 +02:00
Game::getInstance()->window->setView(*this->view);
hasViewChanged = false;
2023-05-09 20:50:50 +02:00
}
2023-05-10 11:03:14 +02:00
}
2023-05-24 14:00:51 +02:00
void TrackingView::initializeView()
2023-05-10 11:03:14 +02:00
{
2023-05-24 14:00:51 +02:00
auto size = Game::getInstance()->window->getView().getSize();
view = new sf::View({0, 0}, size);
2023-05-09 20:50:50 +02:00
}
2023-05-23 23:38:37 +02:00
void TrackingView::setSize(sf::Vector2u windowSize)
{
// TODO: Maybe listen to resize events instead of checking every frame?
// Is different?
if (view->getSize().x == windowSize.x && view->getSize().y == windowSize.y)
{
// Nothing to do
return;
}
sf::Vector2f viewSize = sf::Vector2f(windowSize.x, windowSize.y);
view->setSize(viewSize);
hasViewChanged = true;
}
2023-05-23 23:38:37 +02:00
sf::Vector2f TrackingView::getSize() const
{
return view->getSize();
}
2023-05-23 23:38:37 +02:00
sf::Vector2f TrackingView::getCenter() const
{
return view->getCenter();
}
2023-05-23 23:38:37 +02:00
void TrackingView::followTarget()
{
auto trackingPoint = getCollectiveTrackingPoint();
2023-05-24 15:21:53 +02:00
if (DEVELOPER_MODE) {
marker->coordinates.set(IsometricCoordinates(trackingPoint));
}
2023-05-24 15:21:53 +02:00
// Calculate distance to target to check how to handle it
auto currentCenter = view->getCenter();
auto vectorToTarget = trackingPoint - currentCenter;
float distanceToTarget = length(vectorToTarget);
if (distanceToTarget <= freeMoveRadius)
{
// Nothing to do
return;
}
// Move view to place tracking-point at edge of area
auto deltaToDesiredView = normalize(vectorToTarget) * (distanceToTarget - freeMoveRadius);
moveCenter(deltaToDesiredView);
// performHardFollow();
// if (isTargetInArea(dynamicFollowArea))
// {
// // Slowly push target back into free area
// performDynamicFollow();
// } else
// {
// // Hard follow
// performHardFollow();
// }
}
void TrackingView::moveCenter(sf::Vector2<float> delta)
{
view->move(delta);
hasViewChanged = true;
}
void TrackingView::draw(sf::RenderWindow *window) const
{
2023-05-24 15:21:53 +02:00
if (!DEVELOPER_MODE) {
return;
}
marker->draw(window);
}
void TrackingView::addTrackable(ITrackable *trackable)
{
trackables.push_back(trackable);
}
sf::Vector2f TrackingView::getCollectiveTrackingPoint() const
{
sf::Vector2f minPoint = trackables[0]->getTrackablePosition();
sf::Vector2f maxPoint = minPoint;
// Find min and max point coordinates for x and y axis over all trackables
for (auto trackable : trackables)
{
auto trackableCoordinates = trackable->getTrackablePosition();
auto trackableSize = trackable->getTrackableSize();
auto minPointX = trackableCoordinates.x - trackableSize.x / 2.f;
auto maxPointX = trackableCoordinates.x + trackableSize.x / 2.f;
auto minPointY = trackableCoordinates.y - trackableSize.y / 2.f;
auto maxPointY = trackableCoordinates.y + trackableSize.y / 2.f;
if (minPointX < minPoint.x)
{
minPoint.x = minPointX;
}
if (maxPointX > maxPoint.x)
{
maxPoint.x = maxPointX;
}
if (minPointY < minPoint.y)
{
minPoint.y = minPointY;
}
if (maxPointY > maxPoint.y)
{
maxPoint.y = maxPointY;
}
}
return minPoint + (maxPoint - minPoint) / 2.f;
}
void TrackingView::processTrackableStates()
{
// Remove trackables that have ended tracking
std::remove_if(trackables.begin(), trackables.end(), [](ITrackable *trackable)
{
return trackable->getTrackableState() == TrackableState::END_TRACKING;
});
}
2023-05-24 15:21:53 +02:00
void TrackingView::setCenter(sf::Vector2<float> newCenter)
{
view->setCenter(newCenter);
hasViewChanged = true;
}