You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
9.8 KiB
381 lines
9.8 KiB
#pragma once
|
|
#include "olcPixelGameEngine.h"
|
|
|
|
#include <algorithm>
|
|
#undef min
|
|
#undef max
|
|
|
|
namespace olc
|
|
{
|
|
|
|
class TILE : public olc::PGEX
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
struct Edge
|
|
{
|
|
float sx, sy;
|
|
float ex, ey;
|
|
};
|
|
|
|
public:
|
|
class Atlas
|
|
{
|
|
public:
|
|
Atlas();
|
|
void Create(olc::Sprite *tileSheet);
|
|
olc::rcode LoadFromFile(std::string filename);
|
|
olc::rcode SaveToFile(std::string filename);
|
|
|
|
public:
|
|
olc::Sprite *sprTileSheet;
|
|
std::vector<std::tuple<int32_t, int32_t, int32_t, int32_t>> location;
|
|
};
|
|
|
|
public:
|
|
|
|
template <class T>
|
|
class Layer
|
|
{
|
|
public:
|
|
Layer();
|
|
void Create(int32_t w, int32_t h, int32_t tw, int32_t th);
|
|
olc::rcode LoadFromFile(std::string filename);
|
|
olc::rcode SaveToFile(std::string filename);
|
|
T* GetTile(int32_t x, int32_t y);
|
|
|
|
public:
|
|
int32_t nLayerWidth;
|
|
int32_t nLayerHeight;
|
|
int32_t nTileWidth;
|
|
int32_t nTileHeight;
|
|
|
|
private:
|
|
T *pTiles;
|
|
|
|
};
|
|
|
|
class BasicTile
|
|
{
|
|
public:
|
|
BasicTile();
|
|
|
|
public:
|
|
int32_t id;
|
|
bool exist;
|
|
|
|
int edge_id[4];
|
|
bool edge_exist[4];
|
|
};
|
|
|
|
public:
|
|
template<typename T>
|
|
static void DrawLayer(olc::TILE::Layer<T> &layer, olc::TILE::Atlas &atlas, float cam_x, float cam_y, int tiles_x, int tiles_y, int nScale = 1);
|
|
|
|
template<typename T>
|
|
static olc::Pixel GetLayerPixel(olc::TILE::Layer<T> &layer, olc::TILE::Atlas &atlas, float x, float y);
|
|
|
|
template<typename T>
|
|
static std::vector<olc::TILE::Edge> ExtractEdgesFromLayer(olc::TILE::Layer<T> &layer, int sx, int sy, int width, int height);
|
|
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace olc
|
|
{
|
|
TILE::BasicTile::BasicTile()
|
|
{
|
|
exist = false;
|
|
id = 0;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
edge_exist[i] = false;
|
|
edge_id[i] = 0;
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
TILE::Layer<T>::Layer()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
void TILE::Layer<T>::Create(int32_t w, int32_t h, int32_t tw, int32_t th)
|
|
{
|
|
nLayerWidth = w;
|
|
nLayerHeight = h;
|
|
nTileWidth = tw;
|
|
nTileHeight = th;
|
|
|
|
pTiles = new T[nLayerWidth * nLayerHeight];
|
|
for (int i = 0; i < nLayerWidth*nLayerHeight; i++)
|
|
{
|
|
pTiles[i].id = 0;
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
olc::rcode TILE::Layer<T>::LoadFromFile(std::string filename)
|
|
{
|
|
return olc::FAIL;
|
|
}
|
|
|
|
template <class T>
|
|
olc::rcode TILE::Layer<T>::SaveToFile(std::string filename)
|
|
{
|
|
return olc::FAIL;
|
|
}
|
|
|
|
template <class T>
|
|
T* TILE::Layer<T>::GetTile(int32_t x, int32_t y)
|
|
{
|
|
if (x < 0 || x >= nLayerWidth || y < 0 || y >= nLayerHeight)
|
|
return nullptr;
|
|
else
|
|
return &pTiles[y*nLayerWidth + x];
|
|
}
|
|
|
|
template<typename T>
|
|
void TILE::DrawLayer(olc::TILE::Layer<T> &layer, olc::TILE::Atlas &atlas, float cam_x, float cam_y, int32_t tiles_x, int32_t tiles_y, int nScale)
|
|
{
|
|
float fOffsetX = cam_x - (int)cam_x;
|
|
float fOffsetY = cam_y - (int)cam_y;
|
|
|
|
for (int32_t x = 0; x < tiles_x; x++)
|
|
{
|
|
for (int32_t y = 0; y < tiles_y; y++)
|
|
{
|
|
olc::TILE::BasicTile *t = layer.GetTile(x + (int)cam_x, y + (int)cam_y);
|
|
if (t != nullptr && t->exist)
|
|
{
|
|
float fx = (int)(((float)x - fOffsetX) * (float)(layer.nTileWidth));
|
|
float fy = (int)(((float)y - fOffsetY) * (float)(layer.nTileHeight));
|
|
|
|
pge->DrawPartialSprite(
|
|
fx + 0.5f - (fx < 0.0f),
|
|
fy + 0.5f - (fy < 0.0f),
|
|
atlas.sprTileSheet,
|
|
std::get<0>(atlas.location[t->id]),
|
|
std::get<1>(atlas.location[t->id]),
|
|
std::get<2>(atlas.location[t->id]),
|
|
std::get<3>(atlas.location[t->id]),
|
|
nScale);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
olc::Pixel TILE::GetLayerPixel(olc::TILE::Layer<T> &layer, olc::TILE::Atlas &atlas, float x, float y)
|
|
{
|
|
olc::TILE::BasicTile *t = layer.GetTile((int32_t)x, (int32_t)y);
|
|
if (t != nullptr)
|
|
{
|
|
float fOffsetX = x - (int)x;
|
|
float fOffsetY = y - (int)y;
|
|
return atlas.sprTileSheet->GetPixel(std::get<0>(atlas.location[t->id]) + fOffsetX * std::get<2>(atlas.location[t->id]),
|
|
std::get<1>(atlas.location[t->id]) + fOffsetX * std::get<3>(atlas.location[t->id]));
|
|
}
|
|
else
|
|
return olc::BLANK;
|
|
}
|
|
|
|
template<typename T>
|
|
std::vector<olc::TILE::Edge> TILE::ExtractEdgesFromLayer(olc::TILE::Layer<T> &layer, int sx, int sy, int width, int height)
|
|
{
|
|
enum
|
|
{
|
|
NORTH = 0,
|
|
EAST = 1,
|
|
SOUTH = 2,
|
|
WEST = 3
|
|
};
|
|
|
|
std::vector<olc::TILE::Edge> vecEdges;
|
|
|
|
for (int x = -1; x < width + 1; x++)
|
|
for (int y = -1; y < height + 1; y++)
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if ((x + sx) >= 0 && (y + sy) >= 0 && (x + sx) < (layer.nLayerWidth - 1) && (y + sy) < (layer.nLayerHeight - 1))
|
|
{
|
|
layer.GetTile(x + sx, y + sy)->edge_exist[j] = false;
|
|
layer.GetTile(x + sx, y + sy)->edge_id[j] = 0;
|
|
}
|
|
}
|
|
|
|
// Add boundary edges
|
|
vecEdges.push_back({ (float)(sx)* layer.nTileWidth, (float)(sy)*layer.nTileHeight, (float)(sx + width)*layer.nTileWidth, (float)(sy)*layer.nTileHeight });
|
|
vecEdges.push_back({ (float)(sx + width)* layer.nTileWidth, (float)(sy)*layer.nTileHeight, (float)(sx + width)*layer.nTileWidth, (float)(sy + height)*layer.nTileHeight });
|
|
vecEdges.push_back({ (float)(sx + width)* layer.nTileWidth, (float)(sy + height)*layer.nTileHeight, (float)(sx)*layer.nTileWidth, (float)(sy + height)*layer.nTileHeight });
|
|
vecEdges.push_back({ (float)(sx)* layer.nTileWidth, (float)(sy + height)*layer.nTileHeight, (float)(sx)*layer.nTileWidth, (float)(sy)*layer.nTileHeight });
|
|
|
|
|
|
// Iterate through region from top left to bottom right
|
|
for (int x = 0; x < width; x++)
|
|
for (int y = 0; y < height; y++)
|
|
{
|
|
T* i = layer.GetTile(x + sx, y + sy); //This
|
|
T* n = layer.GetTile(x + sx, y + sy - 1);
|
|
T* s = layer.GetTile(x + sx, y + sy + 1);
|
|
T* w = layer.GetTile(x + sx - 1, y + sy);
|
|
T* e = layer.GetTile(x + sx + 1, y + sy);
|
|
|
|
// If this cell exists, check if it needs edges
|
|
if (i->exist)
|
|
{
|
|
// If this cell has no western neighbour, it needs a western edge
|
|
if (w && !w->exist)
|
|
{
|
|
// It can either extend it from its northern neighbour if they have
|
|
// one, or It can start a new one.
|
|
if (n && n->edge_exist[WEST])
|
|
{
|
|
// Northern neighbour has a western edge, so grow it downwards
|
|
vecEdges[n->edge_id[WEST]].ey += layer.nTileHeight;
|
|
i->edge_id[WEST] = n->edge_id[WEST];
|
|
i->edge_exist[WEST] = true;
|
|
}
|
|
else
|
|
{
|
|
// Northern neighbour does not have one, so create one
|
|
olc::TILE::Edge edge;
|
|
edge.sx = (sx + x) * layer.nTileWidth; edge.sy = (sy + y) * layer.nTileHeight;
|
|
edge.ex = edge.sx; edge.ey = edge.sy + layer.nTileHeight;
|
|
|
|
// Add edge to Polygon Pool
|
|
int edge_id = vecEdges.size();
|
|
vecEdges.push_back(edge);
|
|
|
|
// Update tile information with edge information
|
|
i->edge_id[WEST] = edge_id;
|
|
i->edge_exist[WEST] = true;
|
|
}
|
|
}
|
|
|
|
|
|
// If this cell dont have an eastern neignbour, It needs a eastern edge
|
|
if (e && !e->exist)
|
|
{
|
|
// It can either extend it from its northern neighbour if they have
|
|
// one, or It can start a new one.
|
|
if (n && n->edge_exist[EAST])
|
|
{
|
|
// Northern neighbour has one, so grow it downwards
|
|
vecEdges[n->edge_id[EAST]].ey += layer.nTileHeight;
|
|
i->edge_id[EAST] = n->edge_id[EAST];
|
|
i->edge_exist[EAST] = true;
|
|
}
|
|
else
|
|
{
|
|
// Northern neighbour does not have one, so create one
|
|
olc::TILE::Edge edge;
|
|
edge.sx = (sx + x + 1) * layer.nTileWidth; edge.sy = (sy + y) * layer.nTileHeight;
|
|
edge.ex = edge.sx; edge.ey = edge.sy + layer.nTileHeight;
|
|
|
|
// Add edge to Polygon Pool
|
|
int edge_id = vecEdges.size();
|
|
vecEdges.push_back(edge);
|
|
|
|
// Update tile information with edge information
|
|
i->edge_id[EAST] = edge_id;
|
|
i->edge_exist[EAST] = true;
|
|
}
|
|
}
|
|
|
|
// If this cell doesnt have a northern neignbour, It needs a northern edge
|
|
if (n && !n->exist)
|
|
{
|
|
// It can either extend it from its western neighbour if they have
|
|
// one, or It can start a new one.
|
|
if (w && w->edge_exist[NORTH])
|
|
{
|
|
// Western neighbour has one, so grow it eastwards
|
|
vecEdges[w->edge_id[NORTH]].ex += layer.nTileWidth;
|
|
i->edge_id[NORTH] = w->edge_id[NORTH];
|
|
i->edge_exist[NORTH] = true;
|
|
}
|
|
else
|
|
{
|
|
// Western neighbour does not have one, so create one
|
|
olc::TILE::Edge edge;
|
|
edge.sx = (sx + x) * layer.nTileWidth; edge.sy = (sy + y) * layer.nTileHeight;
|
|
edge.ex = edge.sx + layer.nTileWidth; edge.ey = edge.sy;
|
|
|
|
// Add edge to Polygon Pool
|
|
int edge_id = vecEdges.size();
|
|
vecEdges.push_back(edge);
|
|
|
|
// Update tile information with edge information
|
|
i->edge_id[NORTH] = edge_id;
|
|
i->edge_exist[NORTH] = true;
|
|
}
|
|
}
|
|
|
|
// If this cell doesnt have a southern neignbour, It needs a southern edge
|
|
if (s && !s->exist)
|
|
{
|
|
// It can either extend it from its western neighbour if they have
|
|
// one, or It can start a new one.
|
|
if (w && w->edge_exist[SOUTH])
|
|
{
|
|
// Western neighbour has one, so grow it eastwards
|
|
vecEdges[w->edge_id[SOUTH]].ex += layer.nTileWidth;
|
|
i->edge_id[SOUTH] = w->edge_id[SOUTH];
|
|
i->edge_exist[SOUTH] = true;
|
|
}
|
|
else
|
|
{
|
|
// Western neighbour does not have one, so I need to create one
|
|
olc::TILE::Edge edge;
|
|
edge.sx = (sx + x) * layer.nTileWidth; edge.sy = (sy + y + 1) * layer.nTileHeight;
|
|
edge.ex = edge.sx + layer.nTileWidth; edge.ey = edge.sy;
|
|
|
|
// Add edge to Polygon Pool
|
|
int edge_id = vecEdges.size();
|
|
vecEdges.push_back(edge);
|
|
|
|
// Update tile information with edge information
|
|
i->edge_id[SOUTH] = edge_id;
|
|
i->edge_exist[SOUTH] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return vecEdges;
|
|
}
|
|
|
|
|
|
|
|
TILE::Atlas::Atlas()
|
|
{
|
|
}
|
|
|
|
void TILE::Atlas::Create(olc::Sprite *tileSheet)
|
|
{
|
|
sprTileSheet = tileSheet;
|
|
location.clear();
|
|
|
|
}
|
|
|
|
olc::rcode TILE::Atlas::LoadFromFile(std::string filename)
|
|
{
|
|
return olc::FAIL;
|
|
}
|
|
|
|
olc::rcode TILE::Atlas::SaveToFile(std::string filename)
|
|
{
|
|
return olc::FAIL;
|
|
}
|
|
|
|
}
|
|
|