Merge branch 'master' of github.com:4ian/GD

This commit is contained in:
Florian Rival
2015-08-31 22:41:59 +02:00
12 changed files with 364 additions and 292 deletions

File diff suppressed because one or more lines are too long

View File

@@ -164,7 +164,7 @@ void DeclareTileMapObjectExtension(gd::PlatformExtension & extension)
obj.AddAction("ChangeTexture",
_("Change the tileset texture"),
_("Change the tileset texture."),
_("Change the tileset texture.\nNote: if the texture has a different size, it may produce strange results such as texture offset..."),
_("Change the tileset texture of _PARAM0_ to _PARAM1_"),
_("Tileset"),
"CppPlatform/Extensions/TileMapIcon24.png",

View File

@@ -43,7 +43,6 @@ RuntimeTileMapObject::RuntimeTileMapObject(RuntimeScene & scene, const gd::Objec
//Load the tileset and generate the vertex array
tileSet.Get().LoadResources(*(scene.game));
tileSet.Get().Generate(); //We don't need wxBitmaps
vertexArray = TileMapExtension::GenerateVertexArray(tileSet.Get(), tileMap.Get());
hitboxes = TileMapExtension::GenerateHitboxes(tileSet.Get(), tileMap.Get());
}
@@ -214,7 +213,6 @@ void RuntimeTileMapObject::ChangeTexture(const gd::String &textureName, RuntimeS
{
tileSet.Get().textureName = textureName;
tileSet.Get().LoadResources(*(scene.game));
tileSet.Get().Generate();
needGeneration = true;
}

View File

@@ -62,8 +62,9 @@ void TileEditor::OnTileSetSelectionChanged(TileSelectionEvent &event)
if(!m_tileset || m_tileset->IsDirty())
return;
//Update the editor with the new tile
m_currentTile = event.GetSelectedTile();
m_mainToolbar->ToggleTool(COLLIDABLE_TOOL_ID, m_tileset->GetTileHitbox(m_currentTile).collidable);
m_mainToolbar->ToggleTool(COLLIDABLE_TOOL_ID, m_tileset->IsTileCollidable(m_currentTile));
UpdateScrollbars();
m_tilePreviewPanel->Refresh();
@@ -150,7 +151,7 @@ void TileEditor::OnPreviewPaint(wxPaintEvent& event)
void TileEditor::OnCollidableToolToggled(wxCommandEvent& event)
{
m_tileset->GetTileHitbox(m_currentTile).collidable = event.IsChecked();
m_tileset->SetTileCollidable(m_currentTile, event.IsChecked());
}
void TileEditor::OnPredefinedShapeToolClicked(wxCommandEvent& event)
@@ -167,33 +168,33 @@ void TileEditor::OnPredefinedShapeMenuItemClicked(wxCommandEvent& event)
switch(event.GetId())
{
case RECTANGLE_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Rectangle(m_tileset->tileSize);
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Rectangle(m_tileset->tileSize);
break;
case TRIANGLE_TL_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Triangle(m_tileset->tileSize, TileHitbox::TopLeft);
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Triangle(m_tileset->tileSize, TileHitbox::TopLeft);
break;
case TRIANGLE_TR_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Triangle(m_tileset->tileSize, TileHitbox::TopRight);
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Triangle(m_tileset->tileSize, TileHitbox::TopRight);
break;
case TRIANGLE_BR_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Triangle(m_tileset->tileSize, TileHitbox::BottomRight);
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Triangle(m_tileset->tileSize, TileHitbox::BottomRight);
break;
case TRIANGLE_BL_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Triangle(m_tileset->tileSize, TileHitbox::BottomLeft);
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Triangle(m_tileset->tileSize, TileHitbox::BottomLeft);
break;
case SEMIRECT_T_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Rectangle(sf::Vector2f(m_tileset->tileSize.x, m_tileset->tileSize.y/2.f));
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Rectangle(sf::Vector2f(m_tileset->tileSize.x, m_tileset->tileSize.y/2.f));
break;
case SEMIRECT_R_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Rectangle(sf::Vector2f(m_tileset->tileSize.x/2.f, m_tileset->tileSize.y));
m_tileset->GetTileHitbox(m_currentTile).hitbox.Move(m_tileset->tileSize.x/2.f, 0);
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Rectangle(sf::Vector2f(m_tileset->tileSize.x/2.f, m_tileset->tileSize.y));
m_tileset->GetTileHitboxRef(m_currentTile).hitbox.Move(m_tileset->tileSize.x/2.f, 0);
break;
case SEMIRECT_B_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Rectangle(sf::Vector2f(m_tileset->tileSize.x, m_tileset->tileSize.y/2.f));
m_tileset->GetTileHitbox(m_currentTile).hitbox.Move(0, m_tileset->tileSize.y/2.f);
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Rectangle(sf::Vector2f(m_tileset->tileSize.x, m_tileset->tileSize.y/2.f));
m_tileset->GetTileHitboxRef(m_currentTile).hitbox.Move(0, m_tileset->tileSize.y/2.f);
break;
case SEMIRECT_L_SHAPE_TOOL_ID:
m_tileset->GetTileHitbox(m_currentTile) = TileHitbox::Rectangle(sf::Vector2f(m_tileset->tileSize.x/2.f, m_tileset->tileSize.y));
m_tileset->GetTileHitboxRef(m_currentTile) = TileHitbox::Rectangle(sf::Vector2f(m_tileset->tileSize.x/2.f, m_tileset->tileSize.y));
break;
}
@@ -207,7 +208,7 @@ void TileEditor::OnAddPointToolClicked(wxCommandEvent& event)
if(!m_tileset || m_tileset->IsDirty())
return;
Polygon2d &mask = m_tileset->GetTileHitbox(m_currentTile).hitbox;
Polygon2d &mask = m_tileset->GetTileHitboxRef(m_currentTile).hitbox;
int selectedPoint = m_polygonHelper.GetSelectedPoint();
if(selectedPoint >= mask.vertices.size() || selectedPoint < 0)
@@ -234,7 +235,7 @@ void TileEditor::OnEditPointToolClicked(wxCommandEvent& event)
if(!m_tileset || m_tileset->IsDirty())
return;
Polygon2d &mask = m_tileset->GetTileHitbox(m_currentTile).hitbox;
Polygon2d &mask = m_tileset->GetTileHitboxRef(m_currentTile).hitbox;
int selectedPoint = m_polygonHelper.GetSelectedPoint();
if(selectedPoint >= mask.vertices.size() || selectedPoint < 0)
return;
@@ -253,7 +254,7 @@ void TileEditor::OnRemovePointToolClicked(wxCommandEvent& event)
if(!m_tileset || m_tileset->IsDirty())
return;
Polygon2d &mask = m_tileset->GetTileHitbox(m_currentTile).hitbox;
Polygon2d &mask = m_tileset->GetTileHitboxRef(m_currentTile).hitbox;
if(mask.vertices.size() <= 3)
return;
@@ -274,9 +275,9 @@ void TileEditor::OnPreviewLeftDown(wxMouseEvent& event)
event.SetX(m_tilePreviewPanel->CalcUnscrolledPosition(wxPoint(event.GetX(), event.GetY())).x);
event.SetY(m_tilePreviewPanel->CalcUnscrolledPosition(wxPoint(event.GetX(), event.GetY())).y);
std::vector<Polygon2d> polygonList(1, m_tileset->GetTileHitbox(m_currentTile).hitbox);
std::vector<Polygon2d> polygonList(1, m_tileset->GetTileHitboxRef(m_currentTile).hitbox);
m_polygonHelper.OnMouseLeftDown(polygonList, event, wxPoint(m_xOffset, m_yOffset));
m_tileset->GetTileHitbox(m_currentTile).hitbox = polygonList[0];
m_tileset->GetTileHitboxRef(m_currentTile).hitbox = polygonList[0];
m_tilePreviewPanel->Refresh();
}
@@ -299,9 +300,9 @@ void TileEditor::OnPreviewMotion(wxMouseEvent& event)
event.SetX(m_tilePreviewPanel->CalcUnscrolledPosition(wxPoint(event.GetX(), event.GetY())).x);
event.SetY(m_tilePreviewPanel->CalcUnscrolledPosition(wxPoint(event.GetX(), event.GetY())).y);
std::vector<Polygon2d> polygonList(1, m_tileset->GetTileHitbox(m_currentTile).hitbox);
std::vector<Polygon2d> polygonList(1, m_tileset->GetTileHitboxRef(m_currentTile).hitbox);
m_polygonHelper.OnMouseMove(polygonList, event, wxPoint(m_xOffset, m_yOffset), 0.f, 0.f, m_tileset->tileSize.x, m_tileset->tileSize.y);
m_tileset->GetTileHitbox(m_currentTile).hitbox = polygonList[0];
m_tileset->GetTileHitboxRef(m_currentTile).hitbox = polygonList[0];
m_tilePreviewPanel->Refresh();
}

View File

@@ -90,7 +90,6 @@ void TileMapObject::DoSerializeTo(gd::SerializerElement & element) const
void TileMapObject::LoadResources(gd::Project & project, gd::Layout & layout)
{
tileSet.Get().LoadResources(project);
tileSet.Get().Generate();
vertexArray = TileMapExtension::GenerateVertexArray(tileSet.Get(), tileMap.Get());
}
@@ -156,4 +155,3 @@ gd::Object * CreateTileMapObject(gd::String name)
{
return new TileMapObject(name);
}

View File

@@ -125,6 +125,8 @@ void TileMapObjectEditor::OnCancelButtonPressed(wxCommandEvent& event)
void TileMapObjectEditor::OnOkButtonPressed(wxCommandEvent& event)
{
tileSet.StripUselessHitboxes();
object.tileSet = TileSetProxy(tileSet);
object.tileMap = TileMapProxy(tileMap);
@@ -139,7 +141,6 @@ void TileMapObjectEditor::OnTileSetConfigureButtonClicked(wxCommandEvent& event)
dialog.ShowModal();
tileSet.LoadResources(game);
tileSet.Generate();
if(oldTextureName != tileSet.textureName)
{

View File

@@ -87,7 +87,7 @@ std::vector<Polygon2d> GenerateHitboxes(TileSet &tileSet, TileMap &tileMap)
//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)
if(tileMap.GetTile(layer, col, row) != -1 && tileSet.IsTileCollidable(tileMap.GetTile(layer, col, row)))
{
newPolygon = tileSet.GetTileHitbox(tileMap.GetTile(layer, col, row)).hitbox;
}
@@ -136,7 +136,7 @@ void UpdateHitboxes(std::vector<Polygon2d> &polygons, sf::Vector2f position, int
const int tileWidth = tileSet.tileSize.x;
const int tileHeight = tileSet.tileSize.y;
if(tileMap.GetTile(layer, col, row) != -1 && tileSet.GetTileHitbox(tileMap.GetTile(layer, col, row)).collidable)
if(tileMap.GetTile(layer, col, row) != -1 && tileSet.IsTileCollidable(tileMap.GetTile(layer, col, row)))
{
polygons[vertexPos] = tileSet.GetTileHitbox(tileMap.GetTile(layer, col, row)).hitbox;
}

View File

@@ -22,10 +22,30 @@ This project is released under the MIT License.
wxBitmap TileSet::m_invalidBitmap = wxBitmap();
#endif
bool TileHitbox::operator==(const TileHitbox &other) const
{
if(hitbox.vertices.size() == other.hitbox.vertices.size())
{
for(unsigned int i = 0; i < hitbox.vertices.size(); ++i)
{
if( fabs( hitbox.vertices[i].x - other.hitbox.vertices[i].x ) > 0.01f ||
fabs( hitbox.vertices[i].y - other.hitbox.vertices[i].y ) > 0.01f )
return false;
}
return true;
}
else
return false;
}
bool TileHitbox::operator!=(const TileHitbox &other) const
{
return !(operator==(other));
}
TileHitbox TileHitbox::Rectangle(sf::Vector2f tileSize)
{
TileHitbox hitbox;
hitbox.collidable = true;
hitbox.hitbox = Polygon2d::CreateRectangle(tileSize.x, tileSize.y);
hitbox.hitbox.Move(tileSize.x/2.f, tileSize.y/2.f);
@@ -35,7 +55,6 @@ TileHitbox TileHitbox::Rectangle(sf::Vector2f tileSize)
TileHitbox TileHitbox::Triangle(sf::Vector2f tileSize, TriangleOrientation orientation)
{
TileHitbox hitbox;
hitbox.collidable = true;
if(orientation != TileHitbox::BottomRight)
hitbox.hitbox.vertices.push_back(sf::Vector2f(0,0));
@@ -54,8 +73,6 @@ TileHitbox TileHitbox::Triangle(sf::Vector2f tileSize, TriangleOrientation orien
void TileHitbox::SerializeTo(gd::SerializerElement &element) const
{
element.SetAttribute("collidable", collidable);
//Serialize the polygon
gd::String polygonStr;
for(std::vector<sf::Vector2f>::const_iterator vertexIt = hitbox.vertices.begin(); vertexIt != hitbox.vertices.end(); vertexIt++)
@@ -70,8 +87,6 @@ void TileHitbox::SerializeTo(gd::SerializerElement &element) const
void TileHitbox::UnserializeFrom(const gd::SerializerElement &element, sf::Vector2f defaultTileSize)
{
collidable = element.GetBoolAttribute("collidable", true);
hitbox.vertices.clear();
gd::String defaultPolygonStr = "0;0|"
@@ -89,7 +104,7 @@ void TileHitbox::UnserializeFrom(const gd::SerializerElement &element, sf::Vecto
}
}
TileSet::TileSet() : textureName(), tileSize(24, 24), tileSpacing(0, 0), m_tilesetTexture(), m_dirty(true)
TileSet::TileSet() : textureName(), tileSize(24, 24), tileSpacing(0, 0), m_tilesetTexture()
{
}
@@ -101,14 +116,11 @@ TileSet::~TileSet()
void TileSet::LoadResources(RuntimeGame &game)
{
m_dirty = true;
m_tilesetTexture = game.GetImageManager()->GetSFMLTexture(textureName);
}
void TileSet::LoadResources(gd::Project &game)
{
m_dirty = true;
if(game.GetResourcesManager().HasResource(textureName))
{
gd::ImageResource & image = dynamic_cast<gd::ImageResource&>(game.GetResourcesManager().GetResource(textureName));
@@ -125,10 +137,12 @@ void TileSet::LoadResources(gd::Project &game)
wxSetWorkingDirectory(oldWorkingDir);
if ( wxFileExists(image.GetAbsoluteFile(game)) )
{
wxBitmap bmp( image.GetAbsoluteFile(game), wxBITMAP_TYPE_ANY);
m_tilesetBitmap = bmp;
m_tilesetBitmap.LoadFile(image.GetAbsoluteFile(game), wxBITMAP_TYPE_ANY);
}
#endif
//Readjust the m_collidable std::vector according to the number of tiles
m_collidable.resize(GetTilesCount(), true);
}
else
{
@@ -136,60 +150,18 @@ void TileSet::LoadResources(gd::Project &game)
}
}
void TileSet::Generate()
{
m_dirty = true;
if (!m_tilesetTexture)
return;
std::cout << "Generating texture coords..." << std::endl;
//Calculates the number of rows and columns in the tileset
int columns(0), rows(0);
if (tileSize.x == 0 || tileSize.y == 0)
return;
columns = (m_tilesetTexture->texture.getSize().x + tileSpacing.x) / (tileSize.x + tileSpacing.x);
rows = (m_tilesetTexture->texture.getSize().y + tileSpacing.y) / (tileSize.y + tileSpacing.y);
//Generate the TextureCoords and the sub-bitmaps (only in IDE)
m_coords.clear();
for(int row = 0; row < rows; row++)
{
for(int col = 0; col < columns; col++)
{
//TileTextureCoords
TileTextureCoords tileCoords;
tileCoords.topLeft = sf::Vector2f(col * (tileSize.x + tileSpacing.x),
row * (tileSize.y + tileSpacing.y));
tileCoords.topRight = sf::Vector2f(col * (tileSize.x + tileSpacing.x) + tileSize.x,
row * (tileSize.y + tileSpacing.y));
tileCoords.bottomRight = sf::Vector2f(col * (tileSize.x + tileSpacing.x) + tileSize.x,
row * (tileSize.y + tileSpacing.y) + tileSize.y);
tileCoords.bottomLeft = sf::Vector2f(col * (tileSize.x + tileSpacing.x),
row * (tileSize.y + tileSpacing.y) + tileSize.y);
m_coords.push_back(tileCoords);
}
}
//Puts the default hitbox for new tiles (if there are more tiles than before)
if (GetTilesCount() > m_hitboxes.size())
m_hitboxes.insert(m_hitboxes.end(), (GetTilesCount()-m_hitboxes.size()), TileHitbox::Rectangle(tileSize));
std::cout << "OK" << std::endl;
m_dirty = false;
}
void TileSet::ResetHitboxes()
{
m_collidable.clear();
m_hitboxes.clear();
if (m_dirty)
if (IsDirty())
return;
m_hitboxes.assign(GetTilesCount(), TileHitbox::Rectangle(tileSize));
m_collidable.assign(GetTilesCount(), true);
}
int TileSet::GetTileIDFromPosition(sf::Vector2f position)
int TileSet::GetTileIDFromPosition(sf::Vector2f position) const
{
int columns = GetColumnsCount();
int rows = GetRowsCount();
@@ -200,7 +172,7 @@ int TileSet::GetTileIDFromPosition(sf::Vector2f position)
return (tileColumn * columns + tileRow);
}
int TileSet::GetTileIDFromCell(int col, int row)
int TileSet::GetTileIDFromCell(int col, int row) const
{
int columns = GetColumnsCount();
int rows = GetRowsCount();
@@ -208,6 +180,13 @@ int TileSet::GetTileIDFromCell(int col, int row)
return (row * columns + col);
}
sf::Vector2u TileSet::GetTileCellFromID(int id) const
{
int columns = GetColumnsCount();
int rows = GetRowsCount();
return sf::Vector2u(id - (id / columns) * columns, id / columns);
}
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
const wxBitmap& TileSet::GetWxBitmap() const
{
@@ -227,7 +206,19 @@ const sf::Texture& TileSet::GetTexture() const
TileTextureCoords TileSet::GetTileTextureCoords(int id) const
{
return m_coords.at(id);
//Calculate the tile coords
sf::Vector2u cell = GetTileCellFromID(id);
TileTextureCoords tileCoords;
tileCoords.topLeft = sf::Vector2f(cell.x * (tileSize.x + tileSpacing.x),
cell.y * (tileSize.y + tileSpacing.y));
tileCoords.topRight = sf::Vector2f(cell.x * (tileSize.x + tileSpacing.x) + tileSize.x,
cell.y * (tileSize.y + tileSpacing.y));
tileCoords.bottomRight = sf::Vector2f(cell.x * (tileSize.x + tileSpacing.x) + tileSize.x,
cell.y * (tileSize.y + tileSpacing.y) + tileSize.y);
tileCoords.bottomLeft = sf::Vector2f(cell.x * (tileSize.x + tileSpacing.x),
cell.y * (tileSize.y + tileSpacing.y) + tileSize.y);
return tileCoords;
}
sf::Vector2u TileSet::GetSize() const
@@ -238,14 +229,43 @@ sf::Vector2u TileSet::GetSize() const
return m_tilesetTexture->texture.getSize();
}
TileHitbox& TileSet::GetTileHitbox(int id)
bool TileSet::IsTileCollidable(int id) const
{
return m_collidable[id];
}
void TileSet::SetTileCollidable(int id, bool collidable)
{
m_collidable[id] = collidable;
}
#if defined(GD_IDE_ONLY)
void TileSet::StripUselessHitboxes()
{
auto it = m_hitboxes.begin();
while(it != m_hitboxes.end())
{
if( (it->second) == TileHitbox::Rectangle(tileSize) ) //This is an useless hitbox, remove it.
it = m_hitboxes.erase(it);
else
++it;
}
}
#endif
TileHitbox& TileSet::GetTileHitboxRef(int id)
{
if(m_hitboxes.count(id) == 0)
m_hitboxes[id] = TileHitbox::Rectangle(tileSize);
return m_hitboxes[id];
}
const TileHitbox& TileSet::GetTileHitbox(int id) const
TileHitbox TileSet::GetTileHitbox(int id) const
{
return m_hitboxes.at(id);
if(m_hitboxes.count(id) == 0)
return TileHitbox::Rectangle(tileSize);
else
return m_hitboxes.at(id);
}
int TileSet::GetColumnsCount() const
@@ -261,26 +281,35 @@ int TileSet::GetRowsCount() const
#if defined(GD_IDE_ONLY)
void TileSet::SerializeTo(gd::SerializerElement &element) const
{
element.SetAttribute("version", 2);
element.SetAttribute("textureName", textureName);
element.SetAttribute("tileSizeX", tileSize.x);
element.SetAttribute("tileSizeY", tileSize.y);
element.SetAttribute("tileSpacingX", tileSpacing.x);
element.SetAttribute("tileSpacingY", tileSpacing.y);
gd::SerializerElement &tilesElem = element.AddChild("hitboxes");
//Save if it is collidable or not
gd::SerializerElement &collidableElem = element.AddChild("collidable");
for(auto it = m_collidable.begin(); it != m_collidable.end(); ++it)
{
gd::SerializerElement &tileElem = collidableElem.AddChild("tile");
tileElem.SetAttribute("collidable", *it);
}
//Save polygons
for(std::vector<TileHitbox>::const_iterator it = m_hitboxes.begin(); it != m_hitboxes.end(); it++)
//Save polygons hitboxes
gd::SerializerElement &tilesElem = element.AddChild("hitboxes");
for(auto it = m_hitboxes.begin(); it != m_hitboxes.end(); ++it)
{
gd::SerializerElement &hitboxElem = tilesElem.AddChild("tileHitbox");
it->SerializeTo(hitboxElem);
hitboxElem.SetAttribute("tileId", it->first);
it->second.SerializeTo(hitboxElem);
}
}
#endif
void TileSet::UnserializeFrom(const gd::SerializerElement &element)
{
ResetHitboxes();
int serializationVersion = element.GetIntAttribute("version", 1);
textureName = element.GetStringAttribute("textureName", "");
tileSize.x = element.GetIntAttribute("tileSizeX", 32);
@@ -288,17 +317,39 @@ void TileSet::UnserializeFrom(const gd::SerializerElement &element)
tileSpacing.x = element.GetIntAttribute("tileSpacingX", 0);
tileSpacing.y = element.GetIntAttribute("tileSpacingY", 0);
if (element.HasChild("hitboxes"))
ResetHitboxes();
m_collidable.clear();
if(serializationVersion == 1)
{
gd::SerializerElement &tilesElem = element.GetChild("hitboxes");
tilesElem.ConsiderAsArrayOf("tileHitbox");
for(int i = 0; i < tilesElem.GetChildrenCount("tileHitbox"); i++)
if(element.HasChild("hitboxes"))
{
TileHitbox newHitbox;
newHitbox.UnserializeFrom(tilesElem.GetChild(i), tileSize);
m_hitboxes.push_back(newHitbox);
gd::SerializerElement &tilesElem = element.GetChild("hitboxes");
tilesElem.ConsiderAsArrayOf("tileHitbox");
for(int i = 0; i < tilesElem.GetChildrenCount("tileHitbox"); i++)
{
m_collidable.push_back(tilesElem.GetChild(i).GetBoolAttribute("collidable", true));
TileHitbox newHitbox;
newHitbox.UnserializeFrom(tilesElem.GetChild(i), tileSize);
if(newHitbox != TileHitbox::Rectangle(tileSize))
m_hitboxes[i] = newHitbox;
}
}
}
else if(serializationVersion == 2)
{
gd::SerializerElement &collidableElem = element.GetChild("collidable");
collidableElem.ConsiderAsArrayOf("tile");
for(int i = 0; i < collidableElem.GetChildrenCount("tile"); i++)
{
m_collidable.push_back(collidableElem.GetChild(i).GetBoolAttribute("collidable", true));
}
m_dirty = true;
gd::SerializerElement &hitboxesElem = element.GetChild("hitboxes");
hitboxesElem.ConsiderAsArrayOf("tileHitbox");
for(int i = 0; i < hitboxesElem.GetChildrenCount("tileHitbox"); i++)
{
m_hitboxes[hitboxesElem.GetChild(i).GetIntAttribute("tileId", -1)].UnserializeFrom(hitboxesElem.GetChild(i), tileSize);
}
}
}

View File

@@ -12,6 +12,7 @@ This project is released under the MIT License.
#include <wx/bitmap.h>
#endif
#include <map>
#include <string>
#include <vector>
#include <SFML/System/Vector2.hpp>
@@ -47,9 +48,11 @@ struct TileHitbox
BottomLeft ///< In the bottom-left hand corner
};
bool collidable; ///< True to make the tile collidable
Polygon2d hitbox; ///< The polygonal hitbox
bool operator==(const TileHitbox &other) const;
bool operator!=(const TileHitbox &other) const;
/**
* Generates a default hitbox (rectangle of the size of the tile).
*/
@@ -98,11 +101,10 @@ public:
*/
///\{
/**
* Returns true if the tileset hasn't been loaded and generated from a picture.
* \warning Can return true even if the loaded texture doesn't correspond to the TileSet::textureName or
* if the TileSet::tileSize or TileSet::tileSpacing have been modified as the object is not in a invalid state.
* Returns true if the tileset hasn't been loaded (texture not loaded) or have an invalid tile size.
* \warning Can return true even if the loaded texture doesn't correspond to the TileSet::textureName
*/
bool IsDirty() const {return m_dirty;};
bool IsDirty() const {return (!m_tilesetTexture || tileSize.x == 0.f || tileSize.y == 0.f);}
/**
* Load the image for the tilemap. Need to be called when using the TileSet for the first or after a texture change.
@@ -117,13 +119,6 @@ public:
* in the scene preview or in a release game.
*/
void LoadResources(RuntimeGame &game);
/**
* Generate the tile texture coords and temporary bitmaps for the IDE.
* Need to be called after a change in TileSet::textureName (in that case after TileSet::LoadResources) or after a change in the TileSet::tileSize or TileSet::tileSpacing.
* \sa TileSet::LoadResources
*/
void Generate();
///\}
/**
@@ -167,15 +162,29 @@ public:
*/
void ResetHitboxes();
bool IsTileCollidable(int id) const;
void SetTileCollidable(int id, bool collidable);
/**
* \return the hitbox of a tile.
* \return a reference to the hitbox of a tile.
* Allows the edition of the hitbox.
*/
TileHitbox& GetTileHitbox(int id);
TileHitbox& GetTileHitboxRef(int id);
/**
* \return the hitbox of a tile.
*/
const TileHitbox& GetTileHitbox(int id) const;
TileHitbox GetTileHitbox(int id) const;
#if defined(GD_IDE_ONLY)
/**
* \brief Strips useless hitboxes (the default rectangle hitbox) from the hitboxes data of the tileset.
* The tileset keeps only non-default hitboxes in memory (the default hitbox for tiles is a rectangle with the same size as tiles).
* This method checks if the tileset stores default hitbox and remove them as they are useless.
*/
void StripUselessHitboxes();
#endif
///\}
/**
@@ -185,12 +194,17 @@ public:
/**
* Return the tile ID according to its position.
*/
int GetTileIDFromPosition(sf::Vector2f position);
int GetTileIDFromPosition(sf::Vector2f position) const;
/**
* Return the tile ID according to its row and column.
*/
int GetTileIDFromCell(int col, int row);
int GetTileIDFromCell(int col, int row) const;
/**
* Return the tile cell (col, row) from its ID.
*/
sf::Vector2u GetTileCellFromID(int id) const;
/**
* \return the number of tiles of the tileset.
@@ -230,17 +244,15 @@ public:
private:
std::shared_ptr<SFMLTextureWrapper> m_tilesetTexture; ///< The tileset texture (SFML)
std::vector<TileTextureCoords> m_coords; ///< The tileset coords
std::vector<TileHitbox> m_hitboxes;
std::vector<bool> m_collidable;
std::map<int, TileHitbox> m_hitboxes;
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
wxBitmap m_tilesetBitmap; ///< The tileset texture
static wxBitmap m_invalidBitmap;
#endif
bool m_dirty;
};
#endif

View File

@@ -58,17 +58,24 @@ TileSetConfigurationEditor::~TileSetConfigurationEditor()
}
void TileSetConfigurationEditor::UpdatePreviewTileSetPanel()
void TileSetConfigurationEditor::UpdatePreviewTileSetPanel(bool newTexture)
{
previewTileSet.textureName = m_textureNameTextCtrl->GetValue();
std::cout << "Reloading texture..." << std::endl;
previewTileSet.LoadResources(game);
std::cout << "OK." << std::endl;
if(newTexture)
{
//If the texture has changed, put default values for tile size/spacing
m_tileWidthSpin->SetValue(std::max(1.f, static_cast<float>(previewTileSet.GetSize().x)/10.f));
m_tileHeightSpin->SetValue(std::max(1.f, static_cast<float>(previewTileSet.GetSize().y)/10.f));
}
previewTileSet.tileSize.x = m_tileWidthSpin->GetValue();
previewTileSet.tileSize.y = m_tileHeightSpin->GetValue();
previewTileSet.tileSpacing.x = m_spacingWidthSpin->GetValue();
previewTileSet.tileSpacing.y = m_spacingHeightSpin->GetValue();
previewTileSet.LoadResources(game);
previewTileSet.Generate();
if(previewTileSet.GetSize().x >= 1 && previewTileSet.GetSize().y >= 1)
{
m_tileWidthSpin->SetRange(1, previewTileSet.GetSize().x);
@@ -113,7 +120,7 @@ void TileSetConfigurationEditor::OnOkButtonClicked(wxCommandEvent& event)
void TileSetConfigurationEditor::OnTileSetTextureUpdated(wxCommandEvent& event)
{
UpdatePreviewTileSetPanel();
UpdatePreviewTileSetPanel(true);
}
void TileSetConfigurationEditor::OnTileSetParameterUpdated(wxSpinEvent& event)

View File

@@ -28,7 +28,7 @@ private:
TileSet previewTileSet;
ResourcesEditor *resourcesEditorPnl;
void UpdatePreviewTileSetPanel();
void UpdatePreviewTileSetPanel(bool newTexture = false);
protected:
virtual void OnHelpButtonClicked(wxHyperlinkEvent& event);

View File

@@ -66,8 +66,8 @@ void TileSetPanel::OnPaint(wxPaintEvent& event)
if(m_tileset && !m_tileset->IsDirty())
{
//Determine the first and last columns and rows to draw
int firstCol = std::max((int)(minPos.x / (m_tileset->tileSize.x + m_tileset->tileSpacing.x) - 1), 0);
int firstRow = std::max((int)(minPos.y / (m_tileset->tileSize.y + m_tileset->tileSpacing.y) - 1), 0);
int firstCol = std::max((int)(minPos.x / (m_tileset->tileSize.x + m_tileset->tileSpacing.x) - 1), 1);
int firstRow = std::max((int)(minPos.y / (m_tileset->tileSize.y + m_tileset->tileSpacing.y) - 1), 1);
int lastCol = std::min((int)(maxPos.x / (m_tileset->tileSize.x + m_tileset->tileSpacing.x) + 1), m_tileset->GetColumnsCount());
int lastRow = std::min((int)(maxPos.y / (m_tileset->tileSize.y + m_tileset->tileSpacing.y) + 1), m_tileset->GetRowsCount());