Last active
July 16, 2016 02:21
-
-
Save MORTAL2000/896ea24c907923f9a578fa2fa9296a8c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SFML/Graphics.hpp> | |
#include <iostream> | |
#include <iomanip> | |
#include <array> | |
#include <vector> | |
#include <utility> | |
#include <queue> | |
#include <tuple> | |
#include <set> | |
#include <algorithm> | |
#include <random> | |
#include <cassert> | |
namespace sf | |
{ | |
template <typename T> | |
inline bool operator < (const Vector2<T>& left, const Vector2<T>& right) | |
{ | |
return (left.x < right.x) || ((left.x == right.x) && (left.y < right.y)); | |
} | |
template <typename T> | |
inline bool operator > (const Vector2<T>& left, const Vector2<T>& right) | |
{ | |
return (left.x > right.x) || ((left.x == right.x) && (left.y > right.y)); | |
} | |
template <typename T> | |
inline Vector2<T> operator / (const Vector2<T>& left, const Vector2<T>& right) | |
{ | |
if (right.x == 0 || right.y == 0 ) return left; | |
T x = left.x / right.x; | |
T y = left.y / right.y; | |
return {x, y}; | |
} | |
template <typename T, typename U> | |
inline Vector2<T>& operator +=(Vector2<T>& left, const Vector2<U>& right) | |
{ | |
left.x += right.x; | |
left.y += right.y; | |
return left; | |
} | |
template <typename T, typename U> | |
inline Vector2<T>& operator -=(Vector2<T>& left, const Vector2<U>& right) | |
{ | |
left.x -= right.x; | |
left.y -= right.y; | |
return left; | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator +(const Vector2<T>& left, const Vector2<U>& right) | |
{ | |
return Vector2<T>(left.x + right.x, left.y + right.y); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator +(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x + right, left.y + right); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator -(const Vector2<T>& left, const Vector2<U>& right) | |
{ | |
return Vector2<T>(left.x - right.x, left.y - right.y); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator -(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x - right, left.y - right); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator *(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x * right, left.y * right); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator *(T left, const Vector2<U>& right) | |
{ | |
return Vector2<T>(right.x * left, right.y * left); | |
} | |
template <typename T, typename U> | |
inline Vector2<T>& operator *=(Vector2<T>& left, U right) | |
{ | |
left.x *= right; | |
left.y *= right; | |
return left; | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator /(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x / right, left.y / right); | |
} | |
template <typename T, typename U> | |
inline Vector2<T>& operator /=(Vector2<T>& left, U right) | |
{ | |
left.x /= right; | |
left.y /= right; | |
return left; | |
} | |
} | |
template <typename T> | |
std::ostream& operator<<(std::ostream& out, sf::Vector2<T> v) | |
{ | |
out << '(' << v.x << ',' << v.y <<')'; | |
return out; | |
} | |
std::ostream& operator<<(std::ostream& out, sf::Color c) | |
{ | |
out << '(' << (int)c.r << ',' << (int)c.b << ',' << (int)c.g<< ')'; | |
return out; | |
} | |
std::vector<sf::Vertex> | |
make_outLines(unsigned width, unsigned height, float size, | |
const sf::Color& color=sf::Color{139,137,137}) | |
{ | |
std::vector<sf::Vertex> vertices((width + height + 2) * 2); | |
static const auto e = 0.001f; | |
// make vertical lines | |
for (unsigned i = 0; i <= width; ++i) { | |
const auto& line = &vertices[i * 2]; | |
line[0].position = {((i==0) ? i+e : i) * size, 0}; | |
line[1].position = {((i==0) ? i+e : i) * size, height * size}; | |
line[0].color = line[1].color = color; | |
} | |
// make horizontal lines | |
for (unsigned i = 0; i <= height; ++i) { | |
const auto& line = &vertices[(i + width + 1) * 2]; | |
line[0].position = {0, ((i==height) ? i-e : i) * size}; | |
line[1].position = {width * size, ((i==height) ? i-e : i) * size}; | |
line[0].color = line[1].color = color; | |
} | |
return vertices; | |
} | |
//std::vector<int> make_grid(unsigned cols, unsigned rows) | |
//{ | |
// | |
// unsigned RCvertices=2*cols*(rows-1); | |
// unsigned TSvertices=2*cols*(rows-1)+2*(rows-2); | |
// unsigned numVertices=TSvertices; | |
// std::vector<int> trianglestrip(numVertices); | |
// unsigned j=0; | |
// for(unsigned i = 1; i <= RCvertices; i += 2) | |
// { | |
// trianglestrip[ j ] = (1 +i)/2; | |
// trianglestrip[ j +1 ] = (cols*2 + i + 1) / 2; | |
// if( trianglestrip[ j +1 ] % cols == 0) | |
// { | |
// if( trianglestrip[ j +1 ] != cols && trianglestrip[ j +1 ] != cols*rows ) | |
// { | |
// trianglestrip[ j +2 ] = trianglestrip[ j +1 ]; | |
// trianglestrip[ j +3 ] = (1 + i + 2) / 2; | |
// j += 2; | |
// } | |
// } | |
// j += 2; | |
// } | |
// return trianglestrip; | |
//} | |
class Grid final : public sf::Drawable, public sf::Transformable | |
{ | |
class Cell | |
{ | |
public: | |
explicit Cell(const sf::Vector2i& offset,float size, const sf::Color& color) | |
{ | |
// quad[0].position = { coord.x * size, coord.y * size}; | |
// | |
// quad[1].position = { coord.x * size, (coord.y + 1) * size}; | |
// quad[2].position = {(coord.x + 1) * size, coord.y * size}; | |
// | |
//// quad[3].position = { coord.x * size, (coord.y + 1) * size}; | |
//// quad[4].position = {(coord.x + 1) * size, coord.y * size}; | |
// | |
//// quad[3].position = { (coord.x + 1) * size, (coord.y ) * size}; | |
//// quad[4].position = {(coord.x ) * size, (coord.y + 1) * size}; | |
// | |
// quad[3].position = {(coord.x + 1) * size, (coord.y + 1) * size}; | |
// | |
// //for (auto& v : quad) { v.color = color;} | |
// quad[0].color = quad[3].color = sf::Color::Blue; | |
// quad[1].color = sf::Color::Green; | |
// quad[2].color = sf::Color::Red; | |
// Stip | |
// quad[0] = {{ coord.x * size, coord.y * size}, sf::Color::Blue}; | |
// | |
// quad[1] = {{ coord.x * size, (coord.y + 1) * size}, sf::Color::Green}; | |
// quad[2] = {{(coord.x + 1) * size, coord.y * size}, sf::Color::Red}; | |
// | |
//// quad[3] = {{ coord.x * size, (coord.y + 1) * size}, sf::Color::Green}; | |
//// quad[4] = {{(coord.x + 1) * size, coord.y * size}, sf::Color::Red}; | |
// quad[3] = {{(coord.x + 1) * size, (coord.y + 1) * size}, sf::Color::Blue}; | |
// // fan | |
// quad[0] = {sf::Vector2f{(offset.x + 1) * 0.5f, (offset.y + 1) * 0.5f} * size, sf::Color::Black}; // center for all | |
// | |
// quad[1] = {sf::Vector2f{ offset.x, offset.y } * size, sf::Color::Green}; | |
// quad[2] = {sf::Vector2f{(offset.x + 1), offset.y } * size, sf::Color::Red}; | |
// | |
// quad[3] = {sf::Vector2f{(offset.x + 1), offset.y } * size, sf::Color::Green}; | |
// quad[4] = {sf::Vector2f{(offset.x + 1), (offset.y + 1) } * size, sf::Color::Red}; | |
// | |
// quad[5] = {sf::Vector2f{(offset.x + 1), (offset.y + 1) } * size, sf::Color::Green}; | |
// quad[6] = {sf::Vector2f{ offset.x, (offset.y + 1) } * size, sf::Color::Red}; | |
// | |
// quad[7] = {sf::Vector2f{ offset.x, offset.y } * size, sf::Color::Green}; | |
// quad[8] = {sf::Vector2f{ offset.x, (offset.y + 1) } * size, sf::Color::Red}; | |
// Triangles | |
quad[0] = {sf::Vector2f( offset.x, offset.y ) * size, sf::Color::Blue}; | |
quad[1] = {sf::Vector2f((offset.x + 1), offset.y ) * size, sf::Color::Green}; | |
quad[2] = {sf::Vector2f( offset.x, (offset.y + 1)) * size, sf::Color::Red}; | |
quad[3] = {sf::Vector2f((offset.x + 1), offset.y ) * size, sf::Color::Blue}; | |
quad[4] = {sf::Vector2f((offset.x + 1), (offset.y + 1)) * size, sf::Color::Green}; | |
quad[5] = {sf::Vector2f( offset.x, (offset.y + 1)) * size, sf::Color::Red}; | |
} | |
void setFillColor(const sf::Color& color) const | |
{ | |
for (auto& v : quad) { v.color = color;} | |
} | |
const sf::Color& getFillColor() const | |
{ | |
return quad[0].color; | |
} | |
sf::Vector2i getPosition() const | |
{ | |
return static_cast<const sf::Vector2i>(quad[0].position); | |
} | |
const sf::Vertex* data() const | |
{ | |
return quad.data(); | |
} | |
unsigned size() const | |
{ | |
return quad.size(); | |
} | |
friend std::ostream& operator<<(std::ostream& out, Cell c) | |
{ | |
out << " " | |
<< c.quad[0].position << "\n " << c.quad[1].position << " " | |
<< c.quad[2].position << "\n " | |
// << c.quad[3].position << ' ' | |
// << c.quad[4].position << "\n" | |
<< c.quad[3].position << "\n " | |
<< c.quad[0].color << ' ' << c.quad[1].color << "\n " | |
<< c.quad[3].color << ' ' << c.quad[2].color << "\n"; | |
return out; | |
} | |
private: | |
mutable std::array<sf::Vertex, 6> quad; | |
}; | |
public: | |
explicit Grid(int width, int height, float tile_size, const sf::Color& color) | |
: grid{} | |
, outlines{make_outLines((int)std::floor(width/tile_size), (int)std::floor(height/tile_size), tile_size)} | |
{ | |
const auto numOfCellPerRow = (int)std::floor(width/tile_size); | |
const auto numberOfCelles = numOfCellPerRow * (int)std::floor(height/tile_size); | |
grid.reserve(numberOfCelles); | |
for (int i = 0; i < numberOfCelles; ++i) | |
{ | |
sf::Vector2i offset((int)std::floor(i % numOfCellPerRow), (int)std::floor(i / numOfCellPerRow)); | |
grid.emplace_back(offset, tile_size, color); | |
} | |
} | |
Cell& operator[](unsigned index) {return grid[index];} | |
const Cell& operator[](unsigned index) const {return grid[index];} | |
std::vector<Cell>::iterator begin() {return grid.begin();} | |
std::vector<Cell>::iterator end() {return grid.end();} | |
private: | |
void draw(sf::RenderTarget& target, sf::RenderStates states) const | |
{ | |
// const auto& transform = getTransform(); | |
// states.transform *= transform; | |
static const auto grid_size = grid[0].size()*grid.size(); | |
static const auto outlines_size = outlines.size(); | |
static const auto& outlines_cache = outlines.data(); | |
target.draw(grid[0].data(), grid_size, sf::Triangles, states); | |
target.draw(outlines_cache, outlines_size, sf::Lines, states); | |
} | |
private: | |
std::vector<Cell> grid; | |
std::vector<sf::Vertex> outlines; | |
}; | |
void pollEvent(sf::RenderWindow& window) | |
{ | |
sf::Event event; | |
while (window.pollEvent(event)) | |
{ | |
if (event.type == sf::Event::Closed) | |
window.close(); | |
} | |
} | |
int main() | |
{ | |
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!"); | |
int numOfCellPerRow = 6; | |
int tile_size = window.getSize().x/numOfCellPerRow; | |
//sf::View view = window.getDefaultView(); | |
//view.zoom(2.f); | |
//window.setView(view); | |
//int tile_size = window.getSize().x/4; | |
// Quads | |
std::vector<sf::Vertex> quad{ | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Yellow}}, | |
}; | |
// Triangles | |
std::vector<sf::Vertex> triangles{ | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Red}}, | |
}; | |
// Triangles Fan | |
std::vector<sf::Vertex> triangles_fan{ | |
{sf::Vector2f{0.5f, 0.5f} * tile_size, {sf::Color::Black}}, // center for all | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Red}}, | |
}; | |
//Triangles Strip | |
std::vector<sf::Vertex> triangles_strip{ | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Green}}, // shared vertices | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
// {sf::Vector2f{0, 1} * tile_size, {sf::Color::Green}}, | |
// {sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Blue}}, | |
}; | |
std::vector<sf::Vertex> triangles_strip_full{ | |
// top-left | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Blue}}, | |
// bottom-left | |
{sf::Vector2f{0, 0+1} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0, 1+1} * tile_size, {sf::Color::Green}}, // shared vertices | |
{sf::Vector2f{1, 0+1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0, 1+1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 0+1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 1+1} * tile_size, {sf::Color::Blue}}, | |
// top-right | |
{sf::Vector2f{0+1, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0+1, 1} * tile_size, {sf::Color::Green}}, // shared vertices | |
{sf::Vector2f{1+1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0+1, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1+1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1+1, 1} * tile_size, {sf::Color::Blue}}, | |
// bottom-right | |
{sf::Vector2f{0+1, 0+1} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0+1, 1+1} * tile_size, {sf::Color::Green}}, // shared vertices | |
{sf::Vector2f{1+1, 0+1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0+1, 1+1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1+1, 0+1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1+1, 1+1} * tile_size, {sf::Color::Blue}}, | |
}; | |
Grid grid(window.getSize().x, window.getSize().y, tile_size, sf::Color::Blue); | |
for(auto i : grid) std::cout << i << '\n'; | |
sf::Vector2f coord{1,1}; | |
grid[coord.y + (window.getSize().y/tile_size) * coord.x].setFillColor(sf::Color::Yellow); | |
while (window.isOpen()) | |
{ | |
pollEvent(window); | |
window.clear(); | |
// window.draw(quad.data(), quad.size(), sf::Quads); | |
// window.draw(triangles.data(), triangles.size(), sf::Triangles); | |
// window.draw(triangles_fan.data(), triangles_fan.size(), sf::TrianglesFan); | |
//window.draw(triangles_strip.data(), triangles_strip.size(), sf::TrianglesStrip); | |
//window.draw(triangles_strip_full.data(), triangles_strip_full.size(), sf::TrianglesStrip); | |
window.draw(grid); | |
window.display(); | |
} | |
try{ | |
// MapEditor editor; | |
// editor.run(); | |
} catch (std::runtime_error& e) | |
{ | |
std::cout << "Exception: " << e.what() << '\n'; | |
return 1; | |
} catch (std::out_of_range& e) | |
{ | |
std::cout << "Exception: " << e.what() << '\n'; | |
return 1; | |
} catch (...) | |
{ | |
std::cout << "Unknown Exception!\n"; | |
return 1; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SFML/Graphics.hpp> | |
#include <iostream> | |
#include <iomanip> | |
#include <array> | |
#include <vector> | |
#include <utility> | |
#include <queue> | |
#include <tuple> | |
#include <set> | |
#include <algorithm> | |
#include <random> | |
#include <cassert> | |
namespace sf | |
{ | |
template <typename T> | |
inline bool operator < (const Vector2<T>& left, const Vector2<T>& right) | |
{ | |
return (left.x < right.x) || ((left.x == right.x) && (left.y < right.y)); | |
} | |
template <typename T> | |
inline bool operator > (const Vector2<T>& left, const Vector2<T>& right) | |
{ | |
return (left.x > right.x) || ((left.x == right.x) && (left.y > right.y)); | |
} | |
template <typename T> | |
inline Vector2<T> operator / (const Vector2<T>& left, const Vector2<T>& right) | |
{ | |
if (right.x == 0 || right.y == 0 ) return left; | |
T x = left.x / right.x; | |
T y = left.y / right.y; | |
return {x, y}; | |
} | |
template <typename T, typename U> | |
inline Vector2<T>& operator +=(Vector2<T>& left, const Vector2<U>& right) | |
{ | |
left.x += right.x; | |
left.y += right.y; | |
return left; | |
} | |
template <typename T, typename U> | |
inline Vector2<T>& operator -=(Vector2<T>& left, const Vector2<U>& right) | |
{ | |
left.x -= right.x; | |
left.y -= right.y; | |
return left; | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator +(const Vector2<T>& left, const Vector2<U>& right) | |
{ | |
return Vector2<T>(left.x + right.x, left.y + right.y); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator -(const Vector2<T>& left, const Vector2<U>& right) | |
{ | |
return Vector2<T>(left.x - right.x, left.y - right.y); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator +(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x + right, left.y + right); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator -(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x - right, left.y - right); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator *(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x * right, left.y * right); | |
} | |
template <typename T, typename U> | |
inline Vector2<T>& operator *=(Vector2<T>& left, U right) | |
{ | |
left.x *= right; | |
left.y *= right; | |
return left; | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator /(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x / right, left.y / right); | |
} | |
template <typename T, typename U> | |
inline Vector2<T>& operator /=(Vector2<T>& left, U right) | |
{ | |
left.x /= right; | |
left.y /= right; | |
return left; | |
} | |
} | |
template <typename T> | |
std::ostream& operator<<(std::ostream& out, sf::Vector2<T> v) | |
{ | |
out << '(' << v.x << ',' << v.y <<')'; | |
return out; | |
} | |
std::ostream& operator<<(std::ostream& out, sf::Color c) | |
{ | |
out << '(' << (int)c.r << ',' << (int)c.b << ',' << (int)c.g<< ')'; | |
return out; | |
} | |
std::vector<sf::Vertex> | |
make_outLines(unsigned width, unsigned height, float size, | |
const sf::Color& color=sf::Color{139,137,137}) | |
{ | |
std::vector<sf::Vertex> vertices((width + height + 2) * 2); | |
static const auto e = 0.001f; | |
// make vertical lines | |
for (unsigned i = 0; i <= width; ++i) { | |
const auto& line = &vertices[i * 2]; | |
line[0].position = {((i==0) ? i+e : i) * size, 0}; | |
line[1].position = {((i==0) ? i+e : i) * size, height * size}; | |
line[0].color = line[1].color = color; | |
} | |
// make horizontal lines | |
for (unsigned i = 0; i <= height; ++i) { | |
const auto& line = &vertices[(i + width + 1) * 2]; | |
line[0].position = {0, ((i==height) ? i-e : i) * size}; | |
line[1].position = {width * size, ((i==height) ? i-e : i) * size}; | |
line[0].color = line[1].color = color; | |
} | |
return vertices; | |
} | |
//std::vector<int> make_grid(unsigned cols, unsigned rows) | |
//{ | |
// | |
// unsigned RCvertices=2*cols*(rows-1); | |
// unsigned TSvertices=2*cols*(rows-1)+2*(rows-2); | |
// unsigned numVertices=TSvertices; | |
// std::vector<int> trianglestrip(numVertices); | |
// unsigned j=0; | |
// for(unsigned i = 1; i <= RCvertices; i += 2) | |
// { | |
// trianglestrip[ j ] = (1 +i)/2; | |
// trianglestrip[ j +1 ] = (cols*2 + i + 1) / 2; | |
// if( trianglestrip[ j +1 ] % cols == 0) | |
// { | |
// if( trianglestrip[ j +1 ] != cols && trianglestrip[ j +1 ] != cols*rows ) | |
// { | |
// trianglestrip[ j +2 ] = trianglestrip[ j +1 ]; | |
// trianglestrip[ j +3 ] = (1 + i + 2) / 2; | |
// j += 2; | |
// } | |
// } | |
// j += 2; | |
// } | |
// return trianglestrip; | |
//} | |
class Grid final : public sf::Drawable | |
{ | |
class Cell | |
{ | |
public: | |
explicit Cell(const sf::Vector2i& offset, float size, const sf::Color& color) | |
{ | |
quad[0] = {sf::Vector2f( offset.x, offset.y ) * size, color}; | |
quad[1] = {sf::Vector2f((offset.x + 1), offset.y ) * size, color}; | |
quad[2] = {sf::Vector2f( offset.x, (offset.y + 1)) * size, color}; | |
quad[3] = {sf::Vector2f((offset.x + 1), offset.y ) * size, color}; | |
quad[4] = {sf::Vector2f((offset.x + 1), (offset.y + 1)) * size, color}; | |
quad[5] = {sf::Vector2f( offset.x, (offset.y + 1)) * size, color}; | |
} | |
void setFillColor(const sf::Color& color) const | |
{ | |
for (auto& v : quad) { v.color = color;} | |
} | |
const sf::Color& getFillColor() const | |
{ | |
return quad[0].color; | |
} | |
sf::Vector2i getPosition() const | |
{ | |
return static_cast<const sf::Vector2i>(quad[0].position); | |
} | |
const sf::Vertex* data() const | |
{ | |
return quad.data(); | |
} | |
unsigned size() const | |
{ | |
return quad.size(); | |
} | |
friend std::ostream& operator<<(std::ostream& out, Cell c) | |
{ | |
out << " " | |
<< c.quad[0].position << " " << c.quad[1].position << " " | |
<< c.quad[3].position << "\n " | |
<< c.quad[2].position << " " << c.quad[4].position << " " | |
<< c.quad[3].position << "\n " | |
<< "\n " | |
<< c.quad[0].color << " " << c.quad[1].color << " " | |
<< c.quad[3].color << "\n " | |
<< c.quad[2].color << " " << c.quad[4].color << " " | |
<< c.quad[3].color << "\n"; | |
return out; | |
} | |
private: | |
mutable std::array<sf::Vertex, 6> quad; | |
}; | |
public: | |
explicit Grid(int width, int height, float tile_size, const sf::Color& color) | |
: grid{} | |
, outlines{make_outLines(width, height, tile_size)} | |
{ | |
const auto numberOfCelles = width * height; | |
grid.reserve(numberOfCelles); | |
for (int i = 0; i < numberOfCelles; ++i) | |
{ | |
sf::Vector2i offset(i % width, i / width); | |
grid.emplace_back(offset, tile_size, color); | |
} | |
} | |
Cell& operator[](unsigned index) {return grid[index];} | |
const Cell& operator[](unsigned index) const {return grid[index];} | |
std::vector<Cell>::iterator begin() {return grid.begin();} | |
std::vector<Cell>::iterator end() {return grid.end();} | |
private: | |
void draw(sf::RenderTarget& target, sf::RenderStates states) const | |
{ | |
static const auto grid_size = grid[0].size()*grid.size(); | |
static const auto outlines_size = outlines.size(); | |
static const auto& outlines_cache = outlines.data(); | |
target.draw(grid[0].data(), grid_size, sf::Triangles, states); | |
target.draw(outlines_cache, outlines_size, sf::Lines, states); | |
} | |
private: | |
std::vector<Cell> grid; | |
std::vector<sf::Vertex> outlines; | |
}; | |
void pollEvent(sf::RenderWindow& window) | |
{ | |
sf::Event event; | |
while (window.pollEvent(event)) | |
{ | |
if (event.type == sf::Event::Closed) | |
window.close(); | |
} | |
} | |
Grid make_grid(sf::Vector2u windowSize, float numOfCellPerRow) | |
{ | |
float tileSize = windowSize.x/numOfCellPerRow; | |
Grid grid(numOfCellPerRow, numOfCellPerRow, tileSize, sf::Color::Blue); | |
return grid; | |
} | |
int main() | |
{ | |
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!"); | |
float numOfCellPerRow = 6; | |
float tile_size = window.getSize().x/numOfCellPerRow; | |
//sf::View view = window.getDefaultView(); | |
//view.zoom(2.f); | |
//window.setView(view); | |
//int tile_size = window.getSize().x/4; | |
// Quads | |
std::vector<sf::Vertex> quad{ | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Yellow}}, | |
}; | |
// Triangles | |
std::vector<sf::Vertex> triangles{ | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Red}}, | |
}; | |
// Triangles Fan | |
std::vector<sf::Vertex> triangles_fan{ | |
{sf::Vector2f{0.5f, 0.5f} * tile_size, {sf::Color::Black}}, // center for all | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Red}}, | |
}; | |
//Triangles Strip | |
std::vector<sf::Vertex> triangles_strip{ | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Green}}, // shared vertices | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
// {sf::Vector2f{0, 1} * tile_size, {sf::Color::Green}}, | |
// {sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Blue}}, | |
}; | |
std::vector<sf::Vertex> triangles_strip_full{ | |
// top-left | |
{sf::Vector2f{0, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 1} * tile_size, {sf::Color::Blue}}, | |
// bottom-left | |
{sf::Vector2f{0, 0+1} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0, 1+1} * tile_size, {sf::Color::Green}}, // shared vertices | |
{sf::Vector2f{1, 0+1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0, 1+1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1, 0+1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1, 1+1} * tile_size, {sf::Color::Blue}}, | |
// top-right | |
{sf::Vector2f{0+1, 0} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0+1, 1} * tile_size, {sf::Color::Green}}, // shared vertices | |
{sf::Vector2f{1+1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0+1, 1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1+1, 0} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1+1, 1} * tile_size, {sf::Color::Blue}}, | |
// bottom-right | |
{sf::Vector2f{0+1, 0+1} * tile_size, {sf::Color::Blue}}, | |
{sf::Vector2f{0+1, 1+1} * tile_size, {sf::Color::Green}}, // shared vertices | |
{sf::Vector2f{1+1, 0+1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{0+1, 1+1} * tile_size, {sf::Color::Green}}, | |
{sf::Vector2f{1+1, 0+1} * tile_size, {sf::Color::Red}}, | |
{sf::Vector2f{1+1, 1+1} * tile_size, {sf::Color::Blue}}, | |
}; | |
Grid grid = make_grid(window.getSize(),6); | |
sf::Vector2i coord{1, 1}; | |
std::cout << grid[coord.x + 5 * coord.y] ; | |
grid[coord.x + 6 * coord.y].setFillColor(sf::Color::Yellow); | |
while (window.isOpen()) | |
{ | |
pollEvent(window); | |
window.clear(); | |
// window.draw(quad.data(), quad.size(), sf::Quads); | |
// window.draw(triangles.data(), triangles.size(), sf::Triangles); | |
// window.draw(triangles_fan.data(), triangles_fan.size(), sf::TrianglesFan); | |
//window.draw(triangles_strip.data(), triangles_strip.size(), sf::TrianglesStrip); | |
//window.draw(triangles_strip_full.data(), triangles_strip_full.size(), sf::TrianglesStrip); | |
window.draw(grid); | |
window.display(); | |
} | |
try{ | |
// MapEditor editor; | |
// editor.run(); | |
} catch (std::runtime_error& e) | |
{ | |
std::cout << "Exception: " << e.what() << '\n'; | |
return 1; | |
} catch (std::out_of_range& e) | |
{ | |
std::cout << "Exception: " << e.what() << '\n'; | |
return 1; | |
} catch (...) | |
{ | |
std::cout << "Unknown Exception!\n"; | |
return 1; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// hex | |
#include <iostream> | |
#include <vector> | |
#include <SFML/Graphics.hpp> | |
bool isMouseContainsHexagaon(sf::CircleShape& cell, sf::Vector2f passed_mousePos, std::vector<sf::Vector2f>& points) | |
{ | |
points.clear(); | |
bool is_contain = false; | |
const auto& transform = cell.getTransform(); | |
for (unsigned i = 0; i < cell.getPointCount(); ++i){ | |
points.emplace_back(transform.transformPoint(cell.getPoint(i))); | |
} | |
for (unsigned i = 0; i < points.size(); i++) | |
{ | |
unsigned j = ((i + points.size() - 1)%points.size()); | |
//std::cout << i << ' ' << j << ' ' << ((i + points.size() -1)%points.size())<< '\n';//getchar(); | |
bool b1 = (points[i].y > passed_mousePos.y); | |
bool b2 = (points[j].y > passed_mousePos.y); | |
float vX = (points[j].x - points[i].x); | |
float vY = (points[j].y - points[i].y); | |
float ratio = (vX / vY); | |
float vmx = (passed_mousePos.x - points[i].x); | |
float vmy =(passed_mousePos.y - points[i].y) * ratio; | |
if (b1 != b2 && (vmx > vmy)) { | |
is_contain = !is_contain; | |
} | |
} | |
return is_contain; | |
} | |
int main() | |
{ | |
sf::RenderWindow window(sf::VideoMode(800, 600), "Hexgrid Example"); | |
sf::CircleShape hexagon; | |
hexagon.setRadius(window.getSize().x / 16.f); | |
hexagon.setPointCount(6); | |
hexagon.setFillColor(sf::Color(150, 50, 250)); | |
hexagon.setOutlineThickness(2); | |
hexagon.setOutlineColor(sf::Color(250, 150, 100)); | |
hexagon.setOrigin(hexagon.getGlobalBounds().width / 2.f, hexagon.getGlobalBounds().height / 2.f); | |
std::vector<sf::CircleShape> grid; | |
std::vector<sf::Vector2f> points; | |
points.reserve(6); | |
float xpos = 0, ypos = 0; | |
for (int y = 0; y < 12; y++) | |
{ | |
if (y == 0) | |
{ | |
ypos = y * hexagon.getGlobalBounds().height; | |
} | |
else | |
{ | |
ypos = ypos + (hexagon.getGlobalBounds().height - (hexagon.getGlobalBounds().height * 0.25f)); | |
} | |
for (int x = 0; x < 12; x++) | |
{ | |
if (y % 2 == 0) | |
{ | |
xpos = x * hexagon.getGlobalBounds().width; | |
} | |
else | |
{ | |
xpos = (x * hexagon.getGlobalBounds().width) + (hexagon.getGlobalBounds().width * 0.5f); | |
} | |
hexagon.setPosition(xpos, ypos); | |
grid.push_back(hexagon); | |
} | |
} | |
while (window.isOpen()) | |
{ | |
sf::Event e; | |
while (window.pollEvent(e)) | |
{ | |
if (e.type == sf::Event::Closed) | |
{ | |
window.close(); | |
} | |
if (e.type == sf::Event::MouseMoved) | |
{ | |
std::cout << e.mouseMove.x << ' ' << e.mouseMove.y << '\n'; | |
for (auto& c : grid) | |
{ | |
if (isMouseContainsHexagaon(c, sf::Vector2f(e.mouseMove.x, e.mouseMove.y), points)) | |
{ | |
c.setFillColor(sf::Color(255, 255, 255)); | |
} | |
else | |
{ | |
c.setFillColor(sf::Color(150, 50, 250)); | |
} | |
} | |
} | |
} | |
// const auto& position = sf::Mouse::getPosition(window); | |
// const auto& cov = window.mapPixelToCoords(position); | |
// grid.chkHexGridWithMousePos(sf::Vector2f(position)); | |
// | |
// for (auto& c : grid) | |
// { | |
// if (isMouseContainsHexagaon(c, sf::Vector2f(e.mouseMove.x, e.mouseMove.y), points)) | |
// { | |
// c.setFillColor(sf::Color(255, 255, 255)); | |
// } | |
// else | |
// { | |
// c.setFillColor(sf::Color(150, 50, 250)); | |
// } | |
// } | |
window.clear(); | |
for (auto c : grid) | |
{ | |
window.draw(c); | |
} | |
window.display(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SFML/Graphics.hpp> | |
#include <iostream> | |
#include <array> | |
#include <vector> | |
#include <utility> | |
#include <queue> | |
#include <tuple> | |
#include <set> | |
#include <algorithm> | |
#include <random> | |
namespace sf | |
{ | |
template <typename T> | |
inline bool operator < (const Vector2<T>& left, const Vector2<T>& right) | |
{ | |
return (left.x < right.x) || ((left.x == right.x) && (left.y < right.y)); | |
} | |
template <typename T> | |
inline bool operator > (const Vector2<T>& left, const Vector2<T>& right) | |
{ | |
return (left.x > right.x) || ((left.x == right.x) && (left.y > right.y)); | |
} | |
template <typename T, typename U> | |
inline Vector2<T> operator /(const Vector2<T>& left, U right) | |
{ | |
return Vector2<T>(left.x / right, left.y / right); | |
} | |
} | |
template <typename T> | |
inline double manhattan(const T& a, const T& b) | |
{ | |
const auto dx = std::abs(a.x - b.x); | |
const auto dy = std::abs(a.y - b.y); | |
return (dx + dy); | |
} | |
template <typename T> | |
inline double euclidean(const T& a, const T& b) | |
{ | |
const auto dx = std::abs(a.x - b.x); | |
const auto dy = std::abs(a.y - b.y); | |
return std::sqrt(dx * dx + dy * dy); | |
} | |
template <typename T> | |
inline double chebyshev(const T& a, const T& b) | |
{ | |
const auto dx = std::abs(a.x - b.x); | |
const auto dy = std::abs(a.y - b.y); | |
return std::max(dx, dy); | |
} | |
template <typename N> | |
class Graph | |
{ | |
class Node; | |
using NodeHolder = std::set<Node>; | |
public: | |
using NodeVal = N; | |
using NodeRef = typename NodeHolder::iterator; | |
using Edges = std::vector<std::tuple<NodeRef, double, double>>; | |
public: | |
void addNode(const N& data) const | |
{ | |
nodes.emplace(data); | |
} | |
const NodeRef getRef(const N& data) const | |
{ | |
const auto& found = nodes.find(data); | |
if (found == nodes.end()) | |
throw std::runtime_error("Graph::getRef: Key not found!\n"); | |
return found; | |
} | |
void addEdge(const NodeRef src, const NodeRef dst, double cost) const | |
{ | |
if (src != nodes.end() && dst != nodes.end()) | |
src->addEdge(dst, cost); | |
} | |
void clear() | |
{ | |
nodes.clear(); | |
} | |
private: | |
class Node | |
{ | |
using EdgesRef = typename Edges::iterator; | |
N data; | |
mutable Edges edges; | |
public: | |
Node(const N& data) : data{data}, edges{} {} | |
void addEdge(const NodeRef e, double f, double g=0.0) const | |
{ | |
edges.emplace_back(e, f, g); | |
edges.shrink_to_fit(); | |
} | |
const NodeVal& value() const | |
{ | |
return data; | |
} | |
const EdgesRef begin() const {return edges.begin();} | |
const EdgesRef end() const {return edges.end();} | |
friend bool operator < (const Node& lhs, const Node& rhs) | |
{ | |
return lhs.data < rhs.data; | |
} | |
}; | |
private: | |
mutable NodeHolder nodes; | |
}; | |
sf::Vector2f twoDToIso(const sf::Vector2f& coord) | |
{ | |
return {coord.x - coord.y, (coord.x + coord.y) / 2}; | |
} | |
sf::Vector2i isoTo2D(const sf::Vector2f& coord) | |
{ | |
return sf::Vector2i((2 * coord.y + coord.x) / 2, (2 * coord.y - coord.x) / 2); | |
} | |
std::vector<sf::Vertex> | |
make_outLines(unsigned width, unsigned height, float size, | |
const sf::Color& color=sf::Color{139,137,137}) | |
{ | |
std::vector<sf::Vertex> vertices((width + height + 2) * 2); | |
static const auto e = 0.001f; | |
// make vertical lines | |
for (unsigned i = 0; i <= width; ++i) | |
{ | |
const auto& line = &vertices[i * 2]; | |
line[0] = {twoDToIso(sf::Vector2f(((i==0) ? i+e : i), 0 ) * size), color}; | |
line[1] = {twoDToIso(sf::Vector2f(((i==0) ? i+e : i), height) * size), color}; | |
} | |
// make horizontal lines | |
for (unsigned i = 0; i <= height; ++i) | |
{ | |
const auto& line = &vertices[(i + width + 1) * 2]; | |
line[0] = {twoDToIso(sf::Vector2f(0, ((i==height) ? i-e : i)) * size), color}; | |
line[1] = {twoDToIso(sf::Vector2f(width, ((i==height) ? i-e : i)) * size), color}; | |
} | |
return vertices; | |
} | |
class Grid final : public sf::Drawable | |
{ | |
class Cell | |
{ | |
public: | |
explicit Cell(const sf::Vector2i& offset, float size, const sf::Color& color) | |
{ | |
vertices[0] = {twoDToIso(sf::Vector2f( offset.x, offset.y ) * size), color}; | |
vertices[1] = {twoDToIso(sf::Vector2f((offset.x + 1), offset.y ) * size), color}; | |
vertices[2] = {twoDToIso(sf::Vector2f( offset.x, (offset.y + 1)) * size), color}; | |
vertices[3] = {twoDToIso(sf::Vector2f((offset.x + 1), offset.y ) * size), color}; | |
vertices[4] = {twoDToIso(sf::Vector2f((offset.x + 1), (offset.y + 1)) * size), color}; | |
vertices[5] = {twoDToIso(sf::Vector2f( offset.x, (offset.y + 1)) * size), color}; | |
} | |
void setFillColor(const sf::Color& color) const | |
{ | |
for (auto& v : vertices) { v.color = color;} | |
} | |
const sf::Color& getFillColor() const | |
{ | |
return vertices[0].color; | |
} | |
sf::Vector2f getPosition() const | |
{ | |
return vertices[0].position; | |
} | |
const sf::Vertex* data() const | |
{ | |
return vertices.data(); | |
} | |
unsigned size() const | |
{ | |
return vertices.size(); | |
} | |
private: | |
mutable std::array<sf::Vertex, 6> vertices; | |
}; | |
using CellHolder = std::vector<Cell>; | |
using CellRef = CellHolder::iterator; | |
using OutLineHolder = std::vector<sf::Vertex>; | |
public: | |
explicit Grid(int width, | |
int height, | |
float tile_size, | |
const sf::Color& color=sf::Color::White) | |
: grid{} | |
, outlines{make_outLines(width, height, tile_size)} | |
{ | |
const auto numberOfCells = width * height; | |
grid.reserve(numberOfCells); | |
for (int i = 0; i < numberOfCells; ++i) | |
{ | |
sf::Vector2i offset(i % width, i / width); | |
grid.emplace_back(offset, tile_size, color); | |
} | |
} | |
const Cell& operator[](unsigned index) const {return grid[index];} | |
CellRef begin() {return grid.begin();} | |
CellRef end() {return grid.end();} | |
private: | |
void draw(sf::RenderTarget& target, sf::RenderStates) const | |
{ | |
static const auto grid_size = grid[0].size()*grid.size(); | |
static const auto outlines_size = outlines.size(); | |
static const auto& outlines_cache = outlines.data(); | |
target.draw(grid[0].data(), grid_size, sf::Triangles); | |
target.draw(outlines_cache, outlines_size, sf::Lines); | |
} | |
private: | |
CellHolder grid; | |
OutLineHolder outlines; | |
}; | |
template <typename Graph> | |
class PathFinder | |
{ | |
using NodeRef = typename Graph::NodeRef; | |
using NodeVal = typename Graph::NodeVal; | |
using QueBase = std::tuple<NodeRef, double, double, std::vector<NodeRef>>; | |
struct QueueHelper final : public QueBase | |
{ | |
QueueHelper(const QueueHelper&) = default; | |
explicit QueueHelper(const NodeRef& data, | |
double f, | |
double g, | |
const std::vector<NodeRef>& route) | |
: QueBase(data, f, g, route) | |
{ | |
std::get<3>(*this).emplace_back(data); | |
std::get<3>(*this).shrink_to_fit(); | |
} | |
friend bool operator < (const QueueHelper& lhs, const QueueHelper& rhs) | |
{ | |
return std::get<1>(lhs) > std::get<1>(rhs); | |
} | |
}; | |
public: | |
explicit PathFinder(sf::RenderWindow& window, Grid& grid, int width) | |
: window{window} | |
, grid{grid} | |
, width{width} | |
, light{sf::Color{102,205,170}} | |
, dark{sf::Color{127,255,212}} | |
{} | |
std::vector<NodeRef> routeAstar(const NodeRef& src, const NodeRef& dst) const | |
{ | |
std::set<NodeVal> found; | |
std::priority_queue<QueueHelper> frontier; | |
frontier.emplace(src, 0,0, std::vector<NodeRef>{}); | |
const auto& start = src->value(); | |
const auto& goal = dst->value(); | |
static const double scale = 0.001; | |
while (!frontier.empty()) | |
{ | |
const auto next = frontier.top(); frontier.pop(); | |
const auto& nextRef = std::get<0>(next); | |
const auto& nextVal = nextRef->value(); | |
if (found.find(nextVal) != found.end()) continue; | |
const auto& result = std::get<3>(next); | |
if (nextRef == dst) return result; | |
if (nextRef != src && nextRef != dst){ | |
const auto index = nextVal.x + width * nextVal.y; | |
grid[index].setFillColor(light); | |
} | |
found.emplace(nextVal); | |
const auto nextg = std::get<2>(next); | |
const auto& d1 = nextVal - goal; | |
const auto& d2 = start - goal; | |
const auto cross = std::abs(d1.x*d2.y - d2.x*d1.y) * scale; | |
for (const auto& edge : *nextRef) | |
{ | |
const auto& edgeRef = std::get<0>(edge); | |
const auto& edgeVal = edgeRef->value(); | |
if (found.find(edgeVal) != found.end()) continue; | |
const auto h = manhattan(edgeVal, goal) + cross; | |
const auto f = nextg + h; | |
const auto g = nextg + std::get<1>(edge); | |
if (edgeRef != src && edgeRef != dst){ | |
const auto index = edgeVal.x + width * edgeVal.y; | |
grid[index].setFillColor(dark); | |
} | |
frontier.emplace(edgeRef, f, g, result); | |
} | |
draw(); | |
} | |
return {}; | |
} | |
std::vector<NodeRef> routeDijkstra(const NodeRef& src, const NodeRef& dst) const | |
{ | |
std::set<NodeVal> found; | |
std::priority_queue<QueueHelper> frontier; | |
frontier.emplace(src, 0,0, std::vector<NodeRef>{}); | |
while (!frontier.empty()) | |
{ | |
const auto next = frontier.top(); frontier.pop(); | |
const auto& nextRef = std::get<0>(next); | |
const auto& nextVal = nextRef->value(); | |
if (found.find(nextVal) != found.end()) continue; | |
const auto& result = std::get<3>(next); | |
if (nextRef == dst) return result; | |
if (nextRef != src && nextRef != dst){ | |
const auto index = nextVal.x + width * nextVal.y; | |
grid[index].setFillColor(light); | |
} | |
found.emplace(nextVal); | |
const auto& cost = std::get<1>(next); | |
for (const auto& edge : *nextRef) | |
{ | |
const auto& edgeRef = std::get<0>(edge); | |
const auto& edgeVal = edgeRef->value(); | |
if (found.find(edgeVal) != found.end()) continue; | |
if (edgeRef != src && edgeRef != dst){ | |
const auto index = edgeVal.x + width * edgeVal.y; | |
grid[index].setFillColor(dark); | |
} | |
frontier.emplace(edgeRef, cost + std::get<1>(edge), 0, result); | |
} | |
draw(); | |
} | |
return {}; | |
} | |
private: | |
void draw() const | |
{ | |
sf::Event event; | |
while (window.pollEvent(event)) | |
{ | |
if (event.type == sf::Event::Closed | |
|| (event.type == sf::Event::KeyPressed | |
&& event.key.code == sf::Keyboard::Escape)) | |
window.close(); | |
} | |
window.clear(); | |
window.draw(grid); | |
window.display(); | |
} | |
private: | |
sf::RenderWindow& window; | |
Grid& grid; | |
const int width; | |
const sf::Color light; | |
const sf::Color dark; | |
}; | |
class MapEditor : public sf::Transformable | |
{ | |
using PathHolder = std::vector<sf::Vector2i>; | |
using PathRef = PathHolder::iterator; | |
using Graph = Graph<sf::Vector2i>; | |
using PathFinder = PathFinder<Graph>; | |
enum Input | |
{ | |
None = 0, | |
AddWall = 1 << 0, | |
RemoveWall = 1 << 1, | |
MoveStart = 1 << 2, | |
MoveGoal = 1 << 3, | |
}; | |
enum Algorithm | |
{ | |
Dijkstra = 1 << 0, | |
Astar = 1 << 1, | |
}; | |
public: | |
MapEditor() | |
: width{30} | |
, height{30} | |
, tile_size{20} | |
, window{ | |
sf::VideoMode(width*tile_size, height*tile_size), | |
"Path Finders - Algorithms"} | |
, view{window.getDefaultView()} | |
, grid{width, height, tile_size} | |
, input{None} | |
, start{} | |
, goal{} | |
, needUpdate{false} | |
, algorithm{Dijkstra} | |
, graph{} | |
, pathFinder{window, grid, width} | |
{ | |
view.move(-width*tile_size/2, 0); | |
view.zoom(2.f); | |
window.setView(view); | |
std::random_device rd; | |
std::mt19937 gen(rd()); | |
auto distH = std::uniform_int_distribution<>(1,height/2); | |
auto distW = std::uniform_int_distribution<>(width/4,width*2); | |
start.x = distW(gen)%width; start.y = distH(gen)%height; | |
goal.x = distW(gen)%width; goal.y = distH(gen)%height; | |
grid[start.x + width * start.y].setFillColor(sf::Color::Green); | |
grid[goal.x + width * goal.y].setFillColor(sf::Color::Red); | |
begin = path.end(); | |
} | |
void run() | |
{ | |
while (window.isOpen()) | |
{ | |
processEvents(); | |
update(); | |
render(); | |
} | |
} | |
private: | |
void processEvents() | |
{ | |
static const unsigned toggle = (Dijkstra ^ Astar); | |
sf::Event event; | |
float factor = 0.f; | |
while (window.pollEvent(event)) | |
{ | |
const auto& pos = sf::Mouse::getPosition(window); | |
const auto& mappedPos = window.mapPixelToCoords(pos, view); | |
const auto& coord = isoTo2D(mappedPos) / tile_size; | |
switch (event.type) | |
{ | |
case sf::Event::Closed:window.close(); break; | |
case sf::Event::KeyPressed: | |
if (event.key.code == sf::Keyboard::Escape){ | |
window.close(); | |
} | |
else if (event.key.code == sf::Keyboard::P){ | |
clearPath(); | |
} | |
else if (event.key.code == sf::Keyboard::R){ | |
setAlgorithmType(algorithm); | |
} | |
else if (event.key.code == sf::Keyboard::S){ | |
setAlgorithmType(algorithm); | |
} | |
else if (event.key.code == sf::Keyboard::W){ | |
clearWall(); | |
} | |
else if (event.key.code == sf::Keyboard::T){ | |
algorithm ^= toggle; | |
} | |
// debug | |
else if (event.key.code == sf::Keyboard::Right){ | |
view.rotate(factor -= 1.f); | |
window.setView(view); | |
} | |
else if (event.key.code == sf::Keyboard::Left){ | |
view.rotate(factor += 1.f); | |
window.setView(view); | |
} | |
break; | |
case sf::Event::MouseButtonPressed: | |
if (event.mouseButton.button == sf::Mouse::Left) | |
{ | |
if (addWall(coord)){ | |
input = AddWall; | |
} | |
if (moveStart(coord)){ | |
input = MoveStart; | |
} | |
if (moveGoal(coord)){ | |
input = MoveGoal; | |
} | |
} | |
if (event.mouseButton.button == sf::Mouse::Right) | |
{ | |
input = RemoveWall; | |
removeWall(coord); | |
} | |
break; | |
case sf::Event::MouseButtonReleased: | |
{ | |
input &= ~(AddWall | RemoveWall | MoveStart | MoveGoal); | |
} | |
break; | |
case sf::Event::MouseMoved: | |
if (input & AddWall){ | |
addWall(coord); | |
} | |
else if (input & RemoveWall){ | |
removeWall(coord); | |
} | |
else if (input & MoveStart){ | |
moveStart(coord); | |
} | |
else if (input & MoveGoal){ | |
moveGoal(coord); | |
} | |
break; | |
default:break; | |
}; | |
} | |
} | |
void render() | |
{ | |
window.clear(); | |
window.draw(grid); | |
window.display(); | |
} | |
void setAlgorithmType(unsigned a) | |
{ | |
algorithm = a; | |
reset(); | |
std::vector<Graph::NodeRef> result; | |
if (algorithm & Dijkstra) | |
result = pathFinder.routeDijkstra(graph.getRef(start), graph.getRef(goal)); | |
else | |
result = pathFinder.routeAstar(graph.getRef(start), graph.getRef(goal)); | |
for (const auto& c : result){ | |
path.emplace_back(c->value()); | |
} | |
path.shrink_to_fit(); | |
begin = path.begin(); | |
} | |
void update() | |
{ | |
if(needUpdate){ | |
clearPath(); | |
needUpdate = false; | |
} | |
if (begin == path.end()) return; | |
const auto& coord = *begin; | |
if (coord != start && coord != goal){ | |
grid[coord.x + width * coord.y].setFillColor(sf::Color::Yellow); | |
} | |
begin++; | |
} | |
// mouse input | |
bool moveStart(const sf::Vector2i& position) | |
{ | |
if(!in_bounds(position) || !passable(position)|| position == goal) return false; | |
start = position; | |
needUpdate = true; | |
return needUpdate; | |
} | |
bool moveGoal(const sf::Vector2i& position) | |
{ | |
if(!in_bounds(position) || !passable(position) || position == start) return false; | |
goal = position; | |
needUpdate = true; | |
return needUpdate; | |
} | |
bool addWall(const sf::Vector2i& position) | |
{ | |
if(position == start || position == goal || !in_bounds(position)) return false; | |
grid[position.x + width * position.y].setFillColor(Gray); | |
return true; | |
} | |
void removeWall(const sf::Vector2i& position) | |
{ | |
if(position == start || position == goal || !in_bounds(position)) return; | |
grid[position.x + width * position.y].setFillColor(sf::Color::White); | |
needUpdate = true; | |
} | |
// keyboards input | |
void clearPath() | |
{ | |
for (const auto& tile : grid) // keep wall | |
{ | |
if (tile.getFillColor() == Gray) continue; | |
tile.setFillColor(sf::Color::White); | |
} | |
grid[start.x + width * start.y].setFillColor(sf::Color::Green); | |
grid[goal.x + width * goal.y].setFillColor(sf::Color::Red); | |
} | |
void clearWall() | |
{ | |
for (const auto& tile : grid) | |
{ | |
if (tile.getFillColor() == Gray) | |
tile.setFillColor(sf::Color::White); | |
} | |
needUpdate = true; | |
} | |
void reset() | |
{ | |
clearPath(); | |
path.clear(); | |
begin = path.end(); | |
graph.clear(); | |
for (const auto& tile : grid) | |
{ | |
const auto& p = isoTo2D(tile.getPosition()) / tile_size; | |
if (!passable(p)) continue; | |
graph.addNode(p); | |
} | |
for (const auto& tile : grid) | |
{ | |
const auto& p = isoTo2D(tile.getPosition()) / tile_size; | |
if (!passable(p)) continue; | |
for (const auto& next : neighbors(p)){ | |
graph.addEdge(graph.getRef(p), graph.getRef(next), 1.0); | |
} | |
} | |
} | |
inline bool in_bounds(const sf::Vector2i& id) const | |
{ | |
return 0 <= id.x && id.x < width && 0 <= id.y && id.y < height; | |
} | |
inline bool passable(const sf::Vector2i& position) const | |
{ | |
const auto& tile = grid[position.x + width * position.y]; | |
return tile.getFillColor() != Gray; | |
} | |
std::vector<sf::Vector2i> neighbors(const sf::Vector2i& id) const | |
{ | |
static const std::array<sf::Vector2i, 4> Directions{{ | |
{ 1, 0}, | |
{ 0, -1}, | |
{-1, 0}, | |
{ 0, 1}, | |
}}; | |
std::vector<sf::Vector2i> result; | |
result.reserve(Directions.size()); | |
for (const auto& direction : Directions) | |
{ | |
const auto& next(id + direction); | |
if (!in_bounds(next) || !passable(next)) continue; | |
result.emplace_back(next); | |
} | |
return result; | |
} | |
private: | |
static const sf::Color Gray; | |
const int width; | |
const int height; | |
const float tile_size; | |
sf::RenderWindow window; | |
sf::View view; | |
Grid grid; | |
PathHolder path; | |
PathRef begin; | |
unsigned input; | |
sf::Vector2i start; | |
sf::Vector2i goal; | |
bool needUpdate; | |
// Algorithm's engine | |
unsigned algorithm; | |
Graph graph; | |
PathFinder pathFinder; | |
}; | |
const sf::Color MapEditor::Gray = sf::Color{139,137,137}; | |
int main() | |
{ | |
try{ | |
MapEditor editor; | |
editor.run(); | |
} catch (std::runtime_error& e) | |
{ | |
std::cout << "Exception: " << e.what() << '\n'; | |
return 1; | |
} catch (std::out_of_range& e) | |
{ | |
std::cout << "Exception: " << e.what() << '\n'; | |
return 1; | |
} catch (...) | |
{ | |
std::cout << "Unknown Exception!\n"; | |
return 1; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment