Refined, improved and fixed tracking view
This commit is contained in:
parent
bbc74a8cef
commit
8ca3547306
7 changed files with 194 additions and 61 deletions
|
@ -55,7 +55,7 @@ set(SOURCES
|
|||
src/utilities/magic_enum.hpp
|
||||
src/game/player/player_spawner.cpp
|
||||
src/game/player/player_spawner.hpp
|
||||
src/game/camera/tracking_area.h)
|
||||
src/game/camera/tracking_area.h src/game/camera/tracking_view_options.hpp)
|
||||
|
||||
set(PHYSICS_00_SOURCES
|
||||
src/prototypes/physics_00.cpp)
|
||||
|
|
|
@ -20,7 +20,13 @@
|
|||
#define ISOMETRIC_SKEW 0.3f
|
||||
#define WORLD_TO_ISO_SCALE 10.0f
|
||||
|
||||
#define VIEW_DYNAMIC_FOLLOW_SPEED 2.f
|
||||
// Tracking view defaults
|
||||
#define DEF_TV_FREE_MOVE_THRESHOLD 0.f
|
||||
#define DEF_TV_SOFT_FOLLOW_SPEED 2.5f
|
||||
#define DEF_TV_SOFT_RESIZE_SPEED 5.f
|
||||
#define DEF_TV_MIN_VIEW_SIZE sf::Vector2f(300, 300)
|
||||
#define DEF_TV_MAX_VIEW_SIZE sf::Vector2f(0, 0)
|
||||
#define DEF_TV_VIEW_SIZE_PADDING sf::Vector2f(0.5f, 0.5f)
|
||||
|
||||
// Inputs
|
||||
#define JOYSTICK_DEADZONE 0.1f
|
||||
|
|
|
@ -12,6 +12,11 @@ struct TrackingArea
|
|||
{
|
||||
return topLeft + (bottomRight - topLeft) / 2.f;
|
||||
}
|
||||
|
||||
sf::Vector2f getSize() const
|
||||
{
|
||||
return bottomRight - topLeft;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#include "tracking_view.h"
|
||||
#include "../../utilities/vector_utils.hpp"
|
||||
|
||||
TrackingView::TrackingView(float freeMoveRadius, float dynamicFollowRadius) : freeMoveRadius(freeMoveRadius),
|
||||
dynamicFollowRadius(dynamicFollowRadius),
|
||||
TrackingView::TrackingView(TrackingViewOptions options) : options(options),
|
||||
view(nullptr),
|
||||
hasViewChanged(false)
|
||||
{
|
||||
|
@ -27,13 +26,10 @@ void TrackingView::lateUpdate()
|
|||
|
||||
processTrackableStates();
|
||||
|
||||
// Update size
|
||||
// TODO: Update size based on length of tracked objects
|
||||
setSize(Game::getInstance()->window->getSize());
|
||||
|
||||
if (!trackables.empty())
|
||||
{
|
||||
followTarget();
|
||||
followTrackables();
|
||||
adjustSizeToTrackables();
|
||||
}
|
||||
|
||||
// Update window if necessary
|
||||
|
@ -51,18 +47,22 @@ void TrackingView::initializeView()
|
|||
hasViewChanged = true;
|
||||
}
|
||||
|
||||
void TrackingView::setSize(sf::Vector2u windowSize)
|
||||
void TrackingView::setSize(sf::Vector2f newSize)
|
||||
{
|
||||
// TODO: Maybe listen to resize events instead of checking every frame?
|
||||
// Is different?
|
||||
if (view->getSize().x == windowSize.x && view->getSize().y == windowSize.y)
|
||||
auto size = getSize();
|
||||
if (size.x == newSize.x && size.y == newSize.y)
|
||||
{
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
sf::Vector2f viewSize = sf::Vector2f(windowSize.x, windowSize.y);
|
||||
view->setSize(viewSize);
|
||||
if (options.softResizeSpeed != 0) {
|
||||
// Smooth out transition to new size
|
||||
newSize = size + (newSize - size) * options.softResizeSpeed * FRAME_TIME.asSeconds();
|
||||
}
|
||||
|
||||
view->setSize(newSize);
|
||||
hasViewChanged = true;
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ sf::Vector2f TrackingView::getCenter() const
|
|||
return view->getCenter();
|
||||
}
|
||||
|
||||
void TrackingView::followTarget()
|
||||
void TrackingView::followTrackables()
|
||||
{
|
||||
auto trackingPoint = getTrackingArea().getCenter();
|
||||
if (DEVELOPER_MODE)
|
||||
|
@ -87,32 +87,33 @@ void TrackingView::followTarget()
|
|||
// Calculate distance to target to check how to handle it
|
||||
auto currentCenter = view->getCenter();
|
||||
auto vectorToTarget = trackingPoint - currentCenter;
|
||||
float distanceToTarget = length(vectorToTarget);
|
||||
auto distanceToTarget = length(vectorToTarget);
|
||||
|
||||
if (distanceToTarget <= freeMoveRadius)
|
||||
if (distanceToTarget <= getRadius(options.freeMoveThreshold))
|
||||
{
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
// Move view to place tracking-point at edge of area
|
||||
auto deltaToDesiredView = normalize(vectorToTarget) * FRAME_TIME.asSeconds();
|
||||
|
||||
if (distanceToTarget <= dynamicFollowRadius)
|
||||
{
|
||||
// Reduce delta to make it less jaring
|
||||
deltaToDesiredView *= VIEW_DYNAMIC_FOLLOW_SPEED * (distanceToTarget - freeMoveRadius);
|
||||
} else
|
||||
{
|
||||
// Hard follow
|
||||
deltaToDesiredView *= dynamicFollowRadius;
|
||||
}
|
||||
|
||||
// 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
|
||||
deltaToDesiredView *= distanceToTarget - getRadius(options.freeMoveThreshold);
|
||||
|
||||
moveCenter(deltaToDesiredView);
|
||||
}
|
||||
|
||||
void TrackingView::moveCenter(sf::Vector2<float> delta)
|
||||
{
|
||||
if (options.softFollowSpeed != 0)
|
||||
{
|
||||
// Soft
|
||||
delta *= options.softFollowSpeed * FRAME_TIME.asSeconds();
|
||||
}
|
||||
|
||||
view->move(delta);
|
||||
hasViewChanged = true;
|
||||
}
|
||||
|
@ -141,45 +142,118 @@ void TrackingView::processTrackableStates()
|
|||
});
|
||||
}
|
||||
|
||||
void TrackingView::setCenter(sf::Vector2<float> newCenter)
|
||||
{
|
||||
view->setCenter(newCenter);
|
||||
hasViewChanged = true;
|
||||
}
|
||||
|
||||
TrackingArea TrackingView::getTrackingArea() const
|
||||
{
|
||||
sf::Vector2f initialPoints = trackables[0]->getTrackablePosition();
|
||||
TrackingArea area = {initialPoints, initialPoints};
|
||||
auto initialTrackable = trackables[0];
|
||||
TrackingArea area = {
|
||||
initialTrackable->getTrackablePosition() - initialTrackable->getTrackableSize() / 2.f,
|
||||
initialTrackable->getTrackablePosition() + initialTrackable->getTrackableSize() / 2.f
|
||||
};
|
||||
|
||||
// Find min and max point coordinates for x and y axis over all trackables
|
||||
// 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;
|
||||
auto topLeft = trackableCoordinates - trackableSize / 2.f;
|
||||
auto bottomRight = trackableCoordinates + trackableSize / 2.f;
|
||||
|
||||
if (minPointX < area.topLeft.x)
|
||||
if (topLeft.x < area.topLeft.x)
|
||||
{
|
||||
area.topLeft.x = minPointX;
|
||||
area.topLeft.x = topLeft.x;
|
||||
}
|
||||
if (maxPointX > area.bottomRight.x)
|
||||
if (bottomRight.x > area.bottomRight.x)
|
||||
{
|
||||
area.bottomRight.x = maxPointX;
|
||||
area.bottomRight.x = bottomRight.x;
|
||||
}
|
||||
if (minPointY < area.topLeft.y)
|
||||
if (topLeft.y < area.topLeft.y)
|
||||
{
|
||||
area.topLeft.y = minPointY;
|
||||
area.topLeft.y = topLeft.y;
|
||||
}
|
||||
if (maxPointY > area.bottomRight.y)
|
||||
if (bottomRight.y > area.bottomRight.y)
|
||||
{
|
||||
area.bottomRight.y = maxPointY;
|
||||
area.bottomRight.y = bottomRight.y;
|
||||
}
|
||||
}
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
void TrackingView::adjustSizeToTrackables()
|
||||
{
|
||||
// Calculate new view size
|
||||
auto newViewSize = getTrackingArea().getSize();
|
||||
|
||||
newViewSize = applyPadding(newViewSize);
|
||||
newViewSize = restrainToBounds(newViewSize);
|
||||
|
||||
// Extend view to match aspect ratio
|
||||
auto currentViewSize = getSize();
|
||||
auto aspectRatio = currentViewSize.x / currentViewSize.y;
|
||||
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;
|
||||
if (padding.x <= 1)
|
||||
{
|
||||
padding.x *= viewSize.x;
|
||||
}
|
||||
if (padding.y <= 1)
|
||||
{
|
||||
padding.y *= viewSize.y;
|
||||
}
|
||||
return viewSize + padding;
|
||||
}
|
||||
|
||||
float TrackingView::getRadius(float threshold) const
|
||||
{
|
||||
if (threshold <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (threshold > 1)
|
||||
{
|
||||
return threshold;
|
||||
}
|
||||
|
||||
auto viewSize = getSize();
|
||||
float smallestSide = std::min(viewSize.x, viewSize.y);
|
||||
|
||||
// Only half of the side, since we are calculating radius
|
||||
return smallestSide / 2.f * threshold;
|
||||
}
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
#include "ITrackable.h"
|
||||
#include "../../primitives/circle_object.h"
|
||||
#include "tracking_area.h"
|
||||
#include "tracking_view_options.hpp"
|
||||
|
||||
class CircleObject;
|
||||
|
||||
class TrackingView : public GameObject
|
||||
{
|
||||
public:
|
||||
explicit TrackingView(float freeMoveRadius = 0,
|
||||
float dynamicFollowRadius = 300);
|
||||
explicit TrackingView(TrackingViewOptions options = TrackingViewOptions());
|
||||
|
||||
~TrackingView();
|
||||
|
||||
|
@ -31,17 +31,14 @@ public:
|
|||
private:
|
||||
sf::View *view{};
|
||||
bool hasViewChanged{};
|
||||
float freeMoveRadius;
|
||||
float dynamicFollowRadius;
|
||||
TrackingViewOptions options;
|
||||
std::vector<ITrackable *> trackables;
|
||||
|
||||
CircleObject *marker;
|
||||
|
||||
void initializeView();
|
||||
|
||||
void setSize(sf::Vector2u windowSize);
|
||||
|
||||
void followTarget();
|
||||
void followTrackables();
|
||||
|
||||
void moveCenter(sf::Vector2<float> delta);
|
||||
|
||||
|
@ -49,7 +46,15 @@ private:
|
|||
|
||||
void processTrackableStates();
|
||||
|
||||
void setCenter(sf::Vector2<float> newCenter);
|
||||
void adjustSizeToTrackables();
|
||||
|
||||
void setSize(sf::Vector2f newSize);
|
||||
|
||||
sf::Vector2f applyPadding(sf::Vector2f viewSize) const;
|
||||
|
||||
sf::Vector2f restrainToBounds(sf::Vector2f viewSize) const;
|
||||
|
||||
float getRadius(float threshold) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
42
src/game/camera/tracking_view_options.hpp
Normal file
42
src/game/camera/tracking_view_options.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef HOLESOME_TRACKING_VIEW_OPTIONS_HPP
|
||||
#define HOLESOME_TRACKING_VIEW_OPTIONS_HPP
|
||||
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include "../../config.h"
|
||||
|
||||
struct TrackingViewOptions
|
||||
{
|
||||
/**
|
||||
* Value >1 to set pixel radius.
|
||||
* Value between 0 and 1 to set relative radius based on smallest half-axis-size.
|
||||
*/
|
||||
float freeMoveThreshold = DEF_TV_FREE_MOVE_THRESHOLD;
|
||||
|
||||
/**
|
||||
* 0 for instant follow.
|
||||
*/
|
||||
float softFollowSpeed = DEF_TV_SOFT_FOLLOW_SPEED;
|
||||
/**
|
||||
* 0 for instant resize.
|
||||
*/
|
||||
float softResizeSpeed = DEF_TV_SOFT_RESIZE_SPEED;
|
||||
|
||||
/**
|
||||
* If set to 0, view will not be limited.
|
||||
*/
|
||||
sf::Vector2f minViewSize = DEF_TV_MIN_VIEW_SIZE;
|
||||
|
||||
/**
|
||||
* If set to 0, view will not be limited.
|
||||
*/
|
||||
sf::Vector2f maxViewSize = DEF_TV_MAX_VIEW_SIZE;
|
||||
|
||||
/**
|
||||
* Will be added to tracked area size twice, as padding for each side.
|
||||
* Value >1 to set pixel padding.
|
||||
* Value between 0 and 1 to set relative padding.
|
||||
*/
|
||||
sf::Vector2f viewSizePadding = DEF_TV_VIEW_SIZE_PADDING;
|
||||
};
|
||||
|
||||
#endif //HOLESOME_TRACKING_VIEW_OPTIONS_HPP
|
|
@ -10,12 +10,13 @@ sf::Vector2f Player::getTrackablePosition() const
|
|||
sf::Vector2f Player::getTrackableSize() const
|
||||
{
|
||||
// TODO: Proper implementation
|
||||
return {static_cast<float>(circle->getRadius() * 2), static_cast<float>(circle->getRadius() * 2)};
|
||||
return {circle->getRadius() * 2.f, circle->getRadius() * 2.f};
|
||||
}
|
||||
|
||||
void Player::update()
|
||||
{
|
||||
if (!input->isActive) {
|
||||
if (!input->isActive)
|
||||
{
|
||||
isActive = false;
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue