Fixed directions being inverted. Now differentiating between screen and conventional direction vector
This commit is contained in:
parent
1017fee4d3
commit
f9c592b6e0
16 changed files with 261 additions and 47 deletions
|
@ -18,8 +18,10 @@
|
||||||
#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_RUBBER_FOLLOW_SPEED 0.5f
|
||||||
|
|
||||||
// Directions
|
// Directions
|
||||||
#define DIRECTION_HARD_ACTIVATION_THRESHOLD 0.45f
|
#define DIRECTION_HARD_ACTIVATION_THRESHOLD 0.1f
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// Initialize matrix
|
// Initialize matrix
|
||||||
const Eigen::Matrix<float, 3, 3> CoordinateTransformer::worldToIsometricMatrix =
|
const Eigen::Matrix<float, 3, 3> CoordinateTransformer::worldToIsometricMatrix =
|
||||||
(Eigen::Matrix<float, 3, 3>() <<
|
(Eigen::Matrix<float, 3, 3>() <<
|
||||||
-1, 1, 0,
|
1, -1, 0,
|
||||||
-ISOMETRIC_SKEW, -ISOMETRIC_SKEW, -1,
|
-ISOMETRIC_SKEW, -ISOMETRIC_SKEW, -1,
|
||||||
1, 1, 0
|
1, 1, 0
|
||||||
).finished();
|
).finished();
|
||||||
|
@ -22,3 +22,17 @@ IsometricCoordinates CoordinateTransformer::worldToIsometric(WorldCoordinates wo
|
||||||
isoCoordinatesVector.z() // depth
|
isoCoordinatesVector.z() // depth
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WorldCoordinates CoordinateTransformer::isometricToWorld(IsometricCoordinates isometricCoordinates)
|
||||||
|
{
|
||||||
|
Eigen::Vector3f isoCoordinatesVector;
|
||||||
|
isoCoordinatesVector << isometricCoordinates.x, isometricCoordinates.y, isometricCoordinates.depth;
|
||||||
|
|
||||||
|
Eigen::Vector3f worldCoordinatesVector = worldToIsometricMatrix.inverse() * isoCoordinatesVector / WORLD_TO_ISO_SCALE;
|
||||||
|
|
||||||
|
return {
|
||||||
|
worldCoordinatesVector.x(), // x
|
||||||
|
worldCoordinatesVector.y(), // y
|
||||||
|
worldCoordinatesVector.z() // z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static IsometricCoordinates worldToIsometric(WorldCoordinates worldCoordinates);
|
static IsometricCoordinates worldToIsometric(WorldCoordinates worldCoordinates);
|
||||||
|
static WorldCoordinates isometricToWorld(IsometricCoordinates isometricCoordinates);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,14 @@ struct IsometricCoordinates
|
||||||
{
|
{
|
||||||
return {x, y};
|
return {x, y};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IsometricCoordinates() = default;
|
||||||
|
|
||||||
|
IsometricCoordinates(float x, float y, float depth = 0) : x(x), y(y), depth(depth)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit IsometricCoordinates (sf::Vector2f vector) : x(vector.x), y(vector.y), depth(0)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GridCoordinates
|
struct GridCoordinates
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
//
|
|
||||||
// Created by max on 27.04.23.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "translated_coordinates.h"
|
#include "translated_coordinates.h"
|
||||||
|
|
||||||
WorldCoordinates TranslatedCoordinates::world() const {
|
WorldCoordinates TranslatedCoordinates::world() const {
|
||||||
|
@ -9,7 +5,7 @@ WorldCoordinates TranslatedCoordinates::world() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
IsometricCoordinates TranslatedCoordinates::isometric() const {
|
IsometricCoordinates TranslatedCoordinates::isometric() const {
|
||||||
return isoCoordTransformer->worldToIsometric(worldCoordinates);
|
return coordTransformer->worldToIsometric(worldCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
GridCoordinates TranslatedCoordinates::grid() const {
|
GridCoordinates TranslatedCoordinates::grid() const {
|
||||||
|
@ -21,7 +17,11 @@ void TranslatedCoordinates::set(WorldCoordinates newWorldCoordinates) {
|
||||||
this->worldCoordinates = newWorldCoordinates;
|
this->worldCoordinates = newWorldCoordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatedCoordinates::set(TranslatedCoordinates newCoordinates) {
|
void TranslatedCoordinates::set(IsometricCoordinates newIsometricCoordinates) {
|
||||||
|
this->worldCoordinates = coordTransformer->isometricToWorld(newIsometricCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TranslatedCoordinates::set(const TranslatedCoordinates& newCoordinates) {
|
||||||
this->worldCoordinates = newCoordinates.world();
|
this->worldCoordinates = newCoordinates.world();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,9 @@ public:
|
||||||
|
|
||||||
void set(WorldCoordinates newWorldCoordinates);
|
void set(WorldCoordinates newWorldCoordinates);
|
||||||
|
|
||||||
void set(TranslatedCoordinates newCoordinates);
|
void set(const TranslatedCoordinates& newCoordinates);
|
||||||
|
|
||||||
|
void set(IsometricCoordinates newIsometricCoordinates);
|
||||||
|
|
||||||
void move(WorldCoordinates deltaWorldCoordinates);
|
void move(WorldCoordinates deltaWorldCoordinates);
|
||||||
|
|
||||||
|
@ -33,7 +35,7 @@ public:
|
||||||
private:
|
private:
|
||||||
WorldCoordinates worldCoordinates;
|
WorldCoordinates worldCoordinates;
|
||||||
const float worldToGridFactor = INITIAL_WORLD_TO_GRID_FACTOR;
|
const float worldToGridFactor = INITIAL_WORLD_TO_GRID_FACTOR;
|
||||||
const std::shared_ptr<CoordinateTransformer> isoCoordTransformer = std::make_shared<CoordinateTransformer>();
|
const std::shared_ptr<CoordinateTransformer> coordTransformer = std::make_shared<CoordinateTransformer>();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,20 @@ GridDebugLayer::GridDebugLayer(int minX, int maxX, int minY, int maxY)
|
||||||
{
|
{
|
||||||
for (int y = minY; y <= maxY; y++)
|
for (int y = minY; y <= maxY; y++)
|
||||||
{
|
{
|
||||||
auto *gameObject = new CircleObject(DB_ISOPLANE_CORNER_RADIUS, sf::Color::Red);
|
auto color = sf::Color(128, 128, 128);
|
||||||
|
|
||||||
|
if (x == 0 && y != 0)
|
||||||
|
{
|
||||||
|
// Y-axis
|
||||||
|
color = sf::Color::Red;
|
||||||
|
}
|
||||||
|
else if (y == 0)
|
||||||
|
{
|
||||||
|
// X-axis
|
||||||
|
color = sf::Color::Blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *gameObject = new CircleObject(DB_ISOPLANE_CORNER_RADIUS, color);
|
||||||
gameObject->coordinates.set(WorldCoordinates(x, y, 0));
|
gameObject->coordinates.set(WorldCoordinates(x, y, 0));
|
||||||
marker.push_back(gameObject);
|
marker.push_back(gameObject);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,8 +63,15 @@ void Game::addGameObject(GameObject *gameObject)
|
||||||
|
|
||||||
void Game::update()
|
void Game::update()
|
||||||
{
|
{
|
||||||
|
// Basic Updates
|
||||||
for (auto &gameObject: gameObjects)
|
for (auto &gameObject: gameObjects)
|
||||||
{
|
{
|
||||||
gameObject->update(this);
|
gameObject->update(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Late updates
|
||||||
|
for (auto &gameObject: gameObjects)
|
||||||
|
{
|
||||||
|
gameObject->lateUpdate(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,19 @@
|
||||||
|
|
||||||
class Game;
|
class Game;
|
||||||
|
|
||||||
class GameObject {
|
class GameObject
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
GameObject();
|
GameObject();
|
||||||
|
|
||||||
virtual void draw(sf::RenderWindow *window) const = 0;
|
virtual void draw(sf::RenderWindow *window) const
|
||||||
virtual void update(Game *game) = 0;
|
{}
|
||||||
|
|
||||||
|
virtual void update(Game *game)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual void lateUpdate(Game *game)
|
||||||
|
{}
|
||||||
|
|
||||||
TranslatedCoordinates coordinates;
|
TranslatedCoordinates coordinates;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,13 @@ HardDirection Direction::getKeyDirection(sf::Keyboard::Key key)
|
||||||
return map[key];
|
return map[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sf::Vector2f Direction::getScreenVector(HardDirection direction)
|
||||||
|
{
|
||||||
|
auto vector = getVector(direction);
|
||||||
|
vector.y *= -1;
|
||||||
|
return vector;
|
||||||
|
}
|
||||||
|
|
||||||
sf::Vector2f Direction::getVector(HardDirection direction)
|
sf::Vector2f Direction::getVector(HardDirection direction)
|
||||||
{
|
{
|
||||||
auto vector = sf::Vector2f(0.0f, 0.0f);
|
auto vector = sf::Vector2f(0.0f, 0.0f);
|
||||||
|
@ -33,11 +40,11 @@ sf::Vector2f Direction::getVector(HardDirection direction)
|
||||||
// Combine all relevant directions into one vector
|
// Combine all relevant directions into one vector
|
||||||
if (direction & HardDirection::UP)
|
if (direction & HardDirection::UP)
|
||||||
{
|
{
|
||||||
vector.y -= 1;
|
vector.y += 1;
|
||||||
}
|
}
|
||||||
if (direction & HardDirection::DOWN)
|
if (direction & HardDirection::DOWN)
|
||||||
{
|
{
|
||||||
vector.y += 1;
|
vector.y -= 1;
|
||||||
}
|
}
|
||||||
if (direction & HardDirection::LEFT)
|
if (direction & HardDirection::LEFT)
|
||||||
{
|
{
|
||||||
|
@ -51,7 +58,7 @@ sf::Vector2f Direction::getVector(HardDirection direction)
|
||||||
return normalize(vector);
|
return normalize(vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
HardDirection Direction::getHardDirection(sf::Vector2f vector)
|
HardDirection Direction::getHardDirectionFromVector(sf::Vector2f vector)
|
||||||
{
|
{
|
||||||
HardDirection direction = HardDirection::NONE;
|
HardDirection direction = HardDirection::NONE;
|
||||||
vector = normalize(vector);
|
vector = normalize(vector);
|
||||||
|
@ -91,7 +98,7 @@ sf::Vector2f Direction::asVector() const
|
||||||
|
|
||||||
HardDirection Direction::asHardDirection() const
|
HardDirection Direction::asHardDirection() const
|
||||||
{
|
{
|
||||||
return getHardDirection(directionVector);
|
return getHardDirectionFromVector(directionVector);
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction::Direction(sf::Vector2f directionVector)
|
Direction::Direction(sf::Vector2f directionVector)
|
||||||
|
@ -103,3 +110,10 @@ Direction::Direction(HardDirection direction)
|
||||||
{
|
{
|
||||||
this->directionVector = getVector(direction);
|
this->directionVector = getVector(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sf::Vector2f Direction::asScreenVector() const
|
||||||
|
{
|
||||||
|
auto screenVector = directionVector;
|
||||||
|
screenVector.y *= -1;
|
||||||
|
return screenVector;
|
||||||
|
}
|
||||||
|
|
|
@ -23,11 +23,13 @@ public:
|
||||||
static HardDirection getKeyDirection(sf::Keyboard::Key key);
|
static HardDirection getKeyDirection(sf::Keyboard::Key key);
|
||||||
|
|
||||||
static sf::Vector2f getVector(HardDirection direction);
|
static sf::Vector2f getVector(HardDirection direction);
|
||||||
|
static sf::Vector2f getScreenVector(HardDirection direction);
|
||||||
|
|
||||||
static HardDirection getHardDirection(sf::Vector2f vector);
|
static HardDirection getHardDirectionFromVector(sf::Vector2f vector);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
sf::Vector2f asVector() const;
|
sf::Vector2f asVector() const;
|
||||||
|
sf::Vector2f asScreenVector() const;
|
||||||
|
|
||||||
HardDirection asHardDirection() const;
|
HardDirection asHardDirection() const;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ sf::Vector2f Player::getTrackableSize() const
|
||||||
void Player::update(Game *game)
|
void Player::update(Game *game)
|
||||||
{
|
{
|
||||||
auto moveDirection = InputMapper::getInputDirection().asVector();
|
auto moveDirection = InputMapper::getInputDirection().asVector();
|
||||||
auto moveDelta = moveDirection * 10.0f * FRAME_TIME.asSeconds();
|
auto moveDelta = moveDirection * 30.0f * FRAME_TIME.asSeconds();
|
||||||
coordinates.move(moveDelta);
|
coordinates.move(moveDelta);
|
||||||
circle->coordinates.set(coordinates);
|
circle->coordinates.set(coordinates);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,6 @@ Player::Player(const sf::Color color, WorldCoordinates initCoordinates)
|
||||||
{
|
{
|
||||||
coordinates.set(initCoordinates);
|
coordinates.set(initCoordinates);
|
||||||
|
|
||||||
circle = new CircleObject(50, color);
|
circle = new CircleObject(10, color);
|
||||||
circle->coordinates.set(coordinates);
|
circle->coordinates.set(coordinates);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,13 @@
|
||||||
#include "world_view.h"
|
#include "world_view.h"
|
||||||
|
#include "../../utilities/vector_utils.hpp"
|
||||||
WorldView::WorldView() : view(nullptr), hasViewChanged(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
WorldView::~WorldView()
|
WorldView::~WorldView()
|
||||||
{
|
{
|
||||||
delete view;
|
delete view;
|
||||||
|
delete marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldView::draw(sf::RenderWindow *window) const
|
void WorldView::lateUpdate(Game *game)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldView::update(Game *game)
|
|
||||||
{
|
{
|
||||||
// Initialize if necessary
|
// Initialize if necessary
|
||||||
if (view == nullptr)
|
if (view == nullptr)
|
||||||
|
@ -24,8 +18,10 @@ void WorldView::update(Game *game)
|
||||||
// Update size
|
// Update size
|
||||||
setSize(game->window->getSize());
|
setSize(game->window->getSize());
|
||||||
|
|
||||||
// Update position
|
if (target != nullptr)
|
||||||
moveViewByControls();
|
{
|
||||||
|
followTarget();
|
||||||
|
}
|
||||||
|
|
||||||
// Update window if necessary
|
// Update window if necessary
|
||||||
if (hasViewChanged)
|
if (hasViewChanged)
|
||||||
|
@ -37,28 +33,147 @@ void WorldView::update(Game *game)
|
||||||
|
|
||||||
void WorldView::initializeView(Game *game)
|
void WorldView::initializeView(Game *game)
|
||||||
{
|
{
|
||||||
auto center = game->window->getView().getCenter();
|
|
||||||
auto size = game->window->getView().getSize();
|
auto size = game->window->getView().getSize();
|
||||||
view = new sf::View(center, size);
|
view = new sf::View({0, 0}, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldView::setSize(sf::Vector2u windowSize)
|
void WorldView::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);
|
sf::Vector2f viewSize = sf::Vector2f(windowSize.x, windowSize.y);
|
||||||
view->setSize(viewSize);
|
view->setSize(viewSize);
|
||||||
hasViewChanged = true;
|
hasViewChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldView::moveViewByControls()
|
WorldView::WorldView(ITrackable *trackable, sf::Vector2f freeMoveArea, sf::Vector2f dynamicFollowArea)
|
||||||
|
: target(trackable), freeMoveArea(freeMoveArea), dynamicFollowArea(dynamicFollowArea), view(nullptr),
|
||||||
|
hasViewChanged(false)
|
||||||
{
|
{
|
||||||
auto moveDirection = InputMapper::getInputDirection().asHardDirection();
|
marker = new CircleObject(2, sf::Color::Yellow);
|
||||||
if (moveDirection == HardDirection::NONE)
|
}
|
||||||
|
|
||||||
|
sf::Vector2f WorldView::getSize() const
|
||||||
|
{
|
||||||
|
return view->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::Vector2f WorldView::getCenter() const
|
||||||
|
{
|
||||||
|
return view->getCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldView::followTarget()
|
||||||
|
{
|
||||||
|
|
||||||
|
auto closestPositionInDynamic = getClosestPositionInArea(dynamicFollowArea);
|
||||||
|
marker->coordinates.set(IsometricCoordinates(closestPositionInDynamic));
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isTargetInArea(freeMoveArea))
|
||||||
{
|
{
|
||||||
|
// Nothing to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float stepSize = 100.0f * FRAME_TIME.asSeconds();
|
// performHardFollow();
|
||||||
auto delta = stepSize * Direction::getVector(moveDirection);
|
// if (isTargetInArea(dynamicFollowArea))
|
||||||
this->view->move(delta);
|
// {
|
||||||
|
// // Slowly push target back into free area
|
||||||
|
// performDynamicFollow();
|
||||||
|
// } else
|
||||||
|
// {
|
||||||
|
// // Hard follow
|
||||||
|
// performHardFollow();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldView::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::Vector2f WorldView::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::Vector2f WorldView::getRubber() const
|
||||||
|
{
|
||||||
|
return normalize(target->getTrackablePosition() - getCenter());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldView::performHardFollow()
|
||||||
|
{
|
||||||
|
auto closestPositionInDynamic = getClosestPositionInArea(dynamicFollowArea);
|
||||||
|
auto delta = getCenter() - closestPositionInDynamic;
|
||||||
|
moveCenter(-delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldView::moveCenter(sf::Vector2<float> delta)
|
||||||
|
{
|
||||||
|
view->move(delta);
|
||||||
hasViewChanged = true;
|
hasViewChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldView::performDynamicFollow()
|
||||||
|
{
|
||||||
|
auto closestPositionInDynamic = getClosestPositionInArea(freeMoveArea);
|
||||||
|
auto delta = getCenter() - closestPositionInDynamic;
|
||||||
|
moveCenter(delta * VIEW_RUBBER_FOLLOW_SPEED * FRAME_TIME.asSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldView::draw(sf::RenderWindow *window) const
|
||||||
|
{
|
||||||
|
marker->draw(window);
|
||||||
|
}
|
||||||
|
|
|
@ -4,27 +4,53 @@
|
||||||
|
|
||||||
#include "../game_object.h"
|
#include "../game_object.h"
|
||||||
#include "../game.h"
|
#include "../game.h"
|
||||||
|
#include "ITrackable.h"
|
||||||
|
#include "../../primitives/circle_object.h"
|
||||||
|
|
||||||
class WorldView : public GameObject
|
class WorldView : public GameObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit WorldView();
|
explicit WorldView(ITrackable *trackable = nullptr,
|
||||||
|
sf::Vector2f freeMoveArea = {200, 200},
|
||||||
|
sf::Vector2f dynamicFollowArea = {500, 500});
|
||||||
|
|
||||||
~WorldView();
|
~WorldView();
|
||||||
|
|
||||||
void draw(sf::RenderWindow *window) const override;
|
|
||||||
|
|
||||||
void update(Game *game) override;
|
void draw(sf::RenderWindow *window) const override;
|
||||||
|
void lateUpdate(Game *game) override;
|
||||||
|
|
||||||
|
sf::Vector2f getSize() const;
|
||||||
|
sf::Vector2f getCenter() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf::View *view;
|
sf::View *view{};
|
||||||
bool hasViewChanged;
|
bool hasViewChanged{};
|
||||||
|
sf::Vector2f freeMoveArea;
|
||||||
|
sf::Vector2f dynamicFollowArea;
|
||||||
|
ITrackable *target;
|
||||||
|
|
||||||
|
CircleObject *marker;
|
||||||
|
|
||||||
void initializeView(Game *game);
|
void initializeView(Game *game);
|
||||||
|
|
||||||
void setSize(sf::Vector2u windowSize);
|
void setSize(sf::Vector2u windowSize);
|
||||||
|
|
||||||
void moveViewByControls();
|
void followTarget();
|
||||||
|
|
||||||
|
bool isTargetInArea(sf::Vector2f areaSize);
|
||||||
|
|
||||||
|
sf::Vector2f getClosestPositionInArea(sf::Vector2f areaSize) const;
|
||||||
|
|
||||||
|
/// Calculates the direction the target should be pulled back in.
|
||||||
|
/// \return Normalized vector, pointing from center to target.
|
||||||
|
sf::Vector2f getRubber() const;
|
||||||
|
|
||||||
|
void performHardFollow();
|
||||||
|
|
||||||
|
void moveCenter(sf::Vector2<float> delta);
|
||||||
|
|
||||||
|
void performDynamicFollow();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,11 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
auto game = GameFactory::createWindowed("Holesome");
|
auto game = GameFactory::createWindowed("Holesome");
|
||||||
|
|
||||||
|
auto player = new Player(sf::Color::Green, {0, 0});
|
||||||
|
|
||||||
game->addGameObject(new GridDebugLayer(0, 50, 0, 50));
|
game->addGameObject(new GridDebugLayer(0, 50, 0, 50));
|
||||||
|
game->addGameObject(player);
|
||||||
game->addGameObject(new WorldView());
|
game->addGameObject(new WorldView());
|
||||||
game->addGameObject(new Player(sf::Color::Blue, WorldCoordinates(0, 0)));
|
|
||||||
|
|
||||||
game->run();
|
game->run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ template<typename T>
|
||||||
sf::Vector2<T> normalize(sf::Vector2<T> v)
|
sf::Vector2<T> normalize(sf::Vector2<T> v)
|
||||||
{
|
{
|
||||||
auto length = std::sqrt(v.x * v.x + v.y * v.y);
|
auto length = std::sqrt(v.x * v.x + v.y * v.y);
|
||||||
|
|
||||||
if (length != 0)
|
if (length != 0)
|
||||||
{
|
{
|
||||||
v.x /= length;
|
v.x /= length;
|
||||||
|
|
Loading…
Reference in a new issue