Created
June 7, 2018 13:47
-
-
Save sknjpn/6b2694e87c78818b2d68974e91036b00 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 <Siv3D.hpp> // OpenSiv3D v0.2.5 | |
class Node | |
{ | |
Vec2 m_position; //物理的な座標 | |
Point m_point; //仮想上の座標 | |
double m_height; //高度 | |
double m_radius; //半径 | |
Polygon m_polygon; //形状 | |
Array<Node*> m_near_nodes; | |
public: | |
Node(Point point, Vec2 position, double r) | |
: m_point(point) | |
, m_position(position) | |
, m_height(0) | |
, m_radius(r) | |
, m_polygon(Shape2D::Hexagon(m_radius / 2.0 / Cos(30_deg), position).asPolygon()) | |
{} | |
void add_near_node(Node* node) { m_near_nodes.emplace_back(node); } | |
//getter | |
Vec2 get_position() const { return m_position; } | |
double get_height() const { return m_height; } | |
Polygon get_polygon() const { return m_polygon; } | |
const Array<Node*>& get_near_nodes() const { return m_near_nodes; } | |
//setter | |
void set_height(double height) { m_height = height; } | |
}; | |
class Field | |
{ | |
double m_node_radius; | |
Point m_node_size; | |
Grid<Node*> m_nodes; | |
public: | |
Field(Vec2 size) | |
: m_node_radius(2.0) | |
, m_node_size(int(size.x / m_node_radius), int(size.y / Cos(30_deg) / m_node_radius)) | |
, m_nodes(m_node_size) | |
{ | |
init(); | |
} | |
//マップ初期化 | |
void init() | |
{ | |
for (auto p : step(m_node_size)) | |
{ | |
//奇数列は半分ずらし、縦横比も変更 | |
m_nodes[p.y][p.x] = new Node(p, m_node_radius * Vec2(p.x + (p.y % 2 ? Cos(60_deg) : 0.0), p.y * Cos(30_deg)), m_node_radius); | |
} | |
//Nodeの相互接続 | |
for (auto p : step(m_node_size)) | |
{ | |
//周囲のリスト | |
Array<Point> list; | |
//奇数偶数列に応じた周囲のリストを登録 | |
if (p.y % 2) { list = Array<Point>({ { p.x, p.y - 1 },{ p.x + 1, p.y - 1 },{ p.x + 1, p.y },{ p.x + 1, p.y + 1 },{ p.x, p.y + 1 },{ p.x - 1, p.y } }); } | |
else { list = Array<Point>({ { p.x - 1, p.y - 1 },{ p.x , p.y - 1 },{ p.x + 1, p.y },{ p.x , p.y + 1 },{ p.x - 1, p.y + 1 },{ p.x - 1, p.y } }); } | |
//周囲の結びつきの登録 | |
for (auto& l : list) | |
{ | |
if (l.x >= 0 && l.y >= 0 && l.x < m_node_size.x && l.y < m_node_size.y) { m_nodes[p.y][p.x]->add_near_node(m_nodes[l.y][l.x]); } | |
else { m_nodes[p.y][p.x]->add_near_node(nullptr); } | |
} | |
} | |
generate_terrain(); | |
} | |
void generate_terrain() | |
{ | |
PerlinNoise noise(Random(10000)); | |
for (auto p : step(m_node_size)) | |
{ | |
auto* n = m_nodes[p.y][p.x]; | |
auto h = Abs(noise.octaveNoise(n->get_position() * 0.0025, 10)) | |
* Pow(1.0 - Abs(m_node_size.x / 2 - p.x) / double(m_node_size.x / 2), 0.5) | |
* Pow(1.0 - Abs(m_node_size.y / 2 - p.y) / double(m_node_size.y / 2), 0.5); | |
n->set_height(h); | |
} | |
} | |
void draw_hex() | |
{ | |
//枠の描画 | |
for (auto p : step(m_node_size)) | |
{ | |
auto* n = m_nodes[p.y][p.x]; | |
n->get_polygon().draw(ColorF(Palette::Red, n->get_height())); | |
if (n->get_height() < 0.1) | |
{ | |
n->get_polygon().draw(Palette::Blue); | |
} | |
//n->get_polygon().drawFrame(1.0, ColorF(1.0, 0.25)); | |
} | |
/* | |
//接続線の描画 | |
for (auto p : step(m_node_size)) | |
{ | |
auto* n1 = m_nodes[p.y][p.x]; | |
for (auto* n2 : n1->get_near_nodes()) | |
{ | |
if (n2 != nullptr) { Line(n1->get_position(), n2->get_position()).draw(1.0, ColorF(1.0, 0.125)); } | |
} | |
} | |
*/ | |
} | |
//等高線の描画 | |
void draw_contour(double interval, double thickness) | |
{ | |
for (double h = 0; h <= 1.0; h += interval) | |
{ | |
for (auto p : step(m_node_size)) | |
{ | |
auto* tn = m_nodes[p.y][p.x]; | |
const auto& nns = tn->get_near_nodes(); | |
for (auto it = nns.begin(); it != nns.end(); it++) | |
{ | |
auto* ln = *it; //left | |
auto* rn = (it == nns.end() - 1) ? *(nns.begin()) : *(it + 1); //right | |
if (ln == nullptr || rn == nullptr) { continue; } | |
if (h > tn->get_height() && h < ln->get_height() && h < rn->get_height()) | |
{ | |
auto c1 = tn->get_position().lerp(ln->get_position(), (h - tn->get_height()) / (ln->get_height() - tn->get_height())); | |
auto c2 = tn->get_position().lerp(rn->get_position(), (h - tn->get_height()) / (rn->get_height() - tn->get_height())); | |
Line(c1, c2).draw(thickness); | |
} | |
if (h < tn->get_height() && h > ln->get_height() && h > rn->get_height()) | |
{ | |
auto c1 = ln->get_position().lerp(tn->get_position(), (h - ln->get_height()) / (tn->get_height() - ln->get_height())); | |
auto c2 = rn->get_position().lerp(tn->get_position(), (h - rn->get_height()) / (tn->get_height() - rn->get_height())); | |
Line(c1, c2).draw(thickness); | |
} | |
} | |
} | |
} | |
} | |
void draw() | |
{ | |
draw_hex(); | |
draw_contour(0.1, 1.0); | |
draw_contour(0.025, 0.5); | |
} | |
}; | |
Field* g_field = nullptr; | |
void Main() | |
{ | |
g_field = new Field(Vec2(500, 500)); | |
//ウィンドウの設定 | |
Window::Resize(640, 480); | |
while (System::Update()) | |
{ | |
g_field->draw(); | |
if (KeyEnter.down()) { g_field->generate_terrain(); } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment