2023-05-23 23:38:37 +02:00
|
|
|
#include "tracking_view.h"
|
2023-05-14 22:23:25 +02:00
|
|
|
#include "../../utilities/vector_utils.hpp"
|
2023-06-13 21:59:50 +02:00
|
|
|
#include "../player/player_collection.hpp"
|
2023-05-09 20:50:50 +02:00
|
|
|
|
2023-05-25 22:40:26 +02:00
|
|
|
TrackingView::TrackingView(TrackingViewOptions options) : options(options),
|
2023-07-09 21:24:50 +02:00
|
|
|
view(new sf::View(options.initialCenter,
|
|
|
|
options.minViewSize)),
|
2023-06-13 19:04:38 +02:00
|
|
|
trackables({})
|
2023-06-13 21:59:50 +02:00
|
|
|
{
|
2023-06-12 21:02:04 +02:00
|
|
|
marker = new CircleObject(DB_CIRCLE_RADIUS, sf::Color::Yellow);
|
2023-05-24 01:15:05 +02:00
|
|
|
}
|
|
|
|
|
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;
|
2023-05-14 22:23:25 +02:00
|
|
|
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
|
|
|
{
|
2023-05-24 01:15:05 +02:00
|
|
|
processTrackableStates();
|
|
|
|
|
|
|
|
if (!trackables.empty())
|
2023-05-14 22:23:25 +02:00
|
|
|
{
|
2023-05-25 22:40:26 +02:00
|
|
|
followTrackables();
|
2023-05-14 22:23:25 +02:00
|
|
|
}
|
2023-07-09 21:24:50 +02:00
|
|
|
adjustSizeToTrackables();
|
2023-05-09 20:50:50 +02:00
|
|
|
}
|
2023-05-10 11:30:11 +02:00
|
|
|
|
2023-05-25 22:40:26 +02:00
|
|
|
void TrackingView::setSize(sf::Vector2f newSize)
|
2023-05-10 11:30:11 +02:00
|
|
|
{
|
2023-05-14 22:23:25 +02:00
|
|
|
// Is different?
|
2023-05-25 22:40:26 +02:00
|
|
|
auto size = getSize();
|
|
|
|
if (size.x == newSize.x && size.y == newSize.y)
|
2023-05-14 22:23:25 +02:00
|
|
|
{
|
|
|
|
// Nothing to do
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-27 18:37:08 +02:00
|
|
|
bool didAspectRationChange = false;
|
|
|
|
auto prevRatio = size.x / size.y;
|
|
|
|
auto newRatio = newSize.x / newSize.y;
|
|
|
|
if (abs(prevRatio - newRatio) > 0.001)
|
|
|
|
{
|
|
|
|
didAspectRationChange = true;
|
|
|
|
}
|
|
|
|
|
2023-06-13 21:59:50 +02:00
|
|
|
if (options.softResizeSpeed != 0 && !didAspectRationChange)
|
|
|
|
{
|
2023-05-25 22:40:26 +02:00
|
|
|
// Smooth out transition to new size
|
|
|
|
newSize = size + (newSize - size) * options.softResizeSpeed * FRAME_TIME.asSeconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
view->setSize(newSize);
|
2023-05-10 11:30:11 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 23:38:37 +02:00
|
|
|
sf::Vector2f TrackingView::getSize() const
|
2023-05-10 11:30:11 +02:00
|
|
|
{
|
2023-05-14 22:23:25 +02:00
|
|
|
return view->getSize();
|
|
|
|
}
|
|
|
|
|
2023-06-22 23:14:16 +02:00
|
|
|
sf::Vector2f TrackingView::getSizeInWindow() const
|
2023-05-27 18:37:08 +02:00
|
|
|
{
|
|
|
|
auto size = Game::getInstance()->window->getSize();
|
2023-06-22 23:14:16 +02:00
|
|
|
auto viewPort = view->getViewport();
|
|
|
|
return {static_cast<float>(size.x * viewPort.width), static_cast<float>(size.y * viewPort.height)};
|
2023-05-27 18:37:08 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 23:38:37 +02:00
|
|
|
sf::Vector2f TrackingView::getCenter() const
|
2023-05-14 22:23:25 +02:00
|
|
|
{
|
|
|
|
return view->getCenter();
|
|
|
|
}
|
|
|
|
|
2023-05-25 22:40:26 +02:00
|
|
|
void TrackingView::followTrackables()
|
2023-05-14 22:23:25 +02:00
|
|
|
{
|
2023-05-24 17:05:47 +02:00
|
|
|
auto trackingPoint = getTrackingArea().getCenter();
|
2023-06-17 21:25:33 +02:00
|
|
|
if (DB_TRACKING_VIEW_CENTER)
|
2023-05-24 17:05:47 +02:00
|
|
|
{
|
2023-06-17 19:48:51 +02:00
|
|
|
marker->coordinates->setIsometric(IsometricCoordinates(trackingPoint));
|
2023-05-24 15:21:53 +02:00
|
|
|
}
|
2023-05-14 22:23:25 +02:00
|
|
|
|
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;
|
2023-05-25 22:40:26 +02:00
|
|
|
auto distanceToTarget = length(vectorToTarget);
|
2023-05-24 15:21:53 +02:00
|
|
|
|
2023-07-05 15:22:20 +02:00
|
|
|
if (distanceToTarget <= getFreeMovementRadius())
|
2023-05-24 15:21:53 +02:00
|
|
|
{
|
|
|
|
// Nothing to do
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-24 15:36:49 +02:00
|
|
|
|
2023-05-25 22:40:26 +02:00
|
|
|
|
|
|
|
// Targets are outside of free move radius, follow them
|
|
|
|
auto deltaToDesiredView = normalize(vectorToTarget);
|
|
|
|
|
|
|
|
// Reduce delta to edge of free-move area to make it less jaring
|
2023-07-05 15:22:20 +02:00
|
|
|
deltaToDesiredView *= distanceToTarget - getFreeMovementRadius();
|
2023-05-10 11:30:11 +02:00
|
|
|
|
2023-05-24 15:36:49 +02:00
|
|
|
moveCenter(deltaToDesiredView);
|
2023-05-14 22:23:25 +02:00
|
|
|
}
|
|
|
|
|
2023-05-24 01:15:05 +02:00
|
|
|
void TrackingView::moveCenter(sf::Vector2<float> delta)
|
2023-05-14 22:23:25 +02:00
|
|
|
{
|
2023-05-25 22:40:26 +02:00
|
|
|
if (options.softFollowSpeed != 0)
|
|
|
|
{
|
|
|
|
// Soft
|
|
|
|
delta *= options.softFollowSpeed * FRAME_TIME.asSeconds();
|
|
|
|
}
|
|
|
|
|
2023-05-24 01:15:05 +02:00
|
|
|
view->move(delta);
|
2023-05-14 22:23:25 +02:00
|
|
|
}
|
|
|
|
|
2023-06-10 15:24:03 +02:00
|
|
|
void TrackingView::draw(sf::RenderWindow *window)
|
2023-05-14 22:23:25 +02:00
|
|
|
{
|
2023-06-17 21:25:33 +02:00
|
|
|
if (!DB_TRACKING_VIEW_CENTER)
|
2023-05-24 17:05:47 +02:00
|
|
|
{
|
2023-05-24 15:21:53 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-24 01:15:05 +02:00
|
|
|
marker->draw(window);
|
2023-05-14 22:23:25 +02:00
|
|
|
}
|
|
|
|
|
2023-06-13 21:59:50 +02:00
|
|
|
void TrackingView::addTrackable(const std::shared_ptr<ITrackable> &trackable)
|
2023-05-14 22:23:25 +02:00
|
|
|
{
|
2023-05-24 01:15:05 +02:00
|
|
|
trackables.push_back(trackable);
|
2023-06-22 23:14:16 +02:00
|
|
|
|
|
|
|
// Set initial values if first trackable
|
|
|
|
if (trackables.size() == 1)
|
|
|
|
{
|
|
|
|
view->setCenter(trackable->getTrackablePosition());
|
|
|
|
}
|
2023-05-14 22:23:25 +02:00
|
|
|
}
|
|
|
|
|
2023-05-24 17:05:47 +02:00
|
|
|
void TrackingView::processTrackableStates()
|
|
|
|
{
|
|
|
|
// Remove trackables that have ended tracking
|
2023-06-13 19:04:38 +02:00
|
|
|
std::remove_if(trackables.begin(), trackables.end(), [](std::shared_ptr<ITrackable> trackable)
|
2023-05-24 17:05:47 +02:00
|
|
|
{
|
|
|
|
return trackable->getTrackableState() == TrackableState::END_TRACKING;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
TrackingArea TrackingView::getTrackingArea() const
|
2023-05-14 22:23:25 +02:00
|
|
|
{
|
2023-07-09 21:24:50 +02:00
|
|
|
if (trackables.empty())
|
|
|
|
{
|
|
|
|
return TrackingArea();
|
|
|
|
}
|
|
|
|
|
2023-05-25 22:40:26 +02:00
|
|
|
auto initialTrackable = trackables[0];
|
|
|
|
TrackingArea area = {
|
|
|
|
initialTrackable->getTrackablePosition() - initialTrackable->getTrackableSize() / 2.f,
|
|
|
|
initialTrackable->getTrackablePosition() + initialTrackable->getTrackableSize() / 2.f
|
|
|
|
};
|
2023-05-14 22:23:25 +02:00
|
|
|
|
2023-05-25 22:40:26 +02:00
|
|
|
// Find min and max point coordinates for x- and y-axis over all trackables
|
2023-05-24 17:05:47 +02:00
|
|
|
for (auto trackable: trackables)
|
2023-05-24 01:15:05 +02:00
|
|
|
{
|
2023-05-24 14:29:08 +02:00
|
|
|
auto trackableCoordinates = trackable->getTrackablePosition();
|
|
|
|
auto trackableSize = trackable->getTrackableSize();
|
|
|
|
|
2023-05-25 22:40:26 +02:00
|
|
|
auto topLeft = trackableCoordinates - trackableSize / 2.f;
|
|
|
|
auto bottomRight = trackableCoordinates + trackableSize / 2.f;
|
2023-05-24 14:29:08 +02:00
|
|
|
|
2023-05-25 22:40:26 +02:00
|
|
|
if (topLeft.x < area.topLeft.x)
|
2023-05-24 01:15:05 +02:00
|
|
|
{
|
2023-05-25 22:40:26 +02:00
|
|
|
area.topLeft.x = topLeft.x;
|
2023-05-24 14:29:08 +02:00
|
|
|
}
|
2023-05-25 22:40:26 +02:00
|
|
|
if (bottomRight.x > area.bottomRight.x)
|
2023-05-24 14:29:08 +02:00
|
|
|
{
|
2023-05-25 22:40:26 +02:00
|
|
|
area.bottomRight.x = bottomRight.x;
|
2023-05-24 14:29:08 +02:00
|
|
|
}
|
2023-05-25 22:40:26 +02:00
|
|
|
if (topLeft.y < area.topLeft.y)
|
2023-05-24 14:29:08 +02:00
|
|
|
{
|
2023-05-25 22:40:26 +02:00
|
|
|
area.topLeft.y = topLeft.y;
|
2023-05-24 14:29:08 +02:00
|
|
|
}
|
2023-05-25 22:40:26 +02:00
|
|
|
if (bottomRight.y > area.bottomRight.y)
|
2023-05-24 14:29:08 +02:00
|
|
|
{
|
2023-05-25 22:40:26 +02:00
|
|
|
area.bottomRight.y = bottomRight.y;
|
2023-05-24 01:15:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-24 17:05:47 +02:00
|
|
|
return area;
|
2023-05-24 15:21:53 +02:00
|
|
|
}
|
2023-05-25 22:40:26 +02:00
|
|
|
|
|
|
|
void TrackingView::adjustSizeToTrackables()
|
|
|
|
{
|
|
|
|
// Calculate new view size
|
|
|
|
auto newViewSize = getTrackingArea().getSize();
|
|
|
|
|
|
|
|
newViewSize = applyPadding(newViewSize);
|
|
|
|
newViewSize = restrainToBounds(newViewSize);
|
|
|
|
|
|
|
|
// Extend view to match aspect ratio
|
2023-06-22 23:14:16 +02:00
|
|
|
auto windowSize = getSizeInWindow();
|
2023-05-27 18:37:08 +02:00
|
|
|
auto aspectRatio = windowSize.x / windowSize.y;
|
2023-05-25 22:40:26 +02:00
|
|
|
if (newViewSize.x / newViewSize.y > aspectRatio)
|
|
|
|
{
|
|
|
|
// Extend x-axis
|
|
|
|
newViewSize.y = newViewSize.x / aspectRatio;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
// Extend y-axis
|
|
|
|
newViewSize.x = newViewSize.y * aspectRatio;
|
|
|
|
}
|
|
|
|
|
|
|
|
setSize(newViewSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
sf::Vector2f TrackingView::restrainToBounds(sf::Vector2f viewSize) const
|
|
|
|
{
|
|
|
|
// x-axis
|
|
|
|
if (options.minViewSize.x > 0 && viewSize.x < options.minViewSize.x)
|
|
|
|
{
|
|
|
|
viewSize.x = options.minViewSize.x;
|
|
|
|
} else if (options.maxViewSize.x > 0 && viewSize.x > options.maxViewSize.x)
|
|
|
|
{
|
|
|
|
viewSize.x = options.maxViewSize.x;
|
|
|
|
}
|
|
|
|
// y-axis
|
|
|
|
if (options.minViewSize.y > 0 && viewSize.y < options.minViewSize.y)
|
|
|
|
{
|
|
|
|
viewSize.y = options.minViewSize.y;
|
|
|
|
} else if (options.maxViewSize.y > 0 && viewSize.y > options.maxViewSize.y)
|
|
|
|
{
|
|
|
|
viewSize.y = options.maxViewSize.y;
|
|
|
|
}
|
|
|
|
return viewSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
sf::Vector2f TrackingView::applyPadding(sf::Vector2f viewSize) const
|
|
|
|
{
|
|
|
|
auto padding = options.viewSizePadding;
|
2023-07-05 15:22:20 +02:00
|
|
|
if (!options.isAbsoluteViewSizePadding)
|
2023-05-25 22:40:26 +02:00
|
|
|
{
|
|
|
|
padding.x *= viewSize.x;
|
|
|
|
padding.y *= viewSize.y;
|
|
|
|
}
|
|
|
|
return viewSize + padding;
|
|
|
|
}
|
|
|
|
|
2023-07-05 15:22:20 +02:00
|
|
|
float TrackingView::getFreeMovementRadius() const
|
2023-05-25 22:40:26 +02:00
|
|
|
{
|
2023-07-05 15:22:20 +02:00
|
|
|
if (options.freeMoveThreshold <= 0)
|
2023-05-25 22:40:26 +02:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-05 15:22:20 +02:00
|
|
|
if (options.isAbsoluteFreeMoveThreshold)
|
2023-05-25 22:40:26 +02:00
|
|
|
{
|
2023-07-05 15:22:20 +02:00
|
|
|
return options.freeMoveThreshold;
|
2023-05-25 22:40:26 +02:00
|
|
|
}
|
|
|
|
|
2023-06-22 23:14:16 +02:00
|
|
|
auto windowSize = getSizeInWindow();
|
2023-05-27 18:37:08 +02:00
|
|
|
float smallestSide = std::min(windowSize.x, windowSize.y);
|
2023-05-25 22:40:26 +02:00
|
|
|
|
|
|
|
// Only half of the side, since we are calculating radius
|
2023-07-05 15:22:20 +02:00
|
|
|
return smallestSide / 2.f * options.freeMoveThreshold;
|
2023-05-25 22:40:26 +02:00
|
|
|
}
|
2023-06-13 21:59:50 +02:00
|
|
|
|
|
|
|
void TrackingView::removeTrackable(const std::shared_ptr<ITrackable> &trackable)
|
|
|
|
{
|
|
|
|
trackables.erase(
|
|
|
|
std::remove_if(trackables.begin(), trackables.end(), [&trackable](const std::shared_ptr<ITrackable> &t)
|
|
|
|
{
|
|
|
|
return t == trackable;
|
|
|
|
}), trackables.end());
|
|
|
|
}
|
2023-06-21 20:42:42 +02:00
|
|
|
|
|
|
|
void TrackingView::setViewport(sf::Vector2f center, sf::Vector2f size)
|
|
|
|
{
|
|
|
|
// TODO: Resize content for viewport
|
|
|
|
view->setViewport(sf::FloatRect(center.x, center.y, size.x, size.y));
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrackingView::setViewForWindow()
|
|
|
|
{
|
|
|
|
Game::getInstance()->window->setView(*this->view);
|
|
|
|
}
|