#include <iostream>
#include <limits>
#include <cstdlib>
#include <cassert>
#include <functional>
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window({ 512u, 512u }, "scale animation test");
sf::RectangleShape shape({ 16, 32 });
shape.setFillColor(sf::Color::Red);
shape.setPosition(window.getDefaultView().getCenter());
shape.setOrigin(shape.getLocalBounds().width / 2.f, shape.getLocalBounds().height / 2.f);
sf::Clock clock;
auto timeSinceLastUpdate = sf::Time::Zero;
const auto TimePerFrame = sf::seconds(1 / 60.f);
bool scaleToggle = true;
auto closeEnough = // for float point comparing
[](auto a, auto b, auto epsilon)
{
assert(std::isless(0, epsilon)); // epsilon is a part of the whole quantity
assert(std::isless(epsilon, 1));
const auto delta = std::abs(a - b);
const auto x = std::abs(a);
const auto y = std::abs(b);
// comparable generally and |a - b| < eps * (|a| + |b|) / 2
return std::isless(epsilon * y, x)
&& std::isless(epsilon * x, y)
&& std::isless((delta + delta) / (x + y), epsilon);
};
auto scalingEffect =
[&](const auto& targetScale)
{
auto resultScale = shape.getScale();
const static auto speed = 16.f;
// easing in tearm of constant speed
resultScale += (targetScale - resultScale) * speed * TimePerFrame.asSeconds();
shape.setScale(resultScale);
return closeEnough(targetScale.y, resultScale.y, 0.001f); // compare float points
};
auto update = [&]()
{
auto dt = clock.restart();
timeSinceLastUpdate += dt;
while (timeSinceLastUpdate > TimePerFrame)
{
timeSinceLastUpdate -= TimePerFrame;
// run the animation
if (scaleToggle)
{
if (scalingEffect(sf::Vector2f{ 1.f, 0.5f }))
scaleToggle = !scaleToggle;
}
else
{
if (scalingEffect(sf::Vector2f{ 1.f, 1.f }))
scaleToggle = !scaleToggle;
}
}
};
auto render = [&]()
{
window.clear();
window.draw(shape);
window.display();
};
auto processEvent = [&]()
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
};
// game loop
while (window.isOpen())
{
processEvent();
update();
render();
}
}