Hello everyone !
I'm back to collision issues since I started to use Tiled Editor and the sfml-tmxloader. Now I'm wondering how could I handle efficiently a collision between an entity and a tilemap created with Tiled?
I use a TileMap class (that inherit from SceneNode class), which allows me to load a tilemap from TiledEditor using sfml-tmxloader.
So far I was able to detect a collision between the player entity and objects from the tilemap, here is the code:
std::vector<sf::Vector2f> points;
points.push_back(sf::Vector2f(0.f, 8.f));
points.push_back(sf::Vector2f(-8.f, 0.f));
points.push_back(sf::Vector2f(8.f, 0.f));
points.push_back(sf::Vector2f(0.f, 16.f));
sf::Vector2f position = mPlayerCharacter->getWorldPosition();
std::vector<tmx::MapLayer>& layers = mTileMap->getLayers();
for (auto& layer : layers)
{
if (layer.type == tmx::ObjectGroup)
{
for (auto& obj : layer.objects)
{
if (layer.name == "Objects")
{
for (auto& point : points) {
if (obj.Contains(position + point))
{
std::cout << "Collision";
break;
}
}
}
}
}
}
But I was wondering how to react to that collision according to the book way-of-doing-things.
Usually I just take the current position and calculate the future position, then I test the future position, if there's no collision I just set the future position to the sprite, like this :
std::vector<sf::Vector2f> points;
points.push_back(sf::Vector2f(0.f, 8.f));
points.push_back(sf::Vector2f(-8.f, 0.f));
points.push_back(sf::Vector2f(8.f, 0.f));
points.push_back(sf::Vector2f(0.f, 16.f));
sf::Vector2f position = mSprite.getPosition();
sf::Vector2f velocity = getVelocity() * dt.asSeconds();
position += velocity;
//Testing collision in the future position
for(auto& point : points) {
if(obj.Contains(position + point)) {
//Collision!
}
else
mSprite.setPosition(position);
}
But I don't know how to implement this logic according to the entity system. I tried to handle this directly in my Character class (which looks like the Aircraft class) but I wasn't able to get a correct collision response.
I don't see how I could get the future position of an entity in a generalize approach.
I was thinking of using the SceneNode::checkNodeCollision to handle the collision, which will give me something like this:
//Inside the handleCollision function
void World::handleCollision(sf::Time dt) {
std::set<SceneNode::Pair> collisionPairs;
mSceneGraph.checkSceneCollision(mSceneGraph, collisionPairs);
for (SceneElement::Pair pair : collisionPairs) {
if (matchesCategories(pair, Category::PlayerCharacter, Category::TileMap)) {
auto& player = static_cast<Character&>(*pair.first);
auto& tileMap = static_cast<TileMap&>(*pair.second);
player.checkTileMapCollision(tileMap, dt);
}
....
// Inside the Character class
void Character::checkTileMapCollision(TileMap& tileMap, sf::Time dt){
std::vector<sf::Vector2f> points;
points.push_back(sf::Vector2f(0.f, 8.f));
points.push_back(sf::Vector2f(-8.f, 0.f));
points.push_back(sf::Vector2f(8.f, 0.f));
points.push_back(sf::Vector2f(0.f, 16.f));
sf::Vector2f position = getWorldPosition();
sf::Vector2f velocity = getVelocity() * dt.asSeconds();
position += velocity;
//Testing collision in the future position
for(auto& point : points) {
if(obj.Contains(position + point)) {
//Collision!
}
else
setPosition(position);
}
I don't know if my logic is correct to be honest. Looking for some help guys, any idea is welcomed