Created
July 10, 2020 18:41
-
-
Save fallahn/8a1dfe8c7a480dbdb9c314c90f8ea919 to your computer and use it in GitHub Desktop.
Following a path with SFML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SFML/Graphics.hpp> | |
#include <SFML/Window.hpp> | |
#include <SFML/System.hpp> | |
#include <array> | |
#include <cassert> | |
//dot product calculation | |
//https://relativity.net.au/gaming/java/DotProduct.html | |
float dot(const sf::Vector2f& lv, const sf::Vector2f& rv) | |
{ | |
return lv.x * rv.x + lv.y * rv.y; | |
} | |
//normalises a vector to unit length (length of 1) | |
sf::Vector2f normalise(sf::Vector2f source) | |
{ | |
float length = std::sqrt(dot(source, source)); | |
assert(length != 0); | |
return source /= length; | |
} | |
//positions which make up the path to travel | |
const std::array<sf::Vector2f, 4u> path = | |
{ | |
sf::Vector2f(200.f, 400.f), | |
sf::Vector2f(400.f, 100.f), | |
sf::Vector2f(300.f, 500.f), | |
sf::Vector2f(200.f, 300.f) | |
}; | |
//this is our game entity | |
struct Ship final | |
{ | |
sf::CircleShape circleShape; | |
sf::Vector2f direction; | |
sf::Vector2f target; | |
std::size_t nextTarget = 0; | |
static constexpr float Speed = 200.f; | |
Ship() | |
{ | |
//set initial properties | |
circleShape.setRadius(5.f); | |
circleShape.setFillColor(sf::Color::Red); | |
setTarget(path[0]); | |
} | |
void setTarget(sf::Vector2f targetPoint) | |
{ | |
//set the travel direction. this only needs to | |
//be done once when setting the target point as we'll | |
//be travelling in the same direction up until we | |
//receive a new target | |
direction = targetPoint - circleShape.getPosition(); | |
//by normalising the value we can make sure to travel | |
//at a constant speed, whilst also making use of the dot product | |
direction = normalise(direction); | |
//make sure to remember the world coords of our current target | |
target = targetPoint; | |
} | |
void update(float dt) | |
{ | |
//move by our fixed speed in the direction towards | |
//the current target (multiplied by frame time) | |
circleShape.move(direction * Speed * dt); | |
//now check where we are in relation to the current target. | |
//if we take the dot product of the direction we're moving | |
//with the vector created with the current position relative | |
//to the current target, we can tell if we've overshot yet | |
//if both vectors are pointing in the same direction (ie the | |
//target is still in front of us) the dot product will be | |
//greater than zero. If it is less than zero then the target | |
//vector points in the opposite direction to the movement | |
//vector, and is therefore behind us. | |
//https://betterexplained.com/articles/vector-calculus-understanding-the-dot-product/ | |
auto targetDirection = target - circleShape.getPosition(); | |
if (dot(direction, targetDirection) < 0) | |
{ | |
//correct for the overshoot by placing the entity at the | |
//target position, although this is not strictly necessary | |
//as the direction will automatically be corrected when | |
//setting the next target point. | |
circleShape.setPosition(target); | |
//get the next target id | |
nextTarget = (nextTarget + 1) % path.size(); | |
//and set the next target. | |
setTarget(path[nextTarget]); | |
} | |
} | |
}; | |
int main() | |
{ | |
sf::RenderWindow window; | |
window.create(sf::VideoMode(800, 600), "Window"); | |
const float frameTime = 1.f / 60.f; | |
float accumulator = 0.f; | |
sf::Clock frameClock; | |
Ship ship; | |
while (window.isOpen()) | |
{ | |
sf::Event evt; | |
while (window.pollEvent(evt)) | |
{ | |
if (evt.type == sf::Event::Closed) | |
{ | |
window.close(); | |
} | |
} | |
accumulator += frameClock.restart().asSeconds(); | |
while (accumulator > frameTime) | |
{ | |
accumulator -= frameTime; | |
ship.update(frameTime); | |
} | |
window.clear(); | |
window.draw(ship.circleShape); | |
window.display(); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment