Ejemplo n.º 1
0
bool GD_EXTENSION_API SingleTileCollision(std::map<gd::String, std::vector<RuntimeObject*>*> tileMapList,
                         int layer,
                         int column,
                         int row,
                         std::map<gd::String, std::vector<RuntimeObject*>*> objectLists,
                         bool conditionInverted)
{
    return TwoObjectListsTest(tileMapList, objectLists, conditionInverted, [layer, column, row](RuntimeObject* tileMapObject_, RuntimeObject * object) {
        RuntimeTileMapObject *tileMapObject = dynamic_cast<RuntimeTileMapObject*>(tileMapObject_);
        if(!tileMapObject || tileMapObject->tileSet.Get().IsDirty())
            return false;

        //Get the tile hitbox
        int tileId = tileMapObject->tileMap.Get().GetTile(layer, column, row);
        if(tileId < 0 || tileId >= tileMapObject->tileSet.Get().GetTilesCount())
            return false;

        Polygon2d tileHitbox = tileMapObject->tileSet.Get().GetTileHitbox(tileId).hitbox;
        tileHitbox.Move(tileMapObject->GetX() + column * tileMapObject->tileSet.Get().tileSize.x,
                        tileMapObject->GetY() + row * tileMapObject->tileSet.Get().tileSize.y);

        //Get the object hitbox
        std::vector<Polygon2d> objectHitboxes = object->GetHitBoxes();

        for(std::vector<Polygon2d>::iterator hitboxIt = objectHitboxes.begin(); hitboxIt != objectHitboxes.end(); ++hitboxIt)
        {
            if(PolygonCollisionTest(tileHitbox, *hitboxIt).collision)
            {
                return true;
            }
        }

        return false;
    });
}
Ejemplo n.º 2
0
std::vector<Polygon2d> GenerateHitboxes(TileSet &tileSet, TileMap &tileMap)
{
    std::vector<Polygon2d> hitboxes;
    const int tileWidth = tileSet.tileSize.x;
    const int tileHeight = tileSet.tileSize.y;

    if(tileSet.IsDirty())
        return hitboxes;

    for(int layer = 0; layer < 3; layer++)
    {
        for(int col = 0; col < tileMap.GetColumnsCount(); col++)
        {
            for(int row = 0; row < tileMap.GetRowsCount(); row++)
            {
                //Note : a hitbox is also added for empty/non-collidable tiles to ease the hitbox update when changing a tile
                Polygon2d newPolygon;

                if(tileMap.GetTile(layer, col, row) != -1 && tileSet.GetTileHitbox(tileMap.GetTile(layer, col, row)).collidable)
                {
                    newPolygon = tileSet.GetTileHitbox(tileMap.GetTile(layer, col, row)).hitbox;
                }

                newPolygon.Move(col * tileWidth, row * tileHeight);
                hitboxes.push_back(newPolygon);
            }
        }
    }

    return hitboxes;
}
Ejemplo n.º 3
0
std::vector<Polygon2d> RuntimeObject::GetHitBoxes() const {
  std::vector<Polygon2d> mask;
  Polygon2d rectangle = Polygon2d::CreateRectangle(GetWidth(), GetHeight());
  rectangle.Rotate(GetAngle() / 180 * 3.14159);
  rectangle.Move(GetX() + GetCenterX(), GetY() + GetCenterY());

  mask.push_back(rectangle);
  return mask;
}
Ejemplo n.º 4
0
bool TileMapImporter::ImportTileMap(TileSet &tileSet, TileMap &tileMap,
                                    bool importTileMap, bool importTileSetConf, bool importTileSetImage,
                                    bool importHitboxes, gd::Project &project)
{
    //Checks the map type
    if(m_map->GetOrientation() != Tmx::TMX_MO_ORTHOGONAL)
    {
        gd::LogError(_("Only orthogonal maps are supported !"));
        return false;
    }

    //Get the tileset list
    if(m_map->GetNumTilesets() < 1)
    {
        gd::LogError(_("There are no tilesets in this file !"));
        return false;
    }
    else if(m_map->GetNumTilesets() > 1)
    {
        gd::LogWarning(_("Only the first tileset will be taken into account. Tiles from supplementary tilesets may be lost."));
    }

    //Import the tileset image if needed
    if(importTileSetImage)
    {
        const Tmx::Image *importedImage = m_map->GetTileset(0)->GetImage();
        wxFileName imageFileName(importedImage->GetSource());
        imageFileName.MakeAbsolute(wxFileName(m_filePath).GetPath());

        if(!imageFileName.FileExists())
        {
            gd::LogError(_("The image can't be found !"));
            return false;
        }

        gd::String newResourceName = gd::NewNameGenerator::Generate(
                                         u8"imported_" + imageFileName.GetFullName(),
                                         [&project](const gd::String &name) -> bool { return project.GetResourcesManager().HasResource(name); }
                                     );

        gd::LogMessage(_("The image is imported as ") + "\"" + newResourceName + "\".");

        imageFileName.MakeRelativeTo(wxFileName(project.GetProjectFile()).GetPath());
        project.GetResourcesManager().AddResource(newResourceName, imageFileName.GetFullPath(), "image");

        tileSet.textureName = newResourceName;

        //Reload the texture
        tileSet.LoadResources(project);

        gd::LogStatus(_("Tileset image importation completed."));
    }

    //Import the tileset configuration if wanted
    if(importTileSetConf)
    {
        const Tmx::Tileset *importedTileset = m_map->GetTileset(0);

        if(importedTileset->GetImage()->GetWidth() != tileSet.GetWxBitmap().GetWidth() ||
                importedTileset->GetImage()->GetHeight() != tileSet.GetWxBitmap().GetHeight())
        {
            gd::LogWarning(_("Tileset image size is not the same. Some tiles may not be rendered correctly."));
        }

        tileSet.tileSize.x = importedTileset->GetTileWidth();
        tileSet.tileSize.y = importedTileset->GetTileHeight();
        tileSet.tileSpacing.x = tileSet.tileSpacing.y = importedTileset->GetSpacing();

        if(importedTileset->GetMargin() > 0)
        {
            gd::LogWarning(_("Tilemap objects don't handle tilesets with margins around the images. Consider cutting the picture."));
        }

        gd::LogStatus(_("Tileset configuration importation completed."));
    }

    //Import the tilemap tiles if wanted
    if(importTileMap)
    {
        //Tilemap size
        if(tileMap.GetColumnsCount() != m_map->GetWidth() || tileMap.GetRowsCount() != m_map->GetHeight())
            gd::LogMessage(_("Tilemap size is different."));
        tileMap.SetSize(0, 0);
        tileMap.SetSize(m_map->GetWidth(), m_map->GetHeight());

        if(!importTileSetConf && !importTileSetImage)
            CheckTilesCount(tileSet);

        //Import layers and tiles
        if(m_map->GetNumTileLayers() > 3)
        {
            gd::LogWarning(_("There are more than 3 tiles layers. Only the 3 firsts will be imported."));
        }
        else if(m_map->GetNumTileLayers() < 3)
        {
            gd::LogMessage(_("There are less than 3 tiles layers. Upper layer(s) will be empty."));
        }

        for(std::size_t i = 0; i < std::min(3, m_map->GetNumTileLayers()); i++)
        {
            const Tmx::TileLayer *layer = m_map->GetTileLayer(i);

            for(std::size_t x = 0; x < tileMap.GetColumnsCount(); x++)
            {
                for(std::size_t y = 0; y < tileMap.GetRowsCount(); y++)
                {
                    //Only tiles provided by the first tileset are imported (and also tests for empty tiles)
                    if(m_map->FindTilesetIndex(layer->GetTileGid(x, y)) == 0)
                    {
                        tileMap.SetTile(i, x, y, layer->GetTileId(x, y));
                    }
                }
            }
        }

        gd::LogStatus(_("Tilemap content importation completed."));
    }

    //Import the hitboxes
    if(importHitboxes)
    {
        const Tmx::Tileset *importedTileset = m_map->GetTileset(0);

        //Set all tiles not collidable in the tileset
        tileSet.ResetHitboxes();
        for(std::size_t i = 0; i < tileSet.GetTilesCount(); i++)
            tileSet.SetTileCollidable(i, false);

        if(!importTileSetConf && !importTileSetImage)
            CheckTilesCount(tileSet);

        bool hasMoreThanOneObjectPerTile = false;
        bool hasNotPolygoneObject = false;
        bool hasNotConvexPolygon = false;
        for(auto it = importedTileset->GetTiles().cbegin();
                it != importedTileset->GetTiles().cend();
                ++it)
        {
            const Tmx::Tile *importedTile = *it;

            if(importedTile->GetId() < tileSet.GetTilesCount()) //Check if the tileset has enough tiles to receive the imported hitboxes
            {
                if(importedTile->HasObjects())
                {
                    //Set the tile collidable and gets its hitbox
                    tileSet.SetTileCollidable(importedTile->GetId(), true);
                    TileHitbox &tileHitbox = tileSet.GetTileHitboxRef(importedTile->GetId());

                    //Warn the user if more than one hitbox per tile is found
                    if(importedTile->GetNumObjects() > 1)
                        hasMoreThanOneObjectPerTile = true;

                    const Tmx::Object *importedObj = importedTile->GetObject(0);
                    if(!importedObj->GetPolyline() && !importedObj->GetEllipse())
                    {
                        Polygon2d polygonHitbox;

                        if(!importedObj->GetPolygon())
                        {
                            //This is a rectangle
                            polygonHitbox = Polygon2d::CreateRectangle(importedObj->GetWidth(), importedObj->GetHeight());
                            polygonHitbox.Move(
                                importedObj->GetWidth() / 2.f,
                                importedObj->GetHeight() / 2.f
                            );
                        }
                        else
                        {
                            //This is a polygon
                            const Tmx::Polygon *importedPolygon = importedObj->GetPolygon();

                            for(int i = 0; i < importedPolygon->GetNumPoints(); i++)
                            {
                                polygonHitbox.vertices.emplace_back(
                                    importedPolygon->GetPoint(i).x,
                                    importedPolygon->GetPoint(i).y
                                );
                            }
                        }

                        polygonHitbox.Move(importedObj->GetX(), importedObj->GetY());
                        polygonHitbox.Rotate(importedObj->GetRot());

                        if(polygonHitbox.IsConvex())
                            tileHitbox.hitbox = polygonHitbox;
                        else
                            hasNotConvexPolygon = true;
                    }
                    else
                    {
                        //This is not a supported shape
                        hasNotPolygoneObject = true;
                    }
                }
            }
        }

        if(hasMoreThanOneObjectPerTile)
            gd::LogWarning(_("Some tiles have more than 1 hitbox. Only the first one is imported."));
        if(hasNotPolygoneObject)
            gd::LogWarning(_("Some tiles have a polyline or a ellipsis hitbox. Only rectangle and polygon hitboxes are supported."));
        if(hasNotConvexPolygon)
            gd::LogWarning(_("Some tiles have a concave polygon. It has been ignored and set to a rectangular hitbox as this object only supports convex hitboxes for tiles."));

        gd::LogStatus(_("Tiles hitboxes importation completed."));
    }

    return true;
}