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/utilities/magic_enum.hpp
|
||||||
src/game/player/player_spawner.cpp
|
src/game/player/player_spawner.cpp
|
||||||
src/game/player/player_spawner.hpp
|
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
|
set(PHYSICS_00_SOURCES
|
||||||
src/prototypes/physics_00.cpp)
|
src/prototypes/physics_00.cpp)
|
||||||
|
|
|
@ -20,7 +20,13 @@
|
||||||
#define ISOMETRIC_SKEW 0.3f
|
#define ISOMETRIC_SKEW 0.3f
|
||||||
#define WORLD_TO_ISO_SCALE 10.0f
|
#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
|
// Inputs
|
||||||
#define JOYSTICK_DEADZONE 0.1f
|
#define JOYSTICK_DEADZONE 0.1f
|
||||||
|
|
|
@ -12,6 +12,11 @@ struct TrackingArea
|
||||||
{
|
{
|
||||||
return topLeft + (bottomRight - topLeft) / 2.f;
|
return topLeft + (bottomRight - topLeft) / 2.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sf::Vector2f getSize() const
|
||||||
|
{
|
||||||
|
return bottomRight - topLeft;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#include "tracking_view.h"
|
#include "tracking_view.h"
|
||||||
#include "../../utilities/vector_utils.hpp"
|
#include "../../utilities/vector_utils.hpp"
|
||||||
|
|
||||||
TrackingView::TrackingView(float freeMoveRadius, float dynamicFollowRadius) : freeMoveRadius(freeMoveRadius),
|
TrackingView::TrackingView(TrackingViewOptions options) : options(options),
|
||||||
dynamicFollowRadius(dynamicFollowRadius),
|
|
||||||
view(nullptr),
|
view(nullptr),
|
||||||
hasViewChanged(false)
|
hasViewChanged(false)
|
||||||
{
|
{
|
||||||
|
@ -27,13 +26,10 @@ void TrackingView::lateUpdate()
|
||||||
|
|
||||||
processTrackableStates();
|
processTrackableStates();
|
||||||
|
|
||||||
// Update size
|
|
||||||
// TODO: Update size based on length of tracked objects
|
|
||||||
setSize(Game::getInstance()->window->getSize());
|
|
||||||
|
|
||||||
if (!trackables.empty())
|
if (!trackables.empty())
|
||||||
{
|
{
|
||||||
followTarget();
|
followTrackables();
|
||||||
|
adjustSizeToTrackables();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update window if necessary
|
// Update window if necessary
|
||||||
|
@ -51,18 +47,22 @@ void TrackingView::initializeView()
|
||||||
hasViewChanged = true;
|
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?
|
// 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
|
// Nothing to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sf::Vector2f viewSize = sf::Vector2f(windowSize.x, windowSize.y);
|
if (options.softResizeSpeed != 0) {
|
||||||
view->setSize(viewSize);
|
// Smooth out transition to new size
|
||||||
|
newSize = size + (newSize - size) * options.softResizeSpeed * FRAME_TIME.asSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
view->setSize(newSize);
|
||||||
hasViewChanged = true;
|
hasViewChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ sf::Vector2f TrackingView::getCenter() const
|
||||||
return view->getCenter();
|
return view->getCenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackingView::followTarget()
|
void TrackingView::followTrackables()
|
||||||
{
|
{
|
||||||
auto trackingPoint = getTrackingArea().getCenter();
|
auto trackingPoint = getTrackingArea().getCenter();
|
||||||
if (DEVELOPER_MODE)
|
if (DEVELOPER_MODE)
|
||||||
|
@ -87,32 +87,33 @@ void TrackingView::followTarget()
|
||||||
// Calculate distance to target to check how to handle it
|
// Calculate distance to target to check how to handle it
|
||||||
auto currentCenter = view->getCenter();
|
auto currentCenter = view->getCenter();
|
||||||
auto vectorToTarget = trackingPoint - currentCenter;
|
auto vectorToTarget = trackingPoint - currentCenter;
|
||||||
float distanceToTarget = length(vectorToTarget);
|
auto distanceToTarget = length(vectorToTarget);
|
||||||
|
|
||||||
if (distanceToTarget <= freeMoveRadius)
|
if (distanceToTarget <= getRadius(options.freeMoveThreshold))
|
||||||
{
|
{
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move view to place tracking-point at edge of area
|
|
||||||
auto deltaToDesiredView = normalize(vectorToTarget) * FRAME_TIME.asSeconds();
|
|
||||||
|
|
||||||
if (distanceToTarget <= dynamicFollowRadius)
|
|
||||||
{
|
// Targets are outside of free move radius, follow them
|
||||||
// Reduce delta to make it less jaring
|
auto deltaToDesiredView = normalize(vectorToTarget);
|
||||||
deltaToDesiredView *= VIEW_DYNAMIC_FOLLOW_SPEED * (distanceToTarget - freeMoveRadius);
|
|
||||||
} else
|
// Reduce delta to edge of free-move area to make it less jaring
|
||||||
{
|
deltaToDesiredView *= distanceToTarget - getRadius(options.freeMoveThreshold);
|
||||||
// Hard follow
|
|
||||||
deltaToDesiredView *= dynamicFollowRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
moveCenter(deltaToDesiredView);
|
moveCenter(deltaToDesiredView);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackingView::moveCenter(sf::Vector2<float> delta)
|
void TrackingView::moveCenter(sf::Vector2<float> delta)
|
||||||
{
|
{
|
||||||
|
if (options.softFollowSpeed != 0)
|
||||||
|
{
|
||||||
|
// Soft
|
||||||
|
delta *= options.softFollowSpeed * FRAME_TIME.asSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
view->move(delta);
|
view->move(delta);
|
||||||
hasViewChanged = true;
|
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
|
TrackingArea TrackingView::getTrackingArea() const
|
||||||
{
|
{
|
||||||
sf::Vector2f initialPoints = trackables[0]->getTrackablePosition();
|
auto initialTrackable = trackables[0];
|
||||||
TrackingArea area = {initialPoints, initialPoints};
|
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)
|
for (auto trackable: trackables)
|
||||||
{
|
{
|
||||||
auto trackableCoordinates = trackable->getTrackablePosition();
|
auto trackableCoordinates = trackable->getTrackablePosition();
|
||||||
auto trackableSize = trackable->getTrackableSize();
|
auto trackableSize = trackable->getTrackableSize();
|
||||||
|
|
||||||
auto minPointX = trackableCoordinates.x - trackableSize.x / 2.f;
|
auto topLeft = trackableCoordinates - trackableSize / 2.f;
|
||||||
auto maxPointX = trackableCoordinates.x + trackableSize.x / 2.f;
|
auto bottomRight = trackableCoordinates + trackableSize / 2.f;
|
||||||
auto minPointY = trackableCoordinates.y - trackableSize.y / 2.f;
|
|
||||||
auto maxPointY = trackableCoordinates.y + trackableSize.y / 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;
|
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 "ITrackable.h"
|
||||||
#include "../../primitives/circle_object.h"
|
#include "../../primitives/circle_object.h"
|
||||||
#include "tracking_area.h"
|
#include "tracking_area.h"
|
||||||
|
#include "tracking_view_options.hpp"
|
||||||
|
|
||||||
class CircleObject;
|
class CircleObject;
|
||||||
|
|
||||||
class TrackingView : public GameObject
|
class TrackingView : public GameObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit TrackingView(float freeMoveRadius = 0,
|
explicit TrackingView(TrackingViewOptions options = TrackingViewOptions());
|
||||||
float dynamicFollowRadius = 300);
|
|
||||||
|
|
||||||
~TrackingView();
|
~TrackingView();
|
||||||
|
|
||||||
|
@ -31,17 +31,14 @@ public:
|
||||||
private:
|
private:
|
||||||
sf::View *view{};
|
sf::View *view{};
|
||||||
bool hasViewChanged{};
|
bool hasViewChanged{};
|
||||||
float freeMoveRadius;
|
TrackingViewOptions options;
|
||||||
float dynamicFollowRadius;
|
|
||||||
std::vector<ITrackable *> trackables;
|
std::vector<ITrackable *> trackables;
|
||||||
|
|
||||||
CircleObject *marker;
|
CircleObject *marker;
|
||||||
|
|
||||||
void initializeView();
|
void initializeView();
|
||||||
|
|
||||||
void setSize(sf::Vector2u windowSize);
|
void followTrackables();
|
||||||
|
|
||||||
void followTarget();
|
|
||||||
|
|
||||||
void moveCenter(sf::Vector2<float> delta);
|
void moveCenter(sf::Vector2<float> delta);
|
||||||
|
|
||||||
|
@ -49,7 +46,15 @@ private:
|
||||||
|
|
||||||
void processTrackableStates();
|
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
|
sf::Vector2f Player::getTrackableSize() const
|
||||||
{
|
{
|
||||||
// TODO: Proper implementation
|
// 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()
|
void Player::update()
|
||||||
{
|
{
|
||||||
if (!input->isActive) {
|
if (!input->isActive)
|
||||||
|
{
|
||||||
isActive = false;
|
isActive = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue