holesome/src/game/camera/tracking_view.cpp

180 lines
4.4 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
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-23 23:38:37 +02:00
void TrackingView::lateUpdate(Game *game)
2023-05-09 20:50:50 +02:00
{
// Initialize if necessary
2023-05-10 11:03:14 +02:00
if (view == nullptr)
{
initializeView(game);
}
// Update size
setSize(game->window->getSize());
2023-05-09 20:50:50 +02:00
if (target != nullptr)
{
followTarget();
}
// Update window if necessary
if (hasViewChanged)
2023-05-09 20:50:50 +02:00
{
game->window->setView(*this->view);
hasViewChanged = false;
2023-05-09 20:50:50 +02:00
}
2023-05-10 11:03:14 +02:00
}
2023-05-23 23:38:37 +02:00
void TrackingView::initializeView(Game *game)
2023-05-10 11:03:14 +02:00
{
auto size = game->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
TrackingView::TrackingView(ITrackable *trackable, sf::Vector2f freeMoveArea, sf::Vector2f dynamicFollowArea)
: target(trackable), freeMoveArea(freeMoveArea), dynamicFollowArea(dynamicFollowArea), view(nullptr),
hasViewChanged(false)
{
marker = new CircleObject(2, sf::Color::Yellow);
}
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()
{
// TODO
auto closestPositionInDynamic = getClosestPositionInArea(dynamicFollowArea);
marker->coordinates.set(IsometricCoordinates(closestPositionInDynamic));
return;
if (isTargetInArea(freeMoveArea))
{
// Nothing to do
return;
}
// performHardFollow();
// if (isTargetInArea(dynamicFollowArea))
// {
// // Slowly push target back into free area
// performDynamicFollow();
// } else
// {
// // Hard follow
// performHardFollow();
// }
}
2023-05-23 23:38:37 +02:00
bool TrackingView::isTargetInArea(sf::Vector2f areaSize)
{
// Assuming target is not null
// Target specifications
auto targetSize = target->getTrackableSize();
auto targetTopLeft = target->getTrackablePosition() - targetSize / 2.f;
auto targetBottomRight = targetTopLeft + targetSize;
// Free Movement Area
auto areaTopLeft = getCenter() - areaSize / 2.f;
auto areaBottomRight = areaTopLeft + areaSize;
// Check collision of all edges
if (targetTopLeft.x < areaTopLeft.x ||
targetTopLeft.y < areaTopLeft.y ||
targetBottomRight.x > areaBottomRight.x ||
targetBottomRight.y > areaBottomRight.y)
{
return false;
}
return true;
}
2023-05-23 23:38:37 +02:00
sf::Vector2f TrackingView::getClosestPositionInArea(sf::Vector2f areaSize) const
{
// Reduce area to only consider target position, not size
auto positionOnlyAreaSize = areaSize - target->getTrackableSize();
// Calculate max-length of rubber to land inside of area
sf::Vector2f rubber = getRubber();
// Problem is symmetrical for all corners, so can simplify to use only absolute values and part of the area
auto absRubber = abs(rubber);
auto cornerArea = positionOnlyAreaSize / 2.f;
// Calculate factor for each dimension, that would scale it to the border
float xScale = INFINITY;
if (absRubber.x > 0)
{
xScale = cornerArea.x / absRubber.x;
}
float yScale = INFINITY;
if (absRubber.y > 0)
{
yScale = cornerArea.y / absRubber.y;
}
float length = std::min(xScale, yScale);
return rubber * length;
}
2023-05-23 23:38:37 +02:00
sf::Vector2f TrackingView::getRubber() const
{
return normalize(target->getTrackablePosition() - getCenter());
}
2023-05-23 23:38:37 +02:00
void TrackingView::performHardFollow()
{
auto closestPositionInDynamic = getClosestPositionInArea(dynamicFollowArea);
auto delta = getCenter() - closestPositionInDynamic;
moveCenter(-delta);
}
2023-05-23 23:38:37 +02:00
void TrackingView::moveCenter(sf::Vector2<float> delta)
{
view->move(delta);
hasViewChanged = true;
}
2023-05-23 23:38:37 +02:00
void TrackingView::performDynamicFollow()
{
auto closestPositionInDynamic = getClosestPositionInArea(freeMoveArea);
auto delta = getCenter() - closestPositionInDynamic;
moveCenter(delta * VIEW_RUBBER_FOLLOW_SPEED * FRAME_TIME.asSeconds());
}
2023-05-23 23:38:37 +02:00
void TrackingView::draw(sf::RenderWindow *window) const
{
marker->draw(window);
}