Implemented grid. Modified map renderer so that it can render tiles that have a different size than the map tiles. (Note: this change is not tested yet).
This commit is contained in:
parent
0dc77aacb4
commit
c12a8ede5a
@ -14,6 +14,10 @@
|
|||||||
<BackgroundRenderer />
|
<BackgroundRenderer />
|
||||||
</GameObject>
|
</GameObject>
|
||||||
|
|
||||||
|
<GameObject name="Object Layer">
|
||||||
|
<Grid w="380" h="250" />
|
||||||
|
</GameObject>
|
||||||
|
|
||||||
<!-- Player object -->
|
<!-- Player object -->
|
||||||
<GameObject name="Player">
|
<GameObject name="Player">
|
||||||
<Transform x="120" y="100" />
|
<Transform x="120" y="100" />
|
||||||
@ -32,4 +36,10 @@
|
|||||||
<DebugController />
|
<DebugController />
|
||||||
</GameObject>
|
</GameObject>
|
||||||
|
|
||||||
|
<GameObject name="enemyTest">
|
||||||
|
<Transform x="125" y="110" />
|
||||||
|
<Sprite src="sprites/Player.sprite" />
|
||||||
|
<SpriteRenderer />
|
||||||
|
</GameObject>
|
||||||
|
|
||||||
</Scene>
|
</Scene>
|
@ -49,8 +49,8 @@ FILE_TYPES = [
|
|||||||
([".sprite"], "Sprite"),
|
([".sprite"], "Sprite"),
|
||||||
([".config"], "Configuration"),
|
([".config"], "Configuration"),
|
||||||
([".scene"], "Scene"),
|
([".scene"], "Scene"),
|
||||||
([".back"], "Background"),
|
([".back"], "Map"),
|
||||||
([".csv"], "BackgroundLayer"),
|
([".csv"], "MapLayer"),
|
||||||
([".item"], "Item"),
|
([".item"], "Item"),
|
||||||
([".items"], "ItemCollection"),
|
([".items"], "ItemCollection"),
|
||||||
]
|
]
|
||||||
|
@ -11,9 +11,10 @@ namespace farmlands {
|
|||||||
GameState GameState::s_current;
|
GameState GameState::s_current;
|
||||||
|
|
||||||
GameState::GameState()
|
GameState::GameState()
|
||||||
: renderContext(),
|
: config(nullptr),
|
||||||
|
renderContext(),
|
||||||
scene(nullptr),
|
scene(nullptr),
|
||||||
config(nullptr),
|
itemPrefabs(),
|
||||||
elapsedTime(0),
|
elapsedTime(0),
|
||||||
gameInitialized(false)
|
gameInitialized(false)
|
||||||
{
|
{
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* Background.cpp
|
|
||||||
*
|
|
||||||
* Created on: Dec 1, 2016
|
|
||||||
* Author: tibi
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <components/Background.h>
|
|
||||||
#include <utils/Assert.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace farmlands {
|
|
||||||
namespace components {
|
|
||||||
|
|
||||||
|
|
||||||
Background::Background(size_t layerCount, size_t rowCount, size_t columnCount)
|
|
||||||
: m_cells(new Cell[layerCount * rowCount * columnCount]),
|
|
||||||
m_textures(new resources::ResourceId[layerCount]),
|
|
||||||
m_layers(layerCount),
|
|
||||||
m_rows(rowCount),
|
|
||||||
m_columns(columnCount)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Background::~Background()
|
|
||||||
{
|
|
||||||
delete[] m_cells;
|
|
||||||
delete[] m_textures;
|
|
||||||
}
|
|
||||||
|
|
||||||
model::Component* Background::clone()
|
|
||||||
{
|
|
||||||
Background* clone = new Background(m_layers, m_rows, m_columns);
|
|
||||||
memcpy(clone->m_cells, m_cells, sizeof(Cell) * m_layers * m_rows * m_columns);
|
|
||||||
memcpy(clone->m_textures, m_textures, sizeof(resources::ResourceId) * m_layers);
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cell Background::cell(size_t layer, size_t row, size_t col) const
|
|
||||||
{
|
|
||||||
Assert(layer < m_layers, "Layer out of bounds.");
|
|
||||||
Assert(row < m_rows, "Row out of bounds.");
|
|
||||||
Assert(col < m_columns, "Column out of bounds.");
|
|
||||||
|
|
||||||
return m_cells[layer * m_rows * m_columns + row * m_columns + col];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Background::setCell(size_t layer, size_t row, size_t col, Cell value)
|
|
||||||
{
|
|
||||||
Assert(layer < m_layers, "Layer out of bounds.");
|
|
||||||
Assert(row < m_rows, "Row out of bounds.");
|
|
||||||
Assert(col < m_columns, "Column out of bounds.");
|
|
||||||
|
|
||||||
m_cells[layer * m_rows * m_columns + row * m_columns + col] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
resources::ResourceId Background::texture(size_t layer) const
|
|
||||||
{
|
|
||||||
Assert(layer < m_layers, "Layer out of bounds.");
|
|
||||||
return m_textures[layer];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Background::setTexture(size_t layer, resources::ResourceId textureId) const
|
|
||||||
{
|
|
||||||
Assert(layer < m_layers, "Layer out of bounds.");
|
|
||||||
m_textures[layer] = textureId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Background::dump(unsigned level)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < level; i++)
|
|
||||||
std::cout<<" ";
|
|
||||||
|
|
||||||
std::cout << " .Component: Background\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace model */
|
|
||||||
} /* namespace farmlands */
|
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Background.h
|
|
||||||
*
|
|
||||||
* Created on: Dec 1, 2016
|
|
||||||
* Author: tibi
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MODEL_BACKGROUND_H_
|
|
||||||
#define MODEL_BACKGROUND_H_
|
|
||||||
|
|
||||||
#include <model/Component.h>
|
|
||||||
#include <resources/ResourceManager.h>
|
|
||||||
|
|
||||||
namespace farmlands {
|
|
||||||
namespace components {
|
|
||||||
|
|
||||||
typedef int16_t Cell;
|
|
||||||
|
|
||||||
class Background: public model::Component
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Background(size_t layerCount, size_t rowCount, size_t columnCount);
|
|
||||||
virtual ~Background();
|
|
||||||
|
|
||||||
virtual model::Component* clone() override;
|
|
||||||
virtual void dump(unsigned level) override;
|
|
||||||
|
|
||||||
inline size_t layerCount() const { return m_layers; }
|
|
||||||
inline size_t rowCount() const { return m_rows; }
|
|
||||||
inline size_t columnCount() const { return m_columns; }
|
|
||||||
|
|
||||||
Cell cell(size_t layer, size_t row, size_t col) const;
|
|
||||||
void setCell(size_t layer, size_t row, size_t col, Cell value);
|
|
||||||
|
|
||||||
resources::ResourceId texture(size_t layer) const;
|
|
||||||
void setTexture(size_t layer, resources::ResourceId textureId) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Cell* m_cells;
|
|
||||||
resources::ResourceId* m_textures;
|
|
||||||
size_t m_layers;
|
|
||||||
size_t m_rows;
|
|
||||||
size_t m_columns;
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* namespace model */
|
|
||||||
} /* namespace farmlands */
|
|
||||||
|
|
||||||
#endif /* MODEL_BACKGROUND_H_ */
|
|
113
src/components/Map.cpp
Normal file
113
src/components/Map.cpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Background.cpp
|
||||||
|
*
|
||||||
|
* Created on: Dec 1, 2016
|
||||||
|
* Author: tibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <components/Map.h>
|
||||||
|
#include <utils/Assert.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace farmlands {
|
||||||
|
namespace components {
|
||||||
|
|
||||||
|
/****** MapLayer implementation ******/
|
||||||
|
|
||||||
|
MapLayer::MapLayer(size_t w, size_t h)
|
||||||
|
: name(),
|
||||||
|
tileSet(),
|
||||||
|
m_cells(new Cell[w * h]),
|
||||||
|
m_w(w), m_h(h)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MapLayer* MapLayer::clone()
|
||||||
|
{
|
||||||
|
auto clone = new MapLayer(m_w, m_h);
|
||||||
|
clone->name = name;
|
||||||
|
clone->tileSet = tileSet;
|
||||||
|
memcpy(clone->m_cells, m_cells, sizeof(Cell) * m_w * m_h);
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell MapLayer::get(size_t row, size_t col) const
|
||||||
|
{
|
||||||
|
Assert(row < m_w && col < m_h, "Index out of bounds.");
|
||||||
|
|
||||||
|
return m_cells[row * m_w + col];
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell* MapLayer::operator [](size_t row)
|
||||||
|
{
|
||||||
|
Assert(row < m_w, "Index out of bounds.");
|
||||||
|
|
||||||
|
return m_cells + (row * m_w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapLayer::set(size_t row, size_t col, Cell value)
|
||||||
|
{
|
||||||
|
m_cells[row * m_w + col] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****** Map implementation ******/
|
||||||
|
|
||||||
|
Map::~Map()
|
||||||
|
{
|
||||||
|
for (MapLayer* layer : m_layers)
|
||||||
|
delete layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
model::Component* Map::clone()
|
||||||
|
{
|
||||||
|
Map* clone = new Map();
|
||||||
|
clone->width = width;
|
||||||
|
clone->height = height;
|
||||||
|
|
||||||
|
for (MapLayer* layer : m_layers)
|
||||||
|
{
|
||||||
|
MapLayer* layerClone = layer->clone();
|
||||||
|
clone->m_layers.push_back(layerClone);
|
||||||
|
clone->m_layersStr.emplace(layerClone->name, clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::dump(unsigned level)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < level; i++)
|
||||||
|
std::cout<<" ";
|
||||||
|
|
||||||
|
std::cout << " .Component: Background\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MapLayer& Map::addLayer(std::string name)
|
||||||
|
{
|
||||||
|
Assert(m_layersStr.count(name) == 0, "Layer with same name already exists!");
|
||||||
|
|
||||||
|
MapLayer* layer = new MapLayer(width, height);
|
||||||
|
layer->name = name;
|
||||||
|
m_layers.push_back(layer);
|
||||||
|
m_layersStr.emplace(name, layer);
|
||||||
|
|
||||||
|
return *layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapLayer& Map::layer(size_t index)
|
||||||
|
{
|
||||||
|
return *m_layers.at(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
MapLayer& Map::layer(std::string name)
|
||||||
|
{
|
||||||
|
return *(MapLayer*)m_layersStr.at(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace model */
|
||||||
|
} /* namespace farmlands */
|
||||||
|
|
73
src/components/Map.h
Normal file
73
src/components/Map.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Map.h
|
||||||
|
*
|
||||||
|
* Created on: Dec 1, 2016
|
||||||
|
* Author: tibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MODEL_MAP_H_
|
||||||
|
#define MODEL_MAP_H_
|
||||||
|
|
||||||
|
#include <model/Component.h>
|
||||||
|
#include <model/TileSet.h>
|
||||||
|
#include <resources/ResourceManager.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace farmlands {
|
||||||
|
namespace components {
|
||||||
|
|
||||||
|
typedef int16_t Cell;
|
||||||
|
|
||||||
|
class MapLayer : utils::ICloneable<MapLayer>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapLayer(size_t w, size_t h);
|
||||||
|
virtual MapLayer* clone() override;
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
Cell get(size_t row, size_t col) const;
|
||||||
|
Cell* operator[] (size_t row);
|
||||||
|
|
||||||
|
// Setters
|
||||||
|
void set(size_t row, size_t col, Cell value);
|
||||||
|
|
||||||
|
// Public properties
|
||||||
|
std::string name;
|
||||||
|
model::TileSet tileSet;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Cell* m_cells;
|
||||||
|
size_t m_w, m_h;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Map: public model::Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Map();
|
||||||
|
|
||||||
|
virtual model::Component* clone() override;
|
||||||
|
virtual void dump(unsigned level) override;
|
||||||
|
|
||||||
|
// Layer operations
|
||||||
|
MapLayer& addLayer(std::string name);
|
||||||
|
MapLayer& layer(size_t index);
|
||||||
|
MapLayer& layer(std::string name);
|
||||||
|
|
||||||
|
size_t layersCount() const { return m_layers.size(); }
|
||||||
|
|
||||||
|
// Size counted in cells
|
||||||
|
size_t width, height;
|
||||||
|
size_t cellWidth, cellHeight;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<MapLayer*> m_layers;
|
||||||
|
std::map<std::string, void*> m_layersStr; // gcc gives error if I use MapLayer*
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace model */
|
||||||
|
} /* namespace farmlands */
|
||||||
|
|
||||||
|
#endif /* MODEL_BACKGROUND_H_ */
|
146
src/components/basic/Grid.cpp
Normal file
146
src/components/basic/Grid.cpp
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Grid.cpp
|
||||||
|
*
|
||||||
|
* Created on: Dec 4, 2016
|
||||||
|
* Author: tibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <components/basic/Grid.h>
|
||||||
|
#include <components/basic/Transform.h>
|
||||||
|
#include <utils/Assert.h>
|
||||||
|
#include <utils/Exceptions.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace farmlands::model;
|
||||||
|
using namespace farmlands::utils;
|
||||||
|
|
||||||
|
namespace farmlands {
|
||||||
|
namespace components {
|
||||||
|
namespace basic {
|
||||||
|
|
||||||
|
Grid::Grid()
|
||||||
|
: m_bounds(0, 0, 1, 1),
|
||||||
|
m_grid(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid::~Grid()
|
||||||
|
{
|
||||||
|
if (m_grid != nullptr)
|
||||||
|
delete[] m_grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
model::Component* Grid::clone()
|
||||||
|
{
|
||||||
|
Grid* clone = new Grid();
|
||||||
|
clone->m_bounds = m_bounds;
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grid::dump(unsigned level)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < level; i++)
|
||||||
|
std::cout<<" ";
|
||||||
|
|
||||||
|
std::cout << " .Component: Grid bounds=[";
|
||||||
|
std::cout << m_bounds.x << "," << m_bounds.y << ",";
|
||||||
|
std::cout << m_bounds.w << "," << m_bounds.h << "]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grid::onInitialize()
|
||||||
|
{
|
||||||
|
// Allocate memory
|
||||||
|
m_grid = new model::GameObject*[m_bounds.w * m_bounds.h];
|
||||||
|
memset(m_grid, 0, sizeof(model::GameObject*) * m_bounds.w * m_bounds.h);
|
||||||
|
|
||||||
|
// Add objects
|
||||||
|
for (auto it = gameObject->childrenBegin(); it != gameObject->childrenEnd(); it++)
|
||||||
|
{
|
||||||
|
GameObject* obj = *it;
|
||||||
|
|
||||||
|
// Get transform
|
||||||
|
Transform* tr = obj->component<Transform>();
|
||||||
|
if (tr == nullptr)
|
||||||
|
{
|
||||||
|
std::cerr << "Grid: ignoring object " << obj->name << ": object has no transform.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute grid position(s)
|
||||||
|
Rect<int> bounds(tr->x, tr->y, roundf(tr->w), roundf(tr->h));
|
||||||
|
if (!bounds.intersects(m_bounds))
|
||||||
|
{
|
||||||
|
std::cerr << "Grid: ignoring object " << obj->name << ": object outside allowed bounds.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set
|
||||||
|
for (int y = bounds.y; y < bounds.y + bounds.h; y++)
|
||||||
|
for (int x = bounds.x; x < bounds.x + bounds.w; x++)
|
||||||
|
set(obj, x, y, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grid::setBounds(const utils::Rect<int>& bounds)
|
||||||
|
{
|
||||||
|
if (m_grid == nullptr)
|
||||||
|
m_bounds = bounds;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get rid of old grid
|
||||||
|
delete[] m_grid;
|
||||||
|
m_grid = nullptr;
|
||||||
|
|
||||||
|
m_bounds = bounds;
|
||||||
|
|
||||||
|
// Reinitialize
|
||||||
|
onInitialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::Rect<int> Grid::bounds() const
|
||||||
|
{
|
||||||
|
return m_bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
model::GameObject* Grid::get(int x, int y)
|
||||||
|
{
|
||||||
|
Assert(m_grid != nullptr, "Grid not initialized!!!");
|
||||||
|
|
||||||
|
if (m_bounds.contains(x, y))
|
||||||
|
{
|
||||||
|
int gx = x - m_bounds.x;
|
||||||
|
int gy = y - m_bounds.y;
|
||||||
|
|
||||||
|
return m_grid[gy * m_bounds.w + gx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grid::set(model::GameObject* obj, int x, int y, bool throwOnOverwrite)
|
||||||
|
{
|
||||||
|
int gx = x - m_bounds.x;
|
||||||
|
int gy = y - m_bounds.y;
|
||||||
|
int index = gy * m_bounds.w + gx;
|
||||||
|
|
||||||
|
if (m_grid[index] != nullptr)
|
||||||
|
{
|
||||||
|
if (throwOnOverwrite)
|
||||||
|
THROW(InvalidArgumentException, "Position already occupied!");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Grid: cannot set " << obj->name << " to position " << x << ", " << y;
|
||||||
|
std::cerr << ": cell already occupied";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_grid[index] = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace basic */
|
||||||
|
} /* namespace components */
|
||||||
|
} /* namespace farmlands */
|
82
src/components/basic/Grid.h
Normal file
82
src/components/basic/Grid.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Grid.h
|
||||||
|
*
|
||||||
|
* Created on: Dec 4, 2016
|
||||||
|
* Author: tibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMPONENTS_BASIC_GRID_H_
|
||||||
|
#define COMPONENTS_BASIC_GRID_H_
|
||||||
|
|
||||||
|
#include <model/Component.h>
|
||||||
|
#include <model/GameObject.h>
|
||||||
|
#include <utils/Rect.h>
|
||||||
|
|
||||||
|
namespace farmlands {
|
||||||
|
namespace components {
|
||||||
|
namespace basic {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages all the children components so that they are in a grid.
|
||||||
|
* Uses the x and y positions of the game objects to find the grid position.
|
||||||
|
*
|
||||||
|
* Positions are read in the initialize method.
|
||||||
|
* If there are multiple objects in the same cell position, only the first one is considered.
|
||||||
|
* If there are objects outside the given bounds, they are ignored.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Operation:
|
||||||
|
* After initialization, use get to obtain the element in a specific grid position.
|
||||||
|
* When adding a game object to the parent, make sure to call "update on the grid".
|
||||||
|
*
|
||||||
|
* The update/move methods check if a non-empty cell will be written over, and they throw
|
||||||
|
* an exception.
|
||||||
|
*/
|
||||||
|
class Grid: public model::Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Grid();
|
||||||
|
virtual ~Grid();
|
||||||
|
|
||||||
|
virtual model::Component* clone() override;
|
||||||
|
virtual void dump(unsigned level) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the grid component.
|
||||||
|
*
|
||||||
|
* When this method gets called, the grid puts all the children game objects in corresponding
|
||||||
|
* cells. The object transform is used to calculate what cells the objects occupy (x, y, w, h).
|
||||||
|
*
|
||||||
|
* If there are multiple objects in the same cell position, only the first one is considered.
|
||||||
|
* (a warning is printed to stderr).
|
||||||
|
* Also, if there are objects outside the given bounds, they are ignored.
|
||||||
|
*/
|
||||||
|
virtual void onInitialize() override;
|
||||||
|
|
||||||
|
// Setters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the bounds of the grid.
|
||||||
|
*
|
||||||
|
* If the bounds are changed after initialization, the positions will be updated.
|
||||||
|
*/
|
||||||
|
void setBounds(const utils::Rect<int>& bounds);
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
utils::Rect<int> bounds() const;
|
||||||
|
|
||||||
|
// Operations
|
||||||
|
model::GameObject* get(int x, int y);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set(model::GameObject* obj, int x, int y, bool throwOnOverwrite);
|
||||||
|
|
||||||
|
utils::Rect<int> m_bounds;
|
||||||
|
model::GameObject** m_grid;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace basic */
|
||||||
|
} /* namespace components */
|
||||||
|
} /* namespace farmlands */
|
||||||
|
|
||||||
|
#endif /* COMPONENTS_BASIC_GRID_H_ */
|
@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <GameState.h>
|
#include <GameState.h>
|
||||||
|
#include <components/basic/Transform.h>
|
||||||
#include <components/basic/Sprite.h>
|
#include <components/basic/Sprite.h>
|
||||||
#include <utils/Assert.h>
|
#include <utils/Assert.h>
|
||||||
|
|
||||||
|
@ -6,16 +6,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <GameState.h>
|
#include <GameState.h>
|
||||||
#include <components/GuiController.h>
|
#include <components/gui/GuiController.h>
|
||||||
#include <gui/widgets/TextArea.h>
|
#include <gui/widgets/TextArea.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace components {
|
namespace components {
|
||||||
|
namespace gui {
|
||||||
|
|
||||||
GuiController::GuiController()
|
GuiController::GuiController()
|
||||||
: m_canvas()
|
: m_canvas(),
|
||||||
|
m_context(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,16 +38,16 @@ void GuiController::onInitialize()
|
|||||||
m_canvas.setSize(m_context->viewport.width, m_context->viewport.height);
|
m_canvas.setSize(m_context->viewport.width, m_context->viewport.height);
|
||||||
|
|
||||||
// Add a text element
|
// Add a text element
|
||||||
auto text = new gui::widgets::TextArea();
|
auto text = new farmlands::gui::widgets::TextArea();
|
||||||
text->setText("Hello world!");
|
text->setText("Hello world!");
|
||||||
text->setSize(50, 5);
|
text->setSize(50, 5);
|
||||||
text->setPosition(100, 10);
|
text->setPosition(100, 10);
|
||||||
text->setColor(0, 1, 0);
|
text->setColor(0, 1, 0);
|
||||||
text->setBackColor(0.5f, 0, 0, 0.5f);
|
text->setBackColor(0.5f, 0, 0, 0.5f);
|
||||||
text->setTextSize(11);
|
text->setTextSize(11);
|
||||||
text->setHorizontalWrap(gui::widgets::TextHorizontalWrapping::Ellipsis);
|
text->setHorizontalWrap(farmlands::gui::widgets::TextHorizontalWrapping::Ellipsis);
|
||||||
text->setVerticalWrap(gui::widgets::TextVerticalWrapping::Trim);
|
text->setVerticalWrap(farmlands::gui::widgets::TextVerticalWrapping::Trim);
|
||||||
text->setAlignment(gui::widgets::TextAlign::BottomRight);
|
text->setAlignment(farmlands::gui::widgets::TextAlign::BottomRight);
|
||||||
m_canvas.addChild(text);
|
m_canvas.addChild(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,5 +84,6 @@ void GuiController::dump(unsigned level)
|
|||||||
std::cout << " .Component: DebugController\n";
|
std::cout << " .Component: DebugController\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
} /* namespace controller */
|
} /* namespace controller */
|
||||||
} /* namespace farmlands */
|
} /* namespace farmlands */
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace components {
|
namespace components {
|
||||||
|
namespace gui {
|
||||||
|
|
||||||
class GuiController : public model::Component
|
class GuiController : public model::Component
|
||||||
{
|
{
|
||||||
@ -34,10 +35,11 @@ namespace components {
|
|||||||
virtual void onRender() override;
|
virtual void onRender() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
gui::layout::Canvas m_canvas;
|
farmlands::gui::layout::Canvas m_canvas;
|
||||||
graphics::RenderContext* m_context;
|
graphics::RenderContext* m_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
} /* namespace controller */
|
} /* namespace controller */
|
||||||
} /* namespace farmlands */
|
} /* namespace farmlands */
|
||||||
|
|
@ -8,14 +8,14 @@
|
|||||||
#ifndef COMPONENTS_ITEMS_AXE_H_
|
#ifndef COMPONENTS_ITEMS_AXE_H_
|
||||||
#define COMPONENTS_ITEMS_AXE_H_
|
#define COMPONENTS_ITEMS_AXE_H_
|
||||||
|
|
||||||
#include <components/items/ITool.h>
|
#include <components/items/IPlayerAction.h>
|
||||||
#include <model/Component.h>
|
#include <model/Component.h>
|
||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace components {
|
namespace components {
|
||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
class Axe: public model::Component, public ITool
|
class Axe: public model::Component, public IPlayerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Axe();
|
Axe();
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
#ifndef CONTROLLER_ITEMS_GIFTABLE_H_
|
#ifndef CONTROLLER_ITEMS_GIFTABLE_H_
|
||||||
#define CONTROLLER_ITEMS_GIFTABLE_H_
|
#define CONTROLLER_ITEMS_GIFTABLE_H_
|
||||||
|
|
||||||
#include <components/items/ITool.h>
|
#include <components/items/IPlayerAction.h>
|
||||||
#include <model/Component.h>
|
#include <model/Component.h>
|
||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace components {
|
namespace components {
|
||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
class Giftable: public model::Component, public ITool
|
class Giftable: public model::Component, public IPlayerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Giftable();
|
Giftable();
|
||||||
|
@ -21,7 +21,7 @@ namespace components {
|
|||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
Hoe::Hoe()
|
Hoe::Hoe()
|
||||||
: m_back(nullptr)
|
: m_map(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,15 +47,15 @@ void Hoe::onInitialize()
|
|||||||
model::GameObject* root = &GameState::current().scene->root;
|
model::GameObject* root = &GameState::current().scene->root;
|
||||||
|
|
||||||
// Find background object
|
// Find background object
|
||||||
auto it = root->findByComponent<Background>();
|
auto it = root->findByComponent<Map>();
|
||||||
Assert(it != root->childrenEnd(), "Can't find background game object.");
|
Assert(it != root->childrenEnd(), "Can't find background game object.");
|
||||||
|
|
||||||
m_back = (*it)->component<Background>();
|
m_map = (*it)->component<Map>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hoe::performAction(float x, float y, model::Direction d)
|
void Hoe::performAction(float x, float y, model::Direction d)
|
||||||
{
|
{
|
||||||
Assert(m_back, "No background object!!!");
|
Assert(m_map, "No background object!!!");
|
||||||
|
|
||||||
// Compute watering position
|
// Compute watering position
|
||||||
float digX, digY;
|
float digX, digY;
|
||||||
@ -65,11 +65,11 @@ void Hoe::performAction(float x, float y, model::Direction d)
|
|||||||
size_t row = floorf(digY);
|
size_t row = floorf(digY);
|
||||||
|
|
||||||
// See what the cell contains
|
// See what the cell contains
|
||||||
Cell backCell = m_back->cell(0, row, col);
|
Cell backCell = m_map->layer(0).get(row, col);
|
||||||
Cell soilCell = m_back->cell(1, row, col);
|
Cell soilCell = m_map->layer(1).get(row, col);
|
||||||
|
|
||||||
if (groundIsDirt(backCell) && soilCell == Ground::None)
|
if (groundIsDirt(backCell) && soilCell == Ground::None)
|
||||||
m_back->setCell(1, row, col, Ground::SoilDry);
|
m_map->layer(1)[row][col] = Ground::SoilDry;
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace items */
|
} /* namespace items */
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
#ifndef COMPONENTS_ITEMS_HOE_H_
|
#ifndef COMPONENTS_ITEMS_HOE_H_
|
||||||
#define COMPONENTS_ITEMS_HOE_H_
|
#define COMPONENTS_ITEMS_HOE_H_
|
||||||
|
|
||||||
#include <components/Background.h>
|
#include <components/items/IPlayerAction.h>
|
||||||
#include <components/items/ITool.h>
|
#include <components/Map.h>
|
||||||
#include <model/Component.h>
|
#include <model/Component.h>
|
||||||
#include <model/Direction.h>
|
#include <model/Direction.h>
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ namespace farmlands {
|
|||||||
namespace components {
|
namespace components {
|
||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
class Hoe: public model::Component, public ITool
|
class Hoe: public model::Component, public IPlayerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Hoe();
|
Hoe();
|
||||||
@ -31,7 +31,7 @@ namespace items {
|
|||||||
virtual void performAction(float x, float y, model::Direction d) override;
|
virtual void performAction(float x, float y, model::Direction d) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Background* m_back;
|
Map* m_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace items */
|
} /* namespace items */
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
* Author: tibi
|
* Author: tibi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef COMPONENTS_ITEMS_ITOOL_H_
|
#ifndef COMPONENTS_ITEMS_IPLAYERACTION_H_
|
||||||
#define COMPONENTS_ITEMS_ITOOL_H_
|
#define COMPONENTS_ITEMS_IPLAYERACTION_H_
|
||||||
|
|
||||||
#include <model/Direction.h>
|
#include <model/Direction.h>
|
||||||
|
|
||||||
@ -14,15 +14,17 @@ namespace farmlands {
|
|||||||
namespace components {
|
namespace components {
|
||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
class ITool
|
class IPlayerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ITool() { }
|
virtual ~IPlayerAction() { }
|
||||||
virtual void performAction(float playerX, float playerY, model::Direction) = 0;
|
virtual void performAction(float playerX, float playerY, model::Direction) = 0;
|
||||||
|
|
||||||
|
float actionCost;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace items */
|
} /* namespace items */
|
||||||
} /* namespace components */
|
} /* namespace components */
|
||||||
} /* namespace farmlands */
|
} /* namespace farmlands */
|
||||||
|
|
||||||
#endif /* COMPONENTS_ITEMS_ITOOL_H_ */
|
#endif /* COMPONENTS_ITEMS_IPLAYERACTION_H_ */
|
@ -8,14 +8,14 @@
|
|||||||
#ifndef COMPONENTS_ITEMS_PICKAXE_H_
|
#ifndef COMPONENTS_ITEMS_PICKAXE_H_
|
||||||
#define COMPONENTS_ITEMS_PICKAXE_H_
|
#define COMPONENTS_ITEMS_PICKAXE_H_
|
||||||
|
|
||||||
#include <components/items/ITool.h>
|
#include <components/items/IPlayerAction.h>
|
||||||
#include <model/Component.h>
|
#include <model/Component.h>
|
||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace components {
|
namespace components {
|
||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
class Pickaxe: public model::Component, public ITool
|
class Pickaxe: public model::Component, public IPlayerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Pickaxe();
|
Pickaxe();
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
#ifndef COMPONENTS_ITEMS_SCYTHE_H_
|
#ifndef COMPONENTS_ITEMS_SCYTHE_H_
|
||||||
#define COMPONENTS_ITEMS_SCYTHE_H_
|
#define COMPONENTS_ITEMS_SCYTHE_H_
|
||||||
|
|
||||||
#include <components/items/ITool.h>
|
#include <components/items/IPlayerAction.h>
|
||||||
#include <model/Component.h>
|
#include <model/Component.h>
|
||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace components {
|
namespace components {
|
||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
class Scythe: public model::Component, public ITool
|
class Scythe: public model::Component, public IPlayerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Scythe();
|
Scythe();
|
||||||
|
@ -22,7 +22,7 @@ namespace items {
|
|||||||
WateringCan::WateringCan()
|
WateringCan::WateringCan()
|
||||||
: capacity(10),
|
: capacity(10),
|
||||||
amountLeft(10),
|
amountLeft(10),
|
||||||
m_back(nullptr)
|
m_map(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,15 +52,15 @@ void WateringCan::onInitialize()
|
|||||||
model::GameObject* root = &GameState::current().scene->root;
|
model::GameObject* root = &GameState::current().scene->root;
|
||||||
|
|
||||||
// Find background object
|
// Find background object
|
||||||
auto it = root->findByComponent<Background>();
|
auto it = root->findByComponent<Map>();
|
||||||
Assert(it != root->childrenEnd(), "Can't find background game object.");
|
Assert(it != root->childrenEnd(), "Can't find background game object.");
|
||||||
|
|
||||||
m_back = (*it)->component<Background>();
|
m_map = (*it)->component<Map>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WateringCan::performAction(float x, float y, model::Direction d)
|
void WateringCan::performAction(float x, float y, model::Direction d)
|
||||||
{
|
{
|
||||||
Assert(m_back, "No background object!!!");
|
Assert(m_map, "No background object!!!");
|
||||||
|
|
||||||
// Compute watering position
|
// Compute watering position
|
||||||
float digX, digY;
|
float digX, digY;
|
||||||
@ -70,8 +70,8 @@ void WateringCan::performAction(float x, float y, model::Direction d)
|
|||||||
size_t row = floorf(digY);
|
size_t row = floorf(digY);
|
||||||
|
|
||||||
// See what the cell contains
|
// See what the cell contains
|
||||||
Cell backCell = m_back->cell(0, row, col);
|
Cell backCell = m_map->layer(0).get(row, col);
|
||||||
Cell soilCell = m_back->cell(1, row, col);
|
Cell soilCell = m_map->layer(1).get(row, col);
|
||||||
|
|
||||||
// If there is water, fill can
|
// If there is water, fill can
|
||||||
if (backCell == Ground::Water)
|
if (backCell == Ground::Water)
|
||||||
@ -83,7 +83,7 @@ void WateringCan::performAction(float x, float y, model::Direction d)
|
|||||||
// If there is dry soil, wet it
|
// If there is dry soil, wet it
|
||||||
if (groundIsDrySoil(soilCell) && amountLeft > 0)
|
if (groundIsDrySoil(soilCell) && amountLeft > 0)
|
||||||
{
|
{
|
||||||
m_back->setCell(1, row, col, Ground::SoilWet);
|
m_map->layer(1)[row][col] = Ground::SoilWet;
|
||||||
--amountLeft;
|
--amountLeft;
|
||||||
|
|
||||||
std::cout << "Watering can: " << amountLeft << "\n";
|
std::cout << "Watering can: " << amountLeft << "\n";
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
#ifndef COMPONENTS_ITEMS_WATERINGCAN_H_
|
#ifndef COMPONENTS_ITEMS_WATERINGCAN_H_
|
||||||
#define COMPONENTS_ITEMS_WATERINGCAN_H_
|
#define COMPONENTS_ITEMS_WATERINGCAN_H_
|
||||||
|
|
||||||
#include <components/Background.h>
|
#include <components/items/IPlayerAction.h>
|
||||||
#include <components/items/ITool.h>
|
#include <components/Map.h>
|
||||||
#include <model/Component.h>
|
#include <model/Component.h>
|
||||||
#include <model/Direction.h>
|
#include <model/Direction.h>
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ namespace farmlands {
|
|||||||
namespace components {
|
namespace components {
|
||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
class WateringCan: public model::Component, public ITool
|
class WateringCan: public model::Component, public IPlayerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WateringCan();
|
WateringCan();
|
||||||
@ -35,7 +35,7 @@ namespace items {
|
|||||||
uint32_t amountLeft;
|
uint32_t amountLeft;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Background* m_back;
|
Map* m_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace items */
|
} /* namespace items */
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#define CONTROLLER_ITEMS_WEAPON_H_
|
#define CONTROLLER_ITEMS_WEAPON_H_
|
||||||
|
|
||||||
#include <components/basic/Sprite.h>
|
#include <components/basic/Sprite.h>
|
||||||
#include <components/items/ITool.h>
|
#include <components/items/IPlayerAction.h>
|
||||||
#include <graphics/SpriteRenderer.h>
|
#include <graphics/SpriteRenderer.h>
|
||||||
#include <model/Component.h>
|
#include <model/Component.h>
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ namespace farmlands {
|
|||||||
namespace components {
|
namespace components {
|
||||||
namespace items {
|
namespace items {
|
||||||
|
|
||||||
class Weapon: public model::Component, public ITool
|
class Weapon: public model::Component, public IPlayerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Weapon();
|
Weapon();
|
||||||
|
@ -91,6 +91,7 @@ void PlayerInventory::onInitialize()
|
|||||||
bool PlayerInventory::onEvent(SDL_Event& event)
|
bool PlayerInventory::onEvent(SDL_Event& event)
|
||||||
{
|
{
|
||||||
handleAttackEvents(event);
|
handleAttackEvents(event);
|
||||||
|
handleCurrentInventoryItemEvent(event);
|
||||||
handleInventoryEvents(event);
|
handleInventoryEvents(event);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -106,8 +107,17 @@ void PlayerInventory::onPreRender()
|
|||||||
if (currentItem)
|
if (currentItem)
|
||||||
{
|
{
|
||||||
Transform* itemTransf = currentItem->component<Transform>();
|
Transform* itemTransf = currentItem->component<Transform>();
|
||||||
itemTransf->x = 0.2f;
|
|
||||||
itemTransf->y = -0.8f;
|
if (m_playerMovement->facingDirection & Direction::East)
|
||||||
|
{
|
||||||
|
itemTransf->x = 0.2f;
|
||||||
|
itemTransf->y = -0.8f;
|
||||||
|
}
|
||||||
|
else if (m_playerMovement->facingDirection & Direction::West)
|
||||||
|
{
|
||||||
|
itemTransf->x = -0.8f;
|
||||||
|
itemTransf->y = -0.8f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,14 +133,14 @@ void PlayerInventory::handleAttackEvents(SDL_Event& event)
|
|||||||
// Call components which implement ITool
|
// Call components which implement ITool
|
||||||
for (auto it = currentItem->componentsBegin(); it != currentItem->componentsEnd(); it++)
|
for (auto it = currentItem->componentsBegin(); it != currentItem->componentsEnd(); it++)
|
||||||
{
|
{
|
||||||
ITool* tool = dynamic_cast<ITool*>(it->second);
|
IPlayerAction* tool = dynamic_cast<IPlayerAction*>(it->second);
|
||||||
if (tool != nullptr)
|
if (tool != nullptr)
|
||||||
tool->performAction(x, y, d);
|
tool->performAction(x, y, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerInventory::handleInventoryEvents(SDL_Event& event)
|
void PlayerInventory::handleCurrentInventoryItemEvent(SDL_Event& event)
|
||||||
{
|
{
|
||||||
// See what key was pressed
|
// See what key was pressed
|
||||||
int slot = -1;
|
int slot = -1;
|
||||||
@ -159,8 +169,6 @@ void PlayerInventory::handleInventoryEvents(SDL_Event& event)
|
|||||||
|
|
||||||
// Enable new object
|
// Enable new object
|
||||||
currentItem->setEnabled(true);
|
currentItem->setEnabled(true);
|
||||||
|
|
||||||
gameObject->dumpTree(0);
|
|
||||||
}
|
}
|
||||||
else if (0 <= slot)
|
else if (0 <= slot)
|
||||||
{
|
{
|
||||||
@ -168,6 +176,21 @@ void PlayerInventory::handleInventoryEvents(SDL_Event& event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerInventory::handleInventoryEvents(SDL_Event& event)
|
||||||
|
{
|
||||||
|
bool inventoryDrop = Input::instance().down(GameKey::InventoryDrop, event);
|
||||||
|
|
||||||
|
if (inventoryDrop && currentItem != nullptr)
|
||||||
|
{
|
||||||
|
// For now we delete the object. We may want to save its state later on
|
||||||
|
m_inventory->destroyChild(currentItem);
|
||||||
|
|
||||||
|
currentItemIndex = -1;
|
||||||
|
currentItem = nullptr;
|
||||||
|
currentWeapon = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace player */
|
} /* namespace player */
|
||||||
} /* namespace components */
|
} /* namespace components */
|
||||||
} /* namespace farmlands */
|
} /* namespace farmlands */
|
||||||
|
@ -42,6 +42,7 @@ namespace player {
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
void handleAttackEvents(SDL_Event& event);
|
void handleAttackEvents(SDL_Event& event);
|
||||||
|
void handleCurrentInventoryItemEvent(SDL_Event& event);
|
||||||
void handleInventoryEvents(SDL_Event& event);
|
void handleInventoryEvents(SDL_Event& event);
|
||||||
|
|
||||||
// Inventory
|
// Inventory
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include <GameState.h>
|
#include <GameState.h>
|
||||||
#include <model/GameObject.h>
|
#include <model/GameObject.h>
|
||||||
#include <graphics/backend/SdlRenderer.h>
|
#include <graphics/backend/SdlRenderer.h>
|
||||||
#include <graphics/BackgroundRenderer.h>
|
#include <graphics/MapRenderer.h>
|
||||||
#include <resources/ResourceManager.h>
|
#include <resources/ResourceManager.h>
|
||||||
#include <math/GameMath.h>
|
#include <math/GameMath.h>
|
||||||
#include <utils/Assert.h>
|
#include <utils/Assert.h>
|
||||||
@ -23,33 +23,36 @@ using namespace farmlands::resources;
|
|||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
|
|
||||||
BackgroundRenderer::BackgroundRenderer()
|
MapRenderer::MapRenderer()
|
||||||
: m_context(nullptr),
|
: m_context(nullptr),
|
||||||
m_back(nullptr)
|
m_map(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BackgroundRenderer::~BackgroundRenderer()
|
MapRenderer::~MapRenderer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
model::Component* BackgroundRenderer::clone()
|
model::Component* MapRenderer::clone()
|
||||||
{
|
{
|
||||||
return new BackgroundRenderer();
|
return new MapRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundRenderer::onInitialize()
|
void MapRenderer::onInitialize()
|
||||||
{
|
{
|
||||||
Assert(gameObject != nullptr, "Component not properly initialized!");
|
Assert(gameObject != nullptr, "Component not properly initialized!");
|
||||||
|
|
||||||
m_context = &GameState::current().renderContext;
|
m_context = &GameState::current().renderContext;
|
||||||
m_back = gameObject->component<Background>();
|
m_map = gameObject->component<Map>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundRenderer::onRender()
|
void MapRenderer::onRender()
|
||||||
{
|
{
|
||||||
float cellW = m_context->viewport.pixelsPerUnitX * m_context->camera()->scale;
|
Assert(m_map != nullptr, "Can't find map component.");
|
||||||
float cellH = m_context->viewport.pixelsPerUnitY * m_context->camera()->scale;
|
|
||||||
|
float scale = m_context->camera()->scale;
|
||||||
|
float cellW = m_map->cellWidth * scale;
|
||||||
|
float cellH = m_map->cellHeight * scale;
|
||||||
|
|
||||||
// Compute how many cells fit on the screen
|
// Compute how many cells fit on the screen
|
||||||
float cellsOnScreenX = m_context->viewport.width / cellW;
|
float cellsOnScreenX = m_context->viewport.width / cellW;
|
||||||
@ -61,37 +64,40 @@ void BackgroundRenderer::onRender()
|
|||||||
int maxCellY = ceilf(m_context->cameraTransform()->y + cellsOnScreenY / 2);
|
int maxCellY = ceilf(m_context->cameraTransform()->y + cellsOnScreenY / 2);
|
||||||
|
|
||||||
// Clamp cell positions
|
// Clamp cell positions
|
||||||
minCellX = clamp(minCellX, 0, (int)m_back->columnCount() - 1);
|
minCellX = clamp(minCellX, 0, (int)m_map->width - 1);
|
||||||
maxCellX = clamp(maxCellX, 0, (int)m_back->columnCount() - 1);
|
maxCellX = clamp(maxCellX, 0, (int)m_map->width - 1);
|
||||||
minCellY = clamp(minCellY, 0, (int)m_back->rowCount() - 1);
|
minCellY = clamp(minCellY, 0, (int)m_map->height - 1);
|
||||||
maxCellY = clamp(maxCellY, 0, (int)m_back->rowCount() - 1);
|
maxCellY = clamp(maxCellY, 0, (int)m_map->height - 1);
|
||||||
|
|
||||||
// Draw each layer
|
// Draw each layer
|
||||||
for (size_t i = 0; i < m_back->layerCount(); i++)
|
for (size_t i = 0; i < m_map->layersCount(); i++)
|
||||||
{
|
{
|
||||||
resources::ResourceId textureId = m_back->texture(i);
|
MapLayer& layer = m_map->layer(i);
|
||||||
|
resources::ResourceId textureId = layer.tileSet.texture;
|
||||||
|
|
||||||
// Render only visible tiles
|
// Render only visible tiles
|
||||||
for (int y = minCellY; y <= maxCellY; y++)
|
for (int y = minCellY; y <= maxCellY; y++)
|
||||||
for (int x = minCellX; x <= maxCellX; x++)
|
for (int x = minCellX; x <= maxCellX; x++)
|
||||||
{
|
{
|
||||||
int cellId = m_back->cell(i, y, x);
|
Cell cellId = layer[y][x];
|
||||||
|
|
||||||
// Obtain texture
|
// Obtain texture
|
||||||
SDL_Texture* texture = ResourceManager::instance().texture(textureId);
|
SDL_Texture* texture = ResourceManager::instance().texture(textureId);
|
||||||
|
|
||||||
// Calculate source rect
|
// Calculate source rect
|
||||||
SDL_Rect src;
|
SDL_Rect src;
|
||||||
getCell(texture, cellId, &src.x, &src.y);
|
auto r = layer.tileSet.getCell(cellId);
|
||||||
src.w = m_context->viewport.pixelsPerUnitX;
|
src.x = r.x;
|
||||||
src.h = m_context->viewport.pixelsPerUnitY;
|
src.y = r.y;
|
||||||
|
src.w = r.w;
|
||||||
|
src.h = r.h;
|
||||||
|
|
||||||
// Compute destination rect
|
// Compute destination rect
|
||||||
SDL_Rect dest;
|
SDL_Rect dest;
|
||||||
dest.x = floorf(m_context->xToScreen(x));
|
dest.x = floorf(m_context->xToScreen(x));
|
||||||
dest.y = floorf(m_context->yToScreen(y));
|
dest.y = floorf(m_context->yToScreen(y + 1) - src.h * scale); // Anchor should be bottom right corner
|
||||||
dest.w = ceilf(cellW);
|
dest.w = ceilf(src.w * scale);
|
||||||
dest.h = ceilf(cellH);
|
dest.h = ceilf(src.h * scale);
|
||||||
|
|
||||||
// Blit
|
// Blit
|
||||||
SdlRenderer::instance().renderTexture(texture, &src, &dest);
|
SdlRenderer::instance().renderTexture(texture, &src, &dest);
|
||||||
@ -99,20 +105,7 @@ void BackgroundRenderer::onRender()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundRenderer::getCell(SDL_Texture* texture, uint32_t cell, int* outX, int* outY)
|
void MapRenderer::dump(unsigned level)
|
||||||
{
|
|
||||||
int texWidth, texHeight;
|
|
||||||
SdlRenderer::instance().getTextureSize(texture, &texWidth, &texHeight);
|
|
||||||
|
|
||||||
int ppuX = m_context->viewport.pixelsPerUnitX;
|
|
||||||
int ppuY = m_context->viewport.pixelsPerUnitY;
|
|
||||||
|
|
||||||
// Compute texture coordinates
|
|
||||||
*outX = (cell * ppuX) % texWidth;
|
|
||||||
*outY = ((cell * ppuX) / texWidth) * ppuY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackgroundRenderer::dump(unsigned level)
|
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < level; i++)
|
for (unsigned i = 0; i < level; i++)
|
||||||
std::cout<<" ";
|
std::cout<<" ";
|
@ -5,23 +5,23 @@
|
|||||||
* Author: tibi
|
* Author: tibi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GRAPHICS_BACKGROUNDRENDERER_H_
|
#ifndef GRAPHICS_MAPRENDERER_H_
|
||||||
#define GRAPHICS_BACKGROUNDRENDERER_H_
|
#define GRAPHICS_MAPRENDERER_H_
|
||||||
|
|
||||||
#include <model/Component.h>
|
#include <model/Component.h>
|
||||||
#include <components/Background.h>
|
|
||||||
#include <components/basic/Camera.h>
|
#include <components/basic/Camera.h>
|
||||||
#include <components/basic/Transform.h>
|
#include <components/basic/Transform.h>
|
||||||
|
#include <components/Map.h>
|
||||||
#include <graphics/RenderContext.h>
|
#include <graphics/RenderContext.h>
|
||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
|
|
||||||
class BackgroundRenderer: public model::Component
|
class MapRenderer: public model::Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BackgroundRenderer();
|
MapRenderer();
|
||||||
virtual ~BackgroundRenderer();
|
virtual ~MapRenderer();
|
||||||
|
|
||||||
virtual model::Component* clone() override;
|
virtual model::Component* clone() override;
|
||||||
virtual void dump(unsigned level) override;
|
virtual void dump(unsigned level) override;
|
||||||
@ -30,14 +30,13 @@ namespace graphics {
|
|||||||
virtual void onRender() override;
|
virtual void onRender() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void getCell(SDL_Texture* texture, uint32_t cell, int* outX, int* outY);
|
|
||||||
|
|
||||||
// Private fields
|
// Private fields
|
||||||
graphics::RenderContext* m_context;
|
graphics::RenderContext* m_context;
|
||||||
components::Background* m_back;
|
components::Map* m_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace graphics */
|
} /* namespace graphics */
|
||||||
} /* namespace farmlands */
|
} /* namespace farmlands */
|
||||||
|
|
||||||
#endif /* GRAPHICS_BACKGROUNDRENDERER_H_ */
|
#endif /* GRAPHICS_MAPRENDERER_H_ */
|
@ -22,8 +22,8 @@ namespace farmlands {
|
|||||||
namespace graphics {
|
namespace graphics {
|
||||||
|
|
||||||
SpriteRenderer::SpriteRenderer()
|
SpriteRenderer::SpriteRenderer()
|
||||||
: m_transform(nullptr),
|
: m_context(nullptr),
|
||||||
m_context(nullptr),
|
m_transform(nullptr),
|
||||||
m_sprite(nullptr)
|
m_sprite(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <GameState.h>
|
#include <GameState.h>
|
||||||
#include <graphics/backend/SdlRenderer.h>
|
#include <graphics/backend/SdlRenderer.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@ -29,7 +30,8 @@ SdlRenderer& SdlRenderer::instance()
|
|||||||
|
|
||||||
SdlRenderer::SdlRenderer()
|
SdlRenderer::SdlRenderer()
|
||||||
: m_sdlWindow(nullptr),
|
: m_sdlWindow(nullptr),
|
||||||
m_sdlRenderer(nullptr)
|
m_sdlRenderer(nullptr),
|
||||||
|
m_queue()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,10 +87,20 @@ void SdlRenderer::renderBegin()
|
|||||||
{
|
{
|
||||||
SDL_SetRenderDrawColor(m_sdlRenderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(m_sdlRenderer, 0, 0, 0, 255);
|
||||||
SDL_RenderClear(m_sdlRenderer);
|
SDL_RenderClear(m_sdlRenderer);
|
||||||
|
|
||||||
|
m_queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdlRenderer::renderEnd()
|
void SdlRenderer::renderEnd()
|
||||||
{
|
{
|
||||||
|
// Sort by z index, but keep relative order
|
||||||
|
std::stable_sort(m_queue.begin(), m_queue.end(), compareQueueItems);
|
||||||
|
|
||||||
|
// Render everything to screen
|
||||||
|
for (auto item : m_queue)
|
||||||
|
SDL_RenderCopy(m_sdlRenderer, item.texture, &item.src, &item.dest);
|
||||||
|
|
||||||
|
// Swap buffers
|
||||||
SDL_RenderPresent(m_sdlRenderer);
|
SDL_RenderPresent(m_sdlRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,6 +109,17 @@ void SdlRenderer::renderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* d
|
|||||||
SDL_RenderCopy(m_sdlRenderer, texture, src, dest);
|
SDL_RenderCopy(m_sdlRenderer, texture, src, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SdlRenderer::queueRenderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest, float z)
|
||||||
|
{
|
||||||
|
QueueItem q;
|
||||||
|
q.texture = texture;
|
||||||
|
q.src = *src;
|
||||||
|
q.dest = *dest;
|
||||||
|
q.z = z;
|
||||||
|
|
||||||
|
m_queue.push_back(q);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_Texture* SdlRenderer::renderText(const std::string& text, TTF_Font* font, SDL_Color color)
|
SDL_Texture* SdlRenderer::renderText(const std::string& text, TTF_Font* font, SDL_Color color)
|
||||||
{
|
{
|
||||||
assert(font != nullptr);
|
assert(font != nullptr);
|
||||||
@ -116,6 +139,16 @@ void SdlRenderer::getTextureSize(SDL_Texture* texture, int* width, int* height)
|
|||||||
SDL_QueryTexture(texture, NULL, NULL, width, height);
|
SDL_QueryTexture(texture, NULL, NULL, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SdlRenderer::compareQueueItems(const QueueItem& a, const QueueItem& b)
|
||||||
|
{
|
||||||
|
// First criteria is the z index
|
||||||
|
if (a.z != b.z)
|
||||||
|
return (a.z < b.z);
|
||||||
|
|
||||||
|
// Second criteria is the Y position
|
||||||
|
return (a.dest.y < b.dest.y);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} /* namespace graphics */
|
} /* namespace graphics */
|
||||||
} /* namespace farmlands */
|
} /* namespace farmlands */
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <graphics/RenderContext.h>
|
#include <graphics/RenderContext.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <SDL2/SDL_ttf.h>
|
#include <SDL2/SDL_ttf.h>
|
||||||
@ -49,10 +50,17 @@ namespace backend {
|
|||||||
SDL_Texture* renderText(const std::string& text, TTF_Font* font, SDL_Color color);
|
SDL_Texture* renderText(const std::string& text, TTF_Font* font, SDL_Color color);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a textue
|
* Renders a texture immediately
|
||||||
*/
|
*/
|
||||||
void renderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest);
|
void renderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues a texture for rendering later.
|
||||||
|
*
|
||||||
|
* When using the queue, you can specify a z index.
|
||||||
|
*/
|
||||||
|
void queueRenderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest, float z = 0.0f);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the size of a texture
|
* Returns the size of a texture
|
||||||
*/
|
*/
|
||||||
@ -68,8 +76,25 @@ namespace backend {
|
|||||||
|
|
||||||
SdlRenderer();
|
SdlRenderer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render queue item
|
||||||
|
*/
|
||||||
|
struct QueueItem
|
||||||
|
{
|
||||||
|
SDL_Texture* texture;
|
||||||
|
SDL_Rect src;
|
||||||
|
SDL_Rect dest;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares queue items.
|
||||||
|
*/
|
||||||
|
static bool compareQueueItems(const QueueItem& a, const QueueItem& b);
|
||||||
|
|
||||||
SDL_Window* m_sdlWindow;
|
SDL_Window* m_sdlWindow;
|
||||||
SDL_Renderer* m_sdlRenderer;
|
SDL_Renderer* m_sdlRenderer;
|
||||||
|
std::vector<QueueItem> m_queue;
|
||||||
|
|
||||||
static SdlRenderer s_instance;
|
static SdlRenderer s_instance;
|
||||||
};
|
};
|
||||||
|
@ -42,6 +42,7 @@ namespace input {
|
|||||||
Inventory8,
|
Inventory8,
|
||||||
Inventory9,
|
Inventory9,
|
||||||
Inventory10,
|
Inventory10,
|
||||||
|
InventoryDrop,
|
||||||
|
|
||||||
// Debug keys
|
// Debug keys
|
||||||
Debug_ZoomIn,
|
Debug_ZoomIn,
|
||||||
|
@ -46,6 +46,7 @@ namespace input {
|
|||||||
SDL_SCANCODE_8, // Inventory8
|
SDL_SCANCODE_8, // Inventory8
|
||||||
SDL_SCANCODE_9, // Inventory9
|
SDL_SCANCODE_9, // Inventory9
|
||||||
SDL_SCANCODE_0, // Inventory10
|
SDL_SCANCODE_0, // Inventory10
|
||||||
|
SDL_SCANCODE_G, // InventoryDrop
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
SDL_SCANCODE_KP_PLUS, // Debug_ZoomIn,
|
SDL_SCANCODE_KP_PLUS, // Debug_ZoomIn,
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
#ifndef COMPONENT_H_
|
#ifndef COMPONENT_H_
|
||||||
#define COMPONENT_H_
|
#define COMPONENT_H_
|
||||||
|
|
||||||
#include <model/ICloneable.h>
|
#include <utils/ICloneable.h>
|
||||||
#include <model/INonAssignable.h>
|
#include <utils/INonAssignable.h>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ namespace model {
|
|||||||
|
|
||||||
class GameObject;
|
class GameObject;
|
||||||
|
|
||||||
class Component : public INonAssignable, public ICloneable<Component>
|
class Component : public utils::INonAssignable, public utils::ICloneable<Component>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Component();
|
Component();
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
#ifndef GAMEOBJECT_H_
|
#ifndef GAMEOBJECT_H_
|
||||||
#define GAMEOBJECT_H_
|
#define GAMEOBJECT_H_
|
||||||
|
|
||||||
#include <model/ICloneable.h>
|
|
||||||
#include <model/INonAssignable.h>
|
|
||||||
#include <utils/Assert.h>
|
#include <utils/Assert.h>
|
||||||
|
#include <utils/ICloneable.h>
|
||||||
|
#include <utils/INonAssignable.h>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ namespace model {
|
|||||||
class Component;
|
class Component;
|
||||||
class RenderContext;
|
class RenderContext;
|
||||||
|
|
||||||
class GameObject : public INonAssignable, public ICloneable<GameObject>
|
class GameObject : public utils::INonAssignable, public utils::ICloneable<GameObject>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::unordered_map<std::type_index, Component*> ComponentContainer;
|
typedef std::unordered_map<std::type_index, Component*> ComponentContainer;
|
||||||
|
42
src/model/TileSet.h
Normal file
42
src/model/TileSet.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* TileMap.h
|
||||||
|
*
|
||||||
|
* Created on: Dec 5, 2016
|
||||||
|
* Author: tibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MODEL_TILESET_H_
|
||||||
|
#define MODEL_TILESET_H_
|
||||||
|
|
||||||
|
#include <resources/ResourceManager.h>
|
||||||
|
#include <utils/Rect.h>
|
||||||
|
|
||||||
|
namespace farmlands {
|
||||||
|
namespace model {
|
||||||
|
|
||||||
|
struct TileSet
|
||||||
|
{
|
||||||
|
resources::ResourceId texture;
|
||||||
|
size_t width, height;
|
||||||
|
size_t tileWidth, tileHeight;
|
||||||
|
|
||||||
|
// Gets the boundary of a cell based on its id
|
||||||
|
utils::Rect<int> getCell(int cellId);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline utils::Rect<int> TileSet::getCell(int cellId)
|
||||||
|
{
|
||||||
|
utils::Rect<int> r;
|
||||||
|
size_t tilesRow = width / tileWidth;
|
||||||
|
|
||||||
|
r.x = tileWidth * (cellId % tilesRow);
|
||||||
|
r.y = tileHeight * (cellId / tilesRow);
|
||||||
|
r.w = tileWidth;
|
||||||
|
r.h = tileHeight;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace model */
|
||||||
|
} /* namespace farmlands */
|
||||||
|
|
||||||
|
#endif /* MODEL_TILESET_H_ */
|
@ -19,8 +19,8 @@ namespace resources {
|
|||||||
Sprite,
|
Sprite,
|
||||||
Configuration,
|
Configuration,
|
||||||
Scene,
|
Scene,
|
||||||
Background,
|
Map,
|
||||||
BackgroundLayer,
|
MapLayer,
|
||||||
Item,
|
Item,
|
||||||
ItemCollection,
|
ItemCollection,
|
||||||
};
|
};
|
||||||
|
@ -87,9 +87,9 @@ namespace resources {
|
|||||||
{ "tilesets/Ground.png", ResourceType::Texture },
|
{ "tilesets/Ground.png", ResourceType::Texture },
|
||||||
{ "ui/mini_inventory.png", ResourceType::Texture },
|
{ "ui/mini_inventory.png", ResourceType::Texture },
|
||||||
{ "ui/cursor.png", ResourceType::Texture },
|
{ "ui/cursor.png", ResourceType::Texture },
|
||||||
{ "levels/Farm_Background.csv", ResourceType::BackgroundLayer },
|
{ "levels/Farm_Background.csv", ResourceType::MapLayer },
|
||||||
{ "levels/Farm.back", ResourceType::Background },
|
{ "levels/Farm.back", ResourceType::Map },
|
||||||
{ "levels/Farm_Soil.csv", ResourceType::BackgroundLayer },
|
{ "levels/Farm_Soil.csv", ResourceType::MapLayer },
|
||||||
{ "config/Default.config", ResourceType::Configuration },
|
{ "config/Default.config", ResourceType::Configuration },
|
||||||
{ "items/Tools.items", ResourceType::ItemCollection },
|
{ "items/Tools.items", ResourceType::ItemCollection },
|
||||||
{ "items/Weapons.items", ResourceType::ItemCollection },
|
{ "items/Weapons.items", ResourceType::ItemCollection },
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* Author: tibi
|
* Author: tibi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <graphics/backend/SdlRenderer.h>
|
||||||
#include <storage/Parsers.h>
|
#include <storage/Parsers.h>
|
||||||
#include <resources/Resources.h>
|
#include <resources/Resources.h>
|
||||||
|
|
||||||
@ -15,9 +16,9 @@ namespace storage {
|
|||||||
|
|
||||||
/****** Components ******/
|
/****** Components ******/
|
||||||
|
|
||||||
void parseBackgroundCells(resources::ResourceId cellsResource, components::Background* back, size_t layer)
|
void parseMapCells(resources::ResourceId cellsResource, components::Map* map, components::MapLayer& layer)
|
||||||
{
|
{
|
||||||
Assert(RInfo[cellsResource].type == ResourceType::BackgroundLayer, "Resource must be a level layer.");
|
Assert(RInfo[cellsResource].type == ResourceType::MapLayer, "Resource must be a level layer.");
|
||||||
|
|
||||||
char buffer[1024 * 10];
|
char buffer[1024 * 10];
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ void parseBackgroundCells(resources::ResourceId cellsResource, components::Backg
|
|||||||
THROW(utils::ResourceLoadException, "Could not load level layer " + pathIn);
|
THROW(utils::ResourceLoadException, "Could not load level layer " + pathIn);
|
||||||
|
|
||||||
// Read CSV file line by line
|
// Read CSV file line by line
|
||||||
for (size_t row = 0; row < back->rowCount(); row++)
|
for (size_t row = 0; row < map->height; row++)
|
||||||
{
|
{
|
||||||
in.getline(buffer, sizeof(buffer));
|
in.getline(buffer, sizeof(buffer));
|
||||||
|
|
||||||
@ -37,10 +38,10 @@ void parseBackgroundCells(resources::ResourceId cellsResource, components::Backg
|
|||||||
|
|
||||||
// Separated by comma (or maybe semicolon)
|
// Separated by comma (or maybe semicolon)
|
||||||
char* nextNum = strtok(buffer, ",;");
|
char* nextNum = strtok(buffer, ",;");
|
||||||
for (size_t col = 0; col < back->columnCount() && nextNum != NULL; col++)
|
for (size_t col = 0; col < map->width && nextNum != NULL; col++)
|
||||||
{
|
{
|
||||||
components::Cell cell = (components::Cell) strtol(nextNum, NULL, 10);
|
components::Cell cell = (components::Cell) strtol(nextNum, NULL, 10);
|
||||||
back->setCell(layer, row, col, cell);
|
layer[row][col] = cell;
|
||||||
|
|
||||||
nextNum = strtok(NULL, ",;");
|
nextNum = strtok(NULL, ",;");
|
||||||
}
|
}
|
||||||
@ -50,10 +51,10 @@ void parseBackgroundCells(resources::ResourceId cellsResource, components::Backg
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
components::Background* parse<components::Background> (boost::property_tree::ptree& root)
|
components::Map* parse<components::Map> (boost::property_tree::ptree& root)
|
||||||
{
|
{
|
||||||
// Ensure we are on the model::Scene node (property tree seems to add root of its own)
|
// Ensure we are on the model::Scene node (property tree seems to add root of its own)
|
||||||
if (root.front().first == "Background")
|
if (root.front().first == "Map")
|
||||||
root = root.front().second;
|
root = root.front().second;
|
||||||
|
|
||||||
// This object can be declared in another file
|
// This object can be declared in another file
|
||||||
@ -61,39 +62,42 @@ components::Background* parse<components::Background> (boost::property_tree::ptr
|
|||||||
if (!src.empty())
|
if (!src.empty())
|
||||||
{
|
{
|
||||||
ResourceId id = ResourceManager::instance().getId(src);
|
ResourceId id = ResourceManager::instance().getId(src);
|
||||||
return parse<components::Background>(id);
|
return parse<components::Map>(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read sizes
|
// Read map attributes
|
||||||
uint32_t layers = root.count("Layer");
|
components::Map* map = new components::Map();
|
||||||
uint32_t rows = root.get<uint32_t>("<xmlattr>.rows");
|
|
||||||
uint32_t cols = root.get<uint32_t>("<xmlattr>.columns");
|
|
||||||
|
|
||||||
// Create components::Background object
|
map->width = root.get<size_t>("<xmlattr>.width");
|
||||||
components::Background* back = new components::Background(layers, rows, cols);
|
map->height = root.get<size_t>("<xmlattr>.height");
|
||||||
|
map->cellWidth = root.get<size_t>("<xmlattr>.cellWidth");
|
||||||
|
map->cellHeight = root.get<size_t>("<xmlattr>.cellHeight");
|
||||||
|
|
||||||
// Read layers
|
// Read layers
|
||||||
size_t layerNum = 0;
|
for (auto layerNode : root)
|
||||||
for (auto layer : root)
|
|
||||||
{
|
{
|
||||||
if (layer.first == "Layer")
|
if (layerNode.first == "Layer")
|
||||||
{
|
{
|
||||||
|
// Read layer name
|
||||||
|
std::string name = layerNode.second.get<std::string>("<xmlattr>.name");
|
||||||
|
components::MapLayer& layer = map->addLayer(name);
|
||||||
|
|
||||||
|
// Read tile set
|
||||||
|
auto tileSetNode = layerNode.second.get_child("TileSet");
|
||||||
|
|
||||||
|
model::TileSet* tileSet = parse<model::TileSet>(tileSetNode);
|
||||||
|
layer.tileSet = *tileSet;
|
||||||
|
delete tileSet;
|
||||||
|
|
||||||
// Read cells
|
// Read cells
|
||||||
std::string cellsPath = layer.second.get<std::string>("<xmlattr>.cells");
|
std::string cellsPath = layerNode.second.get<std::string>("<xmlattr>.cells");
|
||||||
resources::ResourceId cellsId = resources::ResourceManager::instance().getId(cellsPath);
|
resources::ResourceId cellsId = resources::ResourceManager::instance().getId(cellsPath);
|
||||||
parseBackgroundCells(cellsId, back, layerNum);
|
parseMapCells(cellsId, map, layer);
|
||||||
|
|
||||||
// Read texture name
|
|
||||||
std::string texPath = layer.second.get<std::string>("<xmlattr>.texture");
|
|
||||||
resources::ResourceId tex = resources::ResourceManager::instance().getId(texPath);
|
|
||||||
back->setTexture(layerNum, tex);
|
|
||||||
|
|
||||||
++layerNum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return back;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -130,6 +134,27 @@ components::basic::Frame* parse<components::basic::Frame> (boost::property_tree:
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
components::basic::Grid* parse<components::basic::Grid> (boost::property_tree::ptree& root)
|
||||||
|
{
|
||||||
|
// Ensure we are on the model::Scene node (property tree seems to add root of its own)
|
||||||
|
if (root.front().first == "Grid")
|
||||||
|
root = root.front().second;
|
||||||
|
|
||||||
|
components::basic::Grid* grid = new components::basic::Grid();
|
||||||
|
|
||||||
|
// Set properties
|
||||||
|
utils::Rect<int> bounds;
|
||||||
|
bounds.x = root.get<int>("<xmlattr>.x", 0);
|
||||||
|
bounds.y = root.get<int>("<xmlattr>.y", 0);
|
||||||
|
bounds.w = root.get<int>("<xmlattr>.w");
|
||||||
|
bounds.h = root.get<int>("<xmlattr>.h");
|
||||||
|
|
||||||
|
grid->setBounds(bounds);
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tree::ptree& root)
|
components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tree::ptree& root)
|
||||||
{
|
{
|
||||||
@ -197,8 +222,8 @@ components::basic::Transform* parse<components::basic::Transform> (boost::proper
|
|||||||
components::basic::Transform* transform = new components::basic::Transform();
|
components::basic::Transform* transform = new components::basic::Transform();
|
||||||
transform->x = root.get<float>("<xmlattr>.x", 0.0f);
|
transform->x = root.get<float>("<xmlattr>.x", 0.0f);
|
||||||
transform->y = root.get<float>("<xmlattr>.y", 0.0f);
|
transform->y = root.get<float>("<xmlattr>.y", 0.0f);
|
||||||
transform->w = root.get<float>("<xmlattr>.w", 0.0f);
|
transform->w = root.get<float>("<xmlattr>.w", 1.0f);
|
||||||
transform->h = root.get<float>("<xmlattr>.h", 0.0f);
|
transform->h = root.get<float>("<xmlattr>.h", 1.0f);
|
||||||
|
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
@ -347,13 +372,13 @@ components::player::PlayerMovement* parse<components::player::PlayerMovement> (b
|
|||||||
/****** Graphics ******/
|
/****** Graphics ******/
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
graphics::BackgroundRenderer* parse<graphics::BackgroundRenderer> (boost::property_tree::ptree& root)
|
graphics::MapRenderer* parse<graphics::MapRenderer> (boost::property_tree::ptree& root)
|
||||||
{
|
{
|
||||||
// Ensure we are on the model::Scene node (property tree seems to add root of its own)
|
// Ensure we are on the model::Scene node (property tree seems to add root of its own)
|
||||||
if (root.front().first == "BackgroundRenderer")
|
if (root.front().first == "MapRenderer")
|
||||||
root = root.front().second;
|
root = root.front().second;
|
||||||
|
|
||||||
graphics::BackgroundRenderer* renderer = new graphics::BackgroundRenderer();
|
graphics::MapRenderer* renderer = new graphics::MapRenderer();
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,15 +457,15 @@ model::GameObject* parse<model::GameObject> (boost::property_tree::ptree& root)
|
|||||||
gameObj->addComponent(parse<components::player::PlayerMovement>(child.second));
|
gameObj->addComponent(parse<components::player::PlayerMovement>(child.second));
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
else if (child.first == "Background")
|
else if (child.first == "Map")
|
||||||
gameObj->addComponent(parse<components::Background>(child.second));
|
gameObj->addComponent(parse<components::Map>(child.second));
|
||||||
|
|
||||||
else if (child.first == "DebugController")
|
else if (child.first == "DebugController")
|
||||||
gameObj->addComponent(parse<components::DebugController>(child.second));
|
gameObj->addComponent(parse<components::DebugController>(child.second));
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
else if (child.first == "BackgroundRenderer")
|
else if (child.first == "MapRenderer")
|
||||||
gameObj->addComponent(parse<graphics::BackgroundRenderer>(child.second));
|
gameObj->addComponent(parse<graphics::MapRenderer>(child.second));
|
||||||
|
|
||||||
else if (child.first == "SpriteRenderer")
|
else if (child.first == "SpriteRenderer")
|
||||||
gameObj->addComponent(parse<graphics::SpriteRenderer>(child.second));
|
gameObj->addComponent(parse<graphics::SpriteRenderer>(child.second));
|
||||||
@ -487,6 +512,39 @@ model::Scene* parse<model::Scene> (boost::property_tree::ptree& root)
|
|||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
model::TileSet* parse<model::TileSet> (boost::property_tree::ptree& root)
|
||||||
|
{
|
||||||
|
// Ensure we are on the model::Scene node (property tree seems to add root of its own)
|
||||||
|
if (root.front().first == "TileSet")
|
||||||
|
root = root.front().second;
|
||||||
|
|
||||||
|
// This object can be declared in another file
|
||||||
|
std::string src = root.get<std::string>("<xmlattr>.src", "");
|
||||||
|
if (!src.empty())
|
||||||
|
{
|
||||||
|
ResourceId id = ResourceManager::instance().getId(src);
|
||||||
|
return parse<model::TileSet>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read attributes
|
||||||
|
model::TileSet* tileSet = new model::TileSet();
|
||||||
|
|
||||||
|
std::string texPath = root.get<std::string>("<xmlattr>.texture");
|
||||||
|
tileSet->texture = resources::ResourceManager::instance().getId(texPath);
|
||||||
|
tileSet->tileWidth = root.get<size_t>("<xmlattr>.tileWidth");
|
||||||
|
tileSet->tileHeight = root.get<size_t>("<xmlattr>.tileHeight");
|
||||||
|
|
||||||
|
// Get image size
|
||||||
|
int w, h;
|
||||||
|
SDL_Texture* sdlTex = ResourceManager::instance().texture(tileSet->texture);
|
||||||
|
graphics::backend::SdlRenderer::instance().getTextureSize(sdlTex, &w, &h);
|
||||||
|
tileSet->width = w;
|
||||||
|
tileSet->height = h;
|
||||||
|
|
||||||
|
return tileSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
#ifndef STORAGE_PARSERS_PARSERS_H_
|
#ifndef STORAGE_PARSERS_PARSERS_H_
|
||||||
#define STORAGE_PARSERS_PARSERS_H_
|
#define STORAGE_PARSERS_PARSERS_H_
|
||||||
|
|
||||||
#include <components/Background.h>
|
|
||||||
#include <components/basic/Camera.h>
|
#include <components/basic/Camera.h>
|
||||||
|
#include <components/basic/Grid.h>
|
||||||
#include <components/basic/Sprite.h>
|
#include <components/basic/Sprite.h>
|
||||||
#include <components/basic/Transform.h>
|
#include <components/basic/Transform.h>
|
||||||
#include <components/DebugController.h>
|
#include <components/DebugController.h>
|
||||||
@ -21,14 +21,15 @@
|
|||||||
#include <components/items/Scythe.h>
|
#include <components/items/Scythe.h>
|
||||||
#include <components/items/WateringCan.h>
|
#include <components/items/WateringCan.h>
|
||||||
#include <components/items/Weapon.h>
|
#include <components/items/Weapon.h>
|
||||||
|
#include <components/Map.h>
|
||||||
#include <components/player/PlayerInventory.h>
|
#include <components/player/PlayerInventory.h>
|
||||||
#include <components/player/PlayerMovement.h>
|
#include <components/player/PlayerMovement.h>
|
||||||
#include <graphics/BackgroundRenderer.h>
|
#include <graphics/MapRenderer.h>
|
||||||
#include <graphics/SpriteRenderer.h>
|
#include <graphics/SpriteRenderer.h>
|
||||||
|
|
||||||
#include <model/GameObject.h>
|
#include <model/GameObject.h>
|
||||||
#include <model/Configuration.h>
|
#include <model/Configuration.h>
|
||||||
#include <model/Scene.h>
|
#include <model/Scene.h>
|
||||||
|
#include <model/TileSet.h>
|
||||||
|
|
||||||
#include <storage/Parse.h>
|
#include <storage/Parse.h>
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ namespace storage {
|
|||||||
/****** Components ******/
|
/****** Components ******/
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
components::Background* parse<components::Background> (boost::property_tree::ptree& root);
|
components::Map* parse<components::Map> (boost::property_tree::ptree& root);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
components::basic::Camera* parse<components::basic::Camera> (boost::property_tree::ptree& root);
|
components::basic::Camera* parse<components::basic::Camera> (boost::property_tree::ptree& root);
|
||||||
@ -46,6 +47,9 @@ namespace storage {
|
|||||||
template <>
|
template <>
|
||||||
components::basic::Frame* parse<components::basic::Frame> (boost::property_tree::ptree& root);
|
components::basic::Frame* parse<components::basic::Frame> (boost::property_tree::ptree& root);
|
||||||
|
|
||||||
|
template <>
|
||||||
|
components::basic::Grid* parse<components::basic::Grid> (boost::property_tree::ptree& root);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tree::ptree& root);
|
components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tree::ptree& root);
|
||||||
|
|
||||||
@ -92,7 +96,7 @@ namespace storage {
|
|||||||
/****** Graphics ******/
|
/****** Graphics ******/
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
graphics::BackgroundRenderer* parse<graphics::BackgroundRenderer> (boost::property_tree::ptree& root);
|
graphics::MapRenderer* parse<graphics::MapRenderer> (boost::property_tree::ptree& root);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
graphics::SpriteRenderer* parse<graphics::SpriteRenderer> (boost::property_tree::ptree& root);
|
graphics::SpriteRenderer* parse<graphics::SpriteRenderer> (boost::property_tree::ptree& root);
|
||||||
@ -109,6 +113,9 @@ namespace storage {
|
|||||||
template <>
|
template <>
|
||||||
model::Scene* parse<model::Scene> (boost::property_tree::ptree& root);
|
model::Scene* parse<model::Scene> (boost::property_tree::ptree& root);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
model::TileSet* parse<model::TileSet> (boost::property_tree::ptree& root);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#define BASE_ICLONEABLE_H_
|
#define BASE_ICLONEABLE_H_
|
||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace model {
|
namespace utils {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ICloneable
|
class ICloneable
|
@ -9,7 +9,7 @@
|
|||||||
#define BASE_INONASSIGNABLE_H_
|
#define BASE_INONASSIGNABLE_H_
|
||||||
|
|
||||||
namespace farmlands {
|
namespace farmlands {
|
||||||
namespace model {
|
namespace utils {
|
||||||
|
|
||||||
class INonAssignable
|
class INonAssignable
|
||||||
{
|
{
|
265
src/utils/QTree.h
Normal file
265
src/utils/QTree.h
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* QTree.h
|
||||||
|
*
|
||||||
|
* Created on: Dec 4, 2016
|
||||||
|
* Author: tibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTILS_QTREE_H_
|
||||||
|
#define UTILS_QTREE_H_
|
||||||
|
|
||||||
|
#include <utils/Assert.h>
|
||||||
|
#include <utils/INonAssignable.h>
|
||||||
|
#include <utils/Rect.h>
|
||||||
|
|
||||||
|
namespace farmlands {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Commented because no longer needed.
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct QTreeItem
|
||||||
|
{
|
||||||
|
T data;
|
||||||
|
float x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quad tree
|
||||||
|
*/
|
||||||
|
template <typename T, size_t Capacity>
|
||||||
|
class QTree : public INonAssignable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef int iterator;
|
||||||
|
|
||||||
|
QTree(const RectF& bounds);
|
||||||
|
virtual ~QTree();
|
||||||
|
|
||||||
|
// Container operations
|
||||||
|
iterator begin();
|
||||||
|
iterator end();
|
||||||
|
|
||||||
|
bool empty() const;
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
void insert(T element, float x, float y);
|
||||||
|
void erase(iterator it);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
iterator find(T element);
|
||||||
|
iterator find(float x, float y);
|
||||||
|
|
||||||
|
iterator lower_bound(float x, float y);
|
||||||
|
iterator lower_bound(float x, float y, float distance);
|
||||||
|
iterator lower_bound(const RectF& area);
|
||||||
|
|
||||||
|
iterator upper_bound(float x, float y);
|
||||||
|
iterator upper_bound(float x, float y, float distance);
|
||||||
|
iterator upper_bound(const RectF& area);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void subdivide();
|
||||||
|
void merge();
|
||||||
|
|
||||||
|
RectF m_bounds;
|
||||||
|
bool m_isSplit;
|
||||||
|
QTree* m_children[4];
|
||||||
|
QTreeItem m_items[Capacity];
|
||||||
|
size_t m_itemsCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
QTree<T, Capacity>::QTree(const RectF& bounds)
|
||||||
|
: m_bounds(bounds),
|
||||||
|
m_isSplit(false),
|
||||||
|
m_children(),
|
||||||
|
m_items(),
|
||||||
|
m_itemsCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
QTree<T, Capacity>::~QTree()
|
||||||
|
{
|
||||||
|
if (m_isSplit)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
delete m_children[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::begin()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::end()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline bool QTree<T, Capacity>::empty() const
|
||||||
|
{
|
||||||
|
return (m_itemsCount == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline size_t QTree<T, Capacity>::size() const
|
||||||
|
{
|
||||||
|
return m_itemsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline void QTree<T, Capacity>::insert(T element, float x, float y)
|
||||||
|
{
|
||||||
|
Assert(m_bounds.contains(x, y), "Can't add element outside bounds.");
|
||||||
|
|
||||||
|
// Not split case
|
||||||
|
if (!m_isSplit && m_itemsCount >= Capacity)
|
||||||
|
subdivide();
|
||||||
|
|
||||||
|
// If split, add element in one of the subtrees
|
||||||
|
if (m_isSplit)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
if (m_children[i]->m_bounds.contains(x, y))
|
||||||
|
{
|
||||||
|
m_children[i]->insert(element, x, y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QTreeItem<T> item =
|
||||||
|
{
|
||||||
|
.data = element,
|
||||||
|
.x = x,
|
||||||
|
.y = y
|
||||||
|
};
|
||||||
|
|
||||||
|
m_items[m_itemsCount] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_itemsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline void QTree<T, Capacity>::erase(iterator it)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline void QTree<T, Capacity>::clear()
|
||||||
|
{
|
||||||
|
if (m_isSplit)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
delete m_children[i];
|
||||||
|
m_isSplit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_itemsCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::find(T element)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::find(float x, float y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::lower_bound(float x, float y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::lower_bound(float x, float y, float distance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::lower_bound(const RectF& area)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::upper_bound(float x, float y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::upper_bound(float x, float y, float distance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::upper_bound(const RectF& area)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
void QTree<T, Capacity>::subdivide()
|
||||||
|
{
|
||||||
|
Assert(!m_isSplit, "Can't subdivide if already subdivided!");
|
||||||
|
|
||||||
|
float halfW = m_bounds.w / 2;
|
||||||
|
float halfH = m_bounds.h / 2;
|
||||||
|
|
||||||
|
RectF rects[4] =
|
||||||
|
{
|
||||||
|
{ m_bounds.x, m_bounds.y, halfW, halfH },
|
||||||
|
{ m_bounds.x + halfW, m_bounds.y, halfW, halfH },
|
||||||
|
{ m_bounds.x, m_bounds.y + halfH, halfW, halfH },
|
||||||
|
{ m_bounds.x + halfW, m_bounds.y + halfH, halfW, halfH },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allocate subtrees
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
m_children[i] = new QTree<T, Capacity>(rects[i]);
|
||||||
|
|
||||||
|
// Set split flag
|
||||||
|
m_isSplit = true;
|
||||||
|
|
||||||
|
// Re-insert all the children
|
||||||
|
size_t itemsCount = m_itemsCount;
|
||||||
|
m_itemsCount = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < itemsCount; i++)
|
||||||
|
insert(m_items[i].data, m_items[i].x, m_items[i].y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t Capacity>
|
||||||
|
void QTree<T, Capacity>::merge()
|
||||||
|
{
|
||||||
|
Assert(m_isSplit, "Can't merge if not subdivided!");
|
||||||
|
|
||||||
|
// Unset split flag
|
||||||
|
m_isSplit = false;
|
||||||
|
|
||||||
|
// Put all the children in their places
|
||||||
|
m_itemsCount = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
Assert(!m_children[i].m_isSplit, "Cannot merge if children are split!!!");
|
||||||
|
|
||||||
|
for (size_t j = 0; j < m_children[i].m_itemsCount; j++)
|
||||||
|
insert(m_children[i].m_items[j].data, m_children[i].m_items[j].x, m_children[i].m_items[j].y);
|
||||||
|
|
||||||
|
delete m_children[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} /* namespace utils */
|
||||||
|
} /* namespace farmlands */
|
||||||
|
|
||||||
|
#endif /* UTILS_QTREE_H_ */
|
50
src/utils/Rect.h
Normal file
50
src/utils/Rect.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Rect.h
|
||||||
|
*
|
||||||
|
* Created on: Dec 4, 2016
|
||||||
|
* Author: tibi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTILS_RECT_H_
|
||||||
|
#define UTILS_RECT_H_
|
||||||
|
|
||||||
|
namespace farmlands {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Rect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
Rect()
|
||||||
|
: x(), y(), w(), h() { }
|
||||||
|
|
||||||
|
Rect(T x, T y, T w, T h)
|
||||||
|
: x(x), y(y), w(w), h(h) { }
|
||||||
|
|
||||||
|
bool contains(T px, T py)
|
||||||
|
{
|
||||||
|
bool containsX = (x <= px && px <= x + w);
|
||||||
|
bool containsY = (y <= px && px <= x + w);
|
||||||
|
|
||||||
|
return containsX && containsY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool intersects(const Rect<T> other)
|
||||||
|
{
|
||||||
|
bool intersectsX = (x <= other.x && other.x <= x + w) || (other.x <= x && other.x + other.w >= x);
|
||||||
|
bool intersectsY = (y <= other.y && other.y <= y + h) || (other.y <= y && other.y + other.h >= y);
|
||||||
|
|
||||||
|
return intersectsX && intersectsY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values
|
||||||
|
T x, y, w, h;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Rect<float> RectF;
|
||||||
|
|
||||||
|
} /* namespace utils */
|
||||||
|
} /* namespace farmlands */
|
||||||
|
|
||||||
|
#endif /* UTILS_RECT_H_ */
|
Loading…
Reference in New Issue
Block a user