new file: addons/delaunator/Delaunator.gd new file: default_env.tres new file: icon.png new file: icon.png.import new file: project.godot new file: ui/map/map.gd new file: ui/map/map.tscn new file: ui/ui.tscn new file: utils/terrain/Terrain.gd new file: world/game.gd new file: world/game.tscnpull/4/head
parent
441d3050df
commit
10140bf69c
@ -0,0 +1,137 @@ |
||||
class_name PoissonDiscSampling |
||||
|
||||
var _radius: float |
||||
var _sample_region_shape |
||||
var _retries: int |
||||
var _start_pos: Vector2 |
||||
var _sample_region_rect: Rect2 |
||||
var _cell_size: float |
||||
var _rows: int |
||||
var _cols: int |
||||
var _cell_size_scaled: Vector2 |
||||
var _grid: Array = [] |
||||
var _points: Array = [] |
||||
var _spawn_points: Array = [] |
||||
var _transpose: Vector2 |
||||
|
||||
# radius - minimum distance between points |
||||
# sample_region_shape - takes any of the following: |
||||
# -a Rect2 for rectangular region |
||||
# -an array of Vector2 for polygon region |
||||
# -a Vector3 with x,y as the position and z as the radius of the circle |
||||
# retries - maximum number of attempts to look around a sample point, reduce this value to speed up generation |
||||
# start_pos - optional parameter specifying the starting point |
||||
# |
||||
# returns an Array of Vector2D with points in the order of their discovery |
||||
func generate_points(radius: float, sample_region_shape, retries: int, start_pos := Vector2(INF, INF)) -> Array: |
||||
_radius = radius |
||||
_sample_region_shape = sample_region_shape |
||||
_retries = retries |
||||
_start_pos = start_pos |
||||
_init_vars() |
||||
|
||||
while _spawn_points.size() > 0: |
||||
var spawn_index: int = randi() % _spawn_points.size() |
||||
var spawn_centre: Vector2 = _spawn_points[spawn_index] |
||||
var sample_accepted: bool = false |
||||
for i in retries: |
||||
var angle: float = 2 * PI * randf() |
||||
var sample: Vector2 = spawn_centre + Vector2(cos(angle), sin(angle)) * (radius + radius * randf()) |
||||
if _is_valid_sample(sample): |
||||
_grid[int((_transpose.x + sample.x) / _cell_size_scaled.x)][int((_transpose.y + sample.y) / _cell_size_scaled.y)] = _points.size() |
||||
_points.append(sample) |
||||
_spawn_points.append(sample) |
||||
sample_accepted = true |
||||
break |
||||
if not sample_accepted: |
||||
_spawn_points.remove(spawn_index) |
||||
return _points |
||||
|
||||
|
||||
func _is_valid_sample(sample: Vector2) -> bool: |
||||
if _is_point_in_sample_region(sample): |
||||
var cell := Vector2(int((_transpose.x + sample.x) / _cell_size_scaled.x), int((_transpose.y + sample.y) / _cell_size_scaled.y)) |
||||
var cell_start := Vector2(max(0, cell.x - 2), max(0, cell.y - 2)) |
||||
var cell_end := Vector2(min(cell.x + 2, _cols - 1), min(cell.y + 2, _rows - 1)) |
||||
|
||||
for i in range(cell_start.x, cell_end.x + 1): |
||||
for j in range(cell_start.y, cell_end.y + 1): |
||||
var search_index: int = _grid[i][j] |
||||
if search_index != -1: |
||||
var dist: float = _points[search_index].distance_to(sample) |
||||
if dist < _radius: |
||||
return false |
||||
return true |
||||
return false |
||||
|
||||
|
||||
func _is_point_in_sample_region(sample: Vector2) -> bool: |
||||
if _sample_region_rect.has_point(sample): |
||||
match typeof(_sample_region_shape): |
||||
TYPE_RECT2: |
||||
return true |
||||
TYPE_VECTOR2_ARRAY, TYPE_ARRAY: |
||||
if Geometry.is_point_in_polygon(sample, _sample_region_shape): |
||||
return true |
||||
TYPE_VECTOR3: |
||||
if Geometry.is_point_in_circle(sample, Vector2(_sample_region_shape.x, _sample_region_shape.y), _sample_region_shape.z): |
||||
return true |
||||
_: |
||||
return false |
||||
return false |
||||
|
||||
func _init_vars() -> void: |
||||
randomize() |
||||
|
||||
# identify the type of shape and it's bounding rectangle and starting point |
||||
match typeof(_sample_region_shape): |
||||
TYPE_RECT2: |
||||
_sample_region_rect = _sample_region_shape |
||||
if _start_pos.x == INF: |
||||
_start_pos.x = _sample_region_rect.position.x + _sample_region_rect.size.x * randf() |
||||
_start_pos.y = _sample_region_rect.position.y + _sample_region_rect.size.y * randf() |
||||
|
||||
TYPE_VECTOR2_ARRAY, TYPE_ARRAY: |
||||
var start: Vector2 = _sample_region_shape[0] |
||||
var end: Vector2 = _sample_region_shape[0] |
||||
for i in range(1, _sample_region_shape.size()): |
||||
start.x = min(start.x, _sample_region_shape[i].x) |
||||
start.y = min(start.y, _sample_region_shape[i].y) |
||||
end.x = max(end.x, _sample_region_shape[i].x) |
||||
end.y = max(end.y, _sample_region_shape[i].y) |
||||
_sample_region_rect = Rect2(start, end - start) |
||||
if _start_pos.x == INF: |
||||
var n: int = _sample_region_shape.size() |
||||
var i: int = randi() % n |
||||
_start_pos = _sample_region_shape[i] + (_sample_region_shape[(i + 1) % n] - _sample_region_shape[i]) * randf() |
||||
|
||||
TYPE_VECTOR3: |
||||
var x = _sample_region_shape.x |
||||
var y = _sample_region_shape.y |
||||
var r = _sample_region_shape.z |
||||
_sample_region_rect = Rect2(x - r, y - r, r * 2, r * 2) |
||||
if _start_pos.x == INF: |
||||
var angle: float = 2 * PI * randf() |
||||
_start_pos = Vector2(x, y) + Vector2(cos(angle), sin(angle)) * r * randf() |
||||
_: |
||||
_sample_region_shape = Rect2(0, 0, 0, 0) |
||||
push_error("Unrecognized shape!!! Please input a valid shape") |
||||
|
||||
_cell_size = _radius / sqrt(2) |
||||
_cols = max(floor(_sample_region_rect.size.x / _cell_size), 1) |
||||
_rows = max(floor(_sample_region_rect.size.y / _cell_size), 1) |
||||
# scale the cell size in each axis |
||||
_cell_size_scaled.x = _sample_region_rect.size.x / _cols |
||||
_cell_size_scaled.y = _sample_region_rect.size.y / _rows |
||||
# use tranpose to map points starting from origin to calculate grid position |
||||
_transpose = -_sample_region_rect.position |
||||
|
||||
_grid = [] |
||||
for i in _cols: |
||||
_grid.append([]) |
||||
for j in _rows: |
||||
_grid[i].append(-1) |
||||
|
||||
_points = [] |
||||
_spawn_points = [] |
||||
_spawn_points.append(_start_pos) |
||||
@ -0,0 +1,571 @@ |
||||
extends Reference |
||||
|
||||
class_name Delaunator |
||||
|
||||
const EPSILON = pow(2, -52) |
||||
const EDGE_STACK = [] |
||||
|
||||
var coords = [] # PoolRealArray. |
||||
var halfedges = [] # PoolIntArray. |
||||
var hull = [] # PoolIntArray. |
||||
var triangles = [] # PoolIntArray. |
||||
var triangles_len = 0 |
||||
var _cx |
||||
var _cy |
||||
var _dists = [] # PoolRealArray. |
||||
var _halfedges = [] # This array should be a PoolIntArray but we need to use the .slice() function on it. |
||||
var _hash_size |
||||
var _hull_hash = [] # PoolIntArray. |
||||
var _hull_next = [] # PoolIntArray. |
||||
var _hull_prev = [] # PoolIntArray. |
||||
var _hull_start |
||||
var _hull_tri = [] # PoolIntArray. |
||||
var _ids = [] # PoolIntArray. |
||||
var _triangles = [] # This array should be a PoolIntArray but we need to use the .slice() function on it. |
||||
|
||||
func _init(points): |
||||
if points.size() < 3: |
||||
push_error(ProjectSettings.get_setting("application/config/name") + " needs at least 3 points.") |
||||
return |
||||
|
||||
EDGE_STACK.resize(512) |
||||
|
||||
var n = points.size() |
||||
|
||||
coords.resize(n * 2) |
||||
|
||||
for i in n: |
||||
var point = points[i] |
||||
coords[2 * i] = point.x |
||||
coords[2 * i + 1] = point.z |
||||
|
||||
_constructor() |
||||
|
||||
func _constructor(): |
||||
var n = coords.size() >> 1 |
||||
|
||||
# Arrays that will store the triangulation graph. |
||||
var max_triangles = max(2 * n - 5, 0) |
||||
_triangles.resize(max_triangles * 3) |
||||
_halfedges.resize(max_triangles * 3) |
||||
|
||||
# Temporary arrays for tracking the edges of the advancing convex hull. |
||||
_hash_size = ceil(sqrt(n)) |
||||
_hull_prev.resize(n) # Edge to prev edge. |
||||
_hull_next.resize(n) # Edge to next edge. |
||||
_hull_tri.resize(n) # Edge to adjacent triangle. |
||||
|
||||
_hull_hash.resize(_hash_size) |
||||
for i in _hash_size: |
||||
_hull_hash[i] = -1 # angular edge hash |
||||
|
||||
# Temporary arrays for sorting points. |
||||
_ids.resize(n) |
||||
_dists.resize(n) |
||||
|
||||
update() |
||||
|
||||
|
||||
func update(): |
||||
var n = coords.size() >> 1 |
||||
|
||||
# Populate an array of point indices; calculate input data bbox. |
||||
var min_x = INF |
||||
var min_y = INF |
||||
var max_x = -INF |
||||
var max_y = -INF |
||||
|
||||
for i in n: |
||||
var x = coords[2 * i] |
||||
var y = coords[2 * i + 1] |
||||
if x < min_x: min_x = x |
||||
if y < min_y: min_y = y |
||||
if x > max_x: max_x = x |
||||
if y > max_y: max_y = y |
||||
_ids[i] = i |
||||
|
||||
var cx = (min_x + max_x) / 2 |
||||
var cy = (min_y + max_y) / 2 |
||||
|
||||
var min_dist = INF |
||||
var i0 = 0 |
||||
var i1 = 0 |
||||
var i2 = 0 |
||||
|
||||
# Pick a seed point close to the center. |
||||
for i in n: |
||||
var d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]) |
||||
if (d < min_dist): |
||||
i0 = i |
||||
min_dist = d |
||||
var i0x = coords[2 * i0] |
||||
var i0y = coords[2 * i0 + 1] |
||||
|
||||
min_dist = INF |
||||
|
||||
# Find the point closest to the seed. |
||||
for i in n: |
||||
if i == i0: continue |
||||
var d = dist(i0x, i0y, coords[2 * i], coords[2 * i + 1]) |
||||
if (d < min_dist and d > 0): |
||||
i1 = i |
||||
min_dist = d |
||||
var i1x = coords[2 * i1] |
||||
var i1y = coords[2 * i1 + 1] |
||||
|
||||
var min_radius = INF |
||||
|
||||
# Find the third point which forms the smallest circumcircle with the first two. |
||||
for i in n: |
||||
if i == i0 or i == i1: continue |
||||
var r = circumradius(i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1]) |
||||
if r < min_radius: |
||||
i2 = i |
||||
min_radius = r |
||||
var i2x = coords[2 * i2] |
||||
var i2y = coords[2 * i2 + 1] |
||||
|
||||
if min_radius == INF: |
||||
# Order collinear points by dx (or dy if all x are identical) |
||||
# and return the list as a hull. |
||||
for i in n: |
||||
var _dist_temp |
||||
|
||||
if coords[2 * i] - coords[0]: |
||||
_dist_temp = coords[2 * i] - coords[0] |
||||
elif coords[2 * i + 1] - coords[1]: |
||||
_dist_temp = coords[2 * i + 1] - coords[1] |
||||
else: |
||||
_dist_temp = 0 |
||||
|
||||
_dists[i] = _dist_temp |
||||
|
||||
quicksort(_ids, _dists, 0, n - 1) |
||||
var hull = [] |
||||
hull.resize(n) |
||||
var j = 0 |
||||
var d0 = -INF |
||||
|
||||
for i in n: |
||||
var id = _ids[i] |
||||
if _dists[id] > d0: |
||||
hull[j] = id |
||||
j += 1 |
||||
d0 = _dists[id] |
||||
hull = hull.slice(0, j - 1) |
||||
triangles = [] |
||||
halfedges = [] |
||||
|
||||
return |
||||
|
||||
# Swap the order of the seed points for counter-clockwise orientation. |
||||
if orient(i0x, i0y, i1x, i1y, i2x, i2y): |
||||
var i = i1 |
||||
var x = i1x |
||||
var y = i1y |
||||
i1 = i2 |
||||
i1x = i2x |
||||
i1y = i2y |
||||
i2 = i |
||||
i2x = x |
||||
i2y = y |
||||
|
||||
var center = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y) |
||||
_cx = center[0] |
||||
_cy = center[1] |
||||
|
||||
for i in n: |
||||
_dists[i] = dist(coords[2 * i], coords[2 * i + 1], center[0], center[1]) |
||||
|
||||
# Sort the points by distance from the seed triangle circumcenter. |
||||
quicksort(_ids, _dists, 0, n - 1) |
||||
|
||||
# Set up the seed triangle as the starting hull. |
||||
_hull_start = i0 |
||||
var hull_size = 3 |
||||
|
||||
_hull_next[i0] = i1 |
||||
_hull_prev[i2] = i1 |
||||
_hull_next[i1] = i2 |
||||
_hull_prev[i0] = i2 |
||||
_hull_next[i2] = i0 |
||||
_hull_prev[i1] = i0 |
||||
|
||||
_hull_tri[i0] = 0 |
||||
_hull_tri[i1] = 1 |
||||
_hull_tri[i2] = 2 |
||||
|
||||
for i in _hull_hash.size(): |
||||
_hull_hash[i] = -1 |
||||
_hull_hash[_hash_key(i0x, i0y)] = i0 |
||||
_hull_hash[_hash_key(i1x, i1y)] = i1 |
||||
_hull_hash[_hash_key(i2x, i2y)] = i2 |
||||
|
||||
# triangles_len = 0 |
||||
_add_triangle(i0, i1, i2, -1, -1, -1) |
||||
|
||||
var xp = 0 |
||||
var yp = 0 |
||||
|
||||
for k in _ids.size(): |
||||
var i = _ids[k] |
||||
var x = coords[2 * i] |
||||
var y = coords[2 * i + 1] |
||||
|
||||
# Skip near-duplicate points. |
||||
if k > 0 and abs(x - xp) <= EPSILON and abs(y - yp) <= EPSILON: continue |
||||
|
||||
xp = x |
||||
yp = y |
||||
|
||||
# Skip seed triangle points. |
||||
if i == i0 or i == i1 or i == i2: continue |
||||
|
||||
# Find a visible edge on the convex hull using edge hash. |
||||
var start = 0 |
||||
var key = _hash_key(x, y) |
||||
|
||||
for j in _hash_size: |
||||
start = _hull_hash[fmod((key + j), _hash_size)] |
||||
if (start != -1 and start != _hull_next[start]): break |
||||
|
||||
start = _hull_prev[start] |
||||
var e = start |
||||
|
||||
while true: |
||||
var q = _hull_next[e] |
||||
if orient(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1]): break |
||||
e = q |
||||
|
||||
if (e == start): |
||||
e = -1 |
||||
break |
||||
|
||||
if (e == -1): continue # Likely a near-duplicate point; Skip it. |
||||
|
||||
# Add the first triangle from the point. |
||||
var t = _add_triangle(e, i, _hull_next[e], -1, -1, _hull_tri[e]) |
||||
# Recursively flip triangles from the point until they satisfy the Delaunay condition. |
||||
_hull_tri[i] = _legalize(t + 2) |
||||
_hull_tri[e] = t # Keep track of boundary triangles on the hull. |
||||
hull_size += 1 |
||||
|
||||
# Walk forward through the hull, adding more triangles and flipping recursively. |
||||
n = _hull_next[e] |
||||
|
||||
while true: |
||||
var q = _hull_next[n] |
||||
if not orient(x, y, coords[2 * n], coords[2 * n + 1], coords[2 * q], coords[2 * q + 1]): break |
||||
t = _add_triangle(n, i, q, _hull_tri[i], -1, _hull_tri[n]) |
||||
_hull_tri[i] = _legalize(t + 2) |
||||
_hull_next[n] = n # Mark as removed. |
||||
hull_size -= 1 |
||||
n = q |
||||
|
||||
# Walk backward from the other side, adding more triangles and flipping. |
||||
if (e == start): |
||||
while true: |
||||
var q = _hull_prev[e] |
||||
if not orient(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1]): break |
||||
t = _add_triangle(q, i, e, -1, _hull_tri[e], _hull_tri[q]) |
||||
_legalize(t + 2) |
||||
_hull_tri[q] = t |
||||
_hull_next[e] = e # Mark as removed. |
||||
hull_size -= 1 |
||||
e = q |
||||
|
||||
# Update the hull indices. |
||||
_hull_start = e |
||||
_hull_prev[i] = e |
||||
_hull_next[e] = i |
||||
_hull_prev[n] = i |
||||
_hull_next[i] = n |
||||
|
||||
# Save the two new edges in the hash table. |
||||
_hull_hash[_hash_key(x, y)] = i |
||||
_hull_hash[_hash_key(coords[2 * e], coords[2 * e + 1])] = e |
||||
|
||||
hull.resize(hull_size) |
||||
var e = _hull_start |
||||
for i in hull_size: |
||||
hull[i] = e |
||||
e = _hull_next[e] |
||||
|
||||
# Trim typed triangle mesh arrays. |
||||
triangles = _triangles.slice(0, triangles_len - 1) |
||||
halfedges = _halfedges.slice(0, triangles_len - 1) |
||||
|
||||
|
||||
func _hash_key(x, y): |
||||
return fmod(floor(pseudo_angle(x - _cx, y - _cy) * _hash_size), _hash_size) |
||||
|
||||
|
||||
func _legalize(a): |
||||
var i = 0 |
||||
var ar = 0 |
||||
|
||||
# Recursion eliminated with a fixed-size stack. |
||||
while true: |
||||
var b = _halfedges[a] |
||||
|
||||
# If the pair of triangles doesn't satisfy the Delaunay condition |
||||
# (p1 is inside the circumcircle of [p0, pl, pr]), flip them, |
||||
# then do the same check/flip recursively for the new pair of triangles |
||||
# |
||||
# pl pl |
||||
# /||\ / \ |
||||
# al/ || \bl al/ \a |
||||
# / || \ / \ |
||||
# / a||b \ flip /___ar___\ |
||||
# p0\ || /p1 => p0\---bl---/p1 |
||||
# \ || / \ / |
||||
# ar\ || /br b\ /br |
||||
# \||/ \ / |
||||
# pr pr |
||||
|
||||
var a0 = a - a % 3 |
||||
ar = a0 + (a + 2) % 3 |
||||
|
||||
if b == -1: # Convex hull edge. |
||||
if i == 0: break |
||||
i -= 1 |
||||
a = EDGE_STACK[i] |
||||
continue |
||||
|
||||
var b0 = b - b % 3 |
||||
var al = a0 + (a + 1) % 3 |
||||
var bl = b0 + (b + 2) % 3 |
||||
|
||||
var p0 = _triangles[ar] |
||||
var pr = _triangles[a] |
||||
var pl = _triangles[al] |
||||
var p1 = _triangles[bl] |
||||
|
||||
var illegal = in_circle( |
||||
coords[2 * p0], coords[2 * p0 + 1], |
||||
coords[2 * pr], coords[2 * pr + 1], |
||||
coords[2 * pl], coords[2 * pl + 1], |
||||
coords[2 * p1], coords[2 * p1 + 1] |
||||
) |
||||
|
||||
if illegal: |
||||
_triangles[a] = p1 |
||||
_triangles[b] = p0 |
||||
|
||||
var hbl = _halfedges[bl] |
||||
|
||||
# Edge swapped on the other side of the hull (rare); Fix the halfedge reference. |
||||
if (hbl == -1): |
||||
var e = _hull_start |
||||
while true: |
||||
if _hull_tri[e] == bl: |
||||
_hull_tri[e] = a |
||||
break |
||||
|
||||
e = _hull_prev[e] |
||||
if e == _hull_start: break |
||||
|
||||
_link(a, hbl) |
||||
_link(b, _halfedges[ar]) |
||||
_link(ar, bl) |
||||
|
||||
var br = b0 + (b + 1) % 3 |
||||
|
||||
# Don't worry about hitting the cap: it can only happen on extremely degenerate input. |
||||
if i < EDGE_STACK.size(): |
||||
EDGE_STACK[i] = br |
||||
i += 1 |
||||
else: |
||||
if i == 0: break |
||||
i -= 1 |
||||
a = EDGE_STACK[i] |
||||
|
||||
return ar |
||||
|
||||
|
||||
func _link(a, b): |
||||
_halfedges[a] = b |
||||
if (b != -1): |
||||
_halfedges[b] = a |
||||
|
||||
|
||||
# Add a new triangle given vertex indices and adjacent half-edge ids. |
||||
func _add_triangle(i0, i1, i2, a, b, c): |
||||
var t = triangles_len |
||||
|
||||
_triangles[t] = i0 |
||||
_triangles[t + 1] = i1 |
||||
_triangles[t + 2] = i2 |
||||
|
||||
_link(t, a) |
||||
_link(t + 1, b) |
||||
_link(t + 2, c) |
||||
|
||||
triangles_len += 3 |
||||
|
||||
return t |
||||
|
||||
|
||||
# Monotonically increases with real angle, but doesn't need expensive trigonometry. |
||||
func pseudo_angle(dx, dy): |
||||
var p = dx / (abs(dx) + abs(dy)) |
||||
|
||||
if (dy > 0): |
||||
return (3 - p) / 4 # [0..1] |
||||
else: |
||||
return (1 + p) / 4 # [0..1] |
||||
|
||||
|
||||
func dist(ax, ay, bx, by): |
||||
var dx = ax - bx |
||||
var dy = ay - by |
||||
return dx * dx + dy * dy |
||||
|
||||
|
||||
# Return 2d orientation sign if we're confident in it through J. Shewchuk's error bound check. |
||||
func orient_if_sure(px, py, rx, ry, qx, qy): |
||||
var l = (ry - py) * (qx - px) |
||||
var r = (rx - px) * (qy - py) |
||||
|
||||
if (abs(l - r) >= 0.00000000000000033306690738754716 * abs(l + r)): |
||||
return l - r |
||||
else: |
||||
return 0 |
||||
|
||||
|
||||
# A more robust orientation test that's stable in a given triangle (to fix robustness issues). |
||||
func orient(rx, ry, qx, qy, px, py): |
||||
var _sign |
||||
|
||||
if orient_if_sure(px, py, rx, ry, qx, qy): |
||||
_sign = orient_if_sure(px, py, rx, ry, qx, qy) |
||||
elif orient_if_sure(rx, ry, qx, qy, px, py): |
||||
_sign = orient_if_sure(rx, ry, qx, qy, px, py) |
||||
elif orient_if_sure(qx, qy, px, py, rx, ry): |
||||
_sign = orient_if_sure(qx, qy, px, py, rx, ry) |
||||
|
||||
return false if _sign == null else _sign < 0 |
||||
|
||||
|
||||
func in_circle(ax, ay, bx, by, cx, cy, px, py): |
||||
var dx = ax - px |
||||
var dy = ay - py |
||||
var ex = bx - px |
||||
var ey = by - py |
||||
var fx = cx - px |
||||
var fy = cy - py |
||||
|
||||
var ap = dx * dx + dy * dy |
||||
var bp = ex * ex + ey * ey |
||||
var cp = fx * fx + fy * fy |
||||
|
||||
return dx * (ey * cp - bp * fy) -\ |
||||
dy * (ex * cp - bp * fx) +\ |
||||
ap * (ex * fy - ey * fx) < 0 |
||||
|
||||
|
||||
func circumradius(ax, ay, bx, by, cx, cy): |
||||
var dx = bx - ax |
||||
var dy = by - ay |
||||
var ex = cx - ax |
||||
var ey = cy - ay |
||||
|
||||
var bl = dx * dx + dy * dy |
||||
var cl = ex * ex + ey * ey |
||||
|
||||
# When you divide by 0 in Godot you get an error. |
||||
# It should return INF (positive or negative). |
||||
var d |
||||
if (dx * ey - dy * ex) == 0: |
||||
d = INF |
||||
elif (dx * ey - dy * ex) == -0: |
||||
d = -INF |
||||
else: |
||||
d = 0.5 / (dx * ey - dy * ex) |
||||
|
||||
var x = (ey * bl - dy * cl) * d |
||||
var y = (dx * cl - ex * bl) * d |
||||
|
||||
return x * x + y * y |
||||
|
||||
|
||||
func circumcenter(ax, ay, bx, by, cx, cy): |
||||
var dx = bx - ax |
||||
var dy = by - ay |
||||
var ex = cx - ax |
||||
var ey = cy - ay |
||||
|
||||
var bl = dx * dx + dy * dy |
||||
var cl = ex * ex + ey * ey |
||||
|
||||
# When you divide by 0 in Godot you get an error. |
||||
# It should return INF (positive or negative). |
||||
var d |
||||
if (dx * ey - dy * ex) == 0: |
||||
d = INF |
||||
elif (dx * ey - dy * ex) == -0: |
||||
d = -INF |
||||
else: |
||||
d = 0.5 / (dx * ey - dy * ex) |
||||
|
||||
var x = ax + (ey * bl - dy * cl) * d |
||||
var y = ay + (dx * cl - ex * bl) * d |
||||
|
||||
return [x, y] |
||||
|
||||
|
||||
func quicksort(ids, dists, left, right): |
||||
if right - left <= 20: |
||||
for i in range(left + 1, right + 1): |
||||
var temp = ids[i] |
||||
var temp_dist = dists[temp] |
||||
var j = i - 1 |
||||
while j >= left and dists[ids[j]] > temp_dist: |
||||
ids[j + 1] = ids[j] |
||||
j -= 1 |
||||
ids[j + 1] = temp |
||||
else: |
||||
var median = (left + right) >> 1 |
||||
var i = left + 1 |
||||
var j = right |
||||
swap(ids, median, i) |
||||
|
||||
if (dists[ids[left]] > dists[ids[right]]): |
||||
swap(ids, left, right) |
||||
|
||||
if (dists[ids[i]] > dists[ids[right]]): |
||||
swap(ids, i, right) |
||||
|
||||
if (dists[ids[left]] > dists[ids[i]]): |
||||
swap(ids, left, i) |
||||
|
||||
var temp = ids[i] |
||||
var temp_dist = dists[temp] |
||||
|
||||
while true: |
||||
while true: |
||||
i += 1 |
||||
if dists[ids[i]] >= temp_dist: break |
||||
|
||||
while true: |
||||
j -= 1 |
||||
if dists[ids[j]] <= temp_dist: break |
||||
|
||||
if j < i: break |
||||
swap(ids, i, j) |
||||
|
||||
ids[left + 1] = ids[j] |
||||
ids[j] = temp |
||||
|
||||
if right - i + 1 >= j - left: |
||||
quicksort(ids, dists, i, right) |
||||
quicksort(ids, dists, left, j - 1) |
||||
else: |
||||
quicksort(ids, dists, left, j - 1) |
||||
quicksort(ids, dists, i, right) |
||||
|
||||
|
||||
func swap(arr, i, j): |
||||
var tmp = arr[i] |
||||
arr[i] = arr[j] |
||||
arr[j] = tmp |
||||
@ -0,0 +1,7 @@ |
||||
[gd_resource type="Environment" load_steps=2 format=2] |
||||
|
||||
[sub_resource type="ProceduralSky" id=1] |
||||
|
||||
[resource] |
||||
background_mode = 2 |
||||
background_sky = SubResource( 1 ) |
||||
@ -0,0 +1,35 @@ |
||||
[remap] |
||||
|
||||
importer="texture" |
||||
type="StreamTexture" |
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" |
||||
metadata={ |
||||
"vram_texture": false |
||||
} |
||||
|
||||
[deps] |
||||
|
||||
source_file="res://icon.png" |
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] |
||||
|
||||
[params] |
||||
|
||||
compress/mode=0 |
||||
compress/lossy_quality=0.7 |
||||
compress/hdr_mode=0 |
||||
compress/bptc_ldr=0 |
||||
compress/normal_map=0 |
||||
flags/repeat=0 |
||||
flags/filter=true |
||||
flags/mipmaps=false |
||||
flags/anisotropic=false |
||||
flags/srgb=2 |
||||
process/fix_alpha_border=true |
||||
process/premult_alpha=false |
||||
process/HDR_as_SRGB=false |
||||
process/invert_color=false |
||||
process/normal_map_invert_y=false |
||||
stream=false |
||||
size_limit=0 |
||||
detect_3d=true |
||||
svg/scale=1.0 |
||||
@ -0,0 +1,49 @@ |
||||
; Engine configuration file. |
||||
; It's best edited using the editor UI and not directly, |
||||
; since the parameters that go here are not all obvious. |
||||
; |
||||
; Format: |
||||
; [section] ; section goes between [] |
||||
; param=value ; assign values to parameters |
||||
|
||||
config_version=4 |
||||
|
||||
_global_script_classes=[ { |
||||
"base": "Reference", |
||||
"class": "Delaunator", |
||||
"language": "GDScript", |
||||
"path": "res://addons/delaunator/Delaunator.gd" |
||||
}, { |
||||
"base": "Reference", |
||||
"class": "PoissonDiscSampling", |
||||
"language": "GDScript", |
||||
"path": "res://addons/PoissonDiscSampling/PoissonDiscSampling.gd" |
||||
}, { |
||||
"base": "Reference", |
||||
"class": "Terrain", |
||||
"language": "GDScript", |
||||
"path": "res://utils/terrain/Terrain.gd" |
||||
} ] |
||||
_global_script_class_icons={ |
||||
"Delaunator": "", |
||||
"PoissonDiscSampling": "", |
||||
"Terrain": "" |
||||
} |
||||
|
||||
[application] |
||||
|
||||
config/name="Societer" |
||||
run/main_scene="res://world/game.tscn" |
||||
config/icon="res://icon.png" |
||||
|
||||
[gui] |
||||
|
||||
common/drop_mouse_on_gui_input_disabled=true |
||||
|
||||
[physics] |
||||
|
||||
common/enable_pause_aware_picking=true |
||||
|
||||
[rendering] |
||||
|
||||
environment/default_environment="res://default_env.tres" |
||||
@ -0,0 +1,116 @@ |
||||
extends Node2D |
||||
|
||||
var terrain |
||||
|
||||
func create_map(): |
||||
var river = {"size": 3, "color": "blue"} |
||||
|
||||
terrain.get_edge(16).set_data("river", river) |
||||
|
||||
var triangle_idx = 5 |
||||
var triangle = terrain.get_triangle(triangle_idx) |
||||
|
||||
print("Triangle index : %d" % (triangle.get_index())) |
||||
|
||||
var edges = triangle.edges() |
||||
|
||||
print("Number of edges : %d" % (edges.size())) |
||||
print() |
||||
|
||||
for edge in edges: |
||||
print("Edge index : %d" % (edge.get_index())) |
||||
var start_point = edge.start() |
||||
var end_point = edge.end() |
||||
var start = start_point.point2d() |
||||
var end = end_point.point2d() |
||||
|
||||
print("Start point index : %d" % (start_point.get_index())) |
||||
print("End point index : %d" % (end_point.get_index())) |
||||
|
||||
print("Start point : %s" % (start)) |
||||
print("End point : %s" % (end)) |
||||
|
||||
if edge.has_key("river"): |
||||
print("Has river") |
||||
var a_river = edge.get_data("river") |
||||
print("River size : %d" % (a_river["size"])) |
||||
print("River color : %s" % (a_river["color"])) |
||||
|
||||
print() |
||||
print(terrain.get_point(5).point3d()) |
||||
|
||||
|
||||
func draw_triangles(): |
||||
for polygon in terrain.get_triangles_as_polygon(): |
||||
var color = Color(randf(), randf(), randf(), 1) |
||||
if polygon.size() > 2: |
||||
draw_polygon(polygon, PoolColorArray([color])) |
||||
|
||||
func draw_triangles_edges(color=Color("#000000")): |
||||
for line in terrain.get_edges_as_line(): |
||||
draw_line(line[0], line[1], color) |
||||
|
||||
func draw_voronoi_edges(color=Color("#000000")): |
||||
for line in terrain.get_voronoi_edges_as_line(): |
||||
draw_line(line[0], line[1], color) |
||||
|
||||
func draw_voronoi_cells_old(): |
||||
var seen = [] |
||||
for edge_idx in terrain.edges(): |
||||
var triangles = [] |
||||
var vertices = [] |
||||
var p = terrain._triangles[terrain.next_half_edge(edge_idx)] |
||||
if not seen.has(p): |
||||
seen.append(p) |
||||
var edges = terrain.edges_around_point(edge_idx) |
||||
for edge_around_idx in edges: |
||||
triangles.append(terrain.triangle_of_edge(edge_around_idx)) |
||||
for triangle in triangles: |
||||
vertices.append(terrain.triangle_center(triangle)) |
||||
|
||||
if triangles.size() > 2: |
||||
var color = Color(randf(), randf(), randf(), 1) |
||||
var voronoi_cell = PoolVector2Array() |
||||
for vertice in vertices: |
||||
voronoi_cell.append(Vector2(vertice.x, vertice.z)) |
||||
draw_polygon(voronoi_cell, PoolColorArray([color])) |
||||
func draw_voronoi_cells(): |
||||
for polygon in terrain.get_voronoi_cells_as_polygon(): |
||||
var color = Color(randf(), randf(), randf(), 1) |
||||
if polygon.size() > 2: |
||||
draw_polygon(polygon, PoolColorArray([color])) |
||||
|
||||
func draw_voronoi_cells_convex_hull(): |
||||
for point_idx in terrain.points(): |
||||
var triangles = [] |
||||
var vertices = [] |
||||
var incoming = terrain._points_to_half_edges.get(point_idx) |
||||
|
||||
if incoming == null: |
||||
triangles.append(0) |
||||
else: |
||||
var edges = terrain.edges_around_point(incoming) |
||||
for edge_idx in edges: |
||||
triangles.append(terrain.triangle_of_edge(edge_idx)) |
||||
|
||||
for triangle_idx in triangles: |
||||
vertices.append(terrain.triangle_center(triangle_idx)) |
||||
|
||||
if triangles.size() > 2: |
||||
var color = Color(randf(), randf(), randf(), 1) |
||||
var voronoi_cell = PoolVector2Array() |
||||
for vertice in vertices: |
||||
voronoi_cell.append(Vector2(vertice[0], vertice[1])) |
||||
draw_polygon(voronoi_cell, PoolColorArray([color])) |
||||
|
||||
func _draw(): |
||||
print("before drawing") |
||||
draw_triangles() |
||||
# draw_voronoi_cells() |
||||
# draw_triangles_edges() |
||||
# draw_voronoi_cells_convex_hull() |
||||
# draw_voronoi_edges(Color("#ff0000")) |
||||
|
||||
func _on_Game_world_loaded(game_terrain): |
||||
terrain = game_terrain |
||||
create_map() |
||||
@ -0,0 +1,6 @@ |
||||
[gd_scene load_steps=2 format=2] |
||||
|
||||
[ext_resource path="res://ui/map/map.gd" type="Script" id=1] |
||||
|
||||
[node name="Map" type="Node2D"] |
||||
script = ExtResource( 1 ) |
||||
@ -0,0 +1,7 @@ |
||||
[gd_scene load_steps=2 format=2] |
||||
|
||||
[ext_resource path="res://ui/map/map.tscn" type="PackedScene" id=1] |
||||
|
||||
[node name="UI" type="Node2D"] |
||||
|
||||
[node name="Map" parent="." instance=ExtResource( 1 )] |
||||
@ -0,0 +1,332 @@ |
||||
extends Reference |
||||
|
||||
class_name Terrain |
||||
|
||||
class Triangle: |
||||
var _idx |
||||
var _terrain |
||||
|
||||
func _init(idx, terrain): |
||||
self._idx = idx |
||||
self._terrain = terrain |
||||
|
||||
func get_index(): |
||||
return _idx |
||||
|
||||
func has_key(key): |
||||
return _terrain._triangles_data[_idx].has(key) |
||||
|
||||
func set_data(key,value): |
||||
var data = _terrain._triangles_data[_idx] |
||||
data[key] = value |
||||
|
||||
func get_data(key): |
||||
var data = _terrain._triangles_data[_idx] |
||||
if data.has(key): |
||||
return data[key] |
||||
|
||||
func edges(): |
||||
return [Edge.new(3 * _idx, _terrain), Edge.new(3 * _idx + 1, _terrain), Edge.new(3 * _idx + 2, _terrain)] |
||||
|
||||
func points(): |
||||
var list_points = [] |
||||
for edge in edges(): |
||||
list_points.append(Point.new(_terrain._triangles[edge._idx], _terrain)) |
||||
return list_points |
||||
|
||||
func triangles_adjacent(): |
||||
var list_triangles = [] |
||||
for edge in edges(): |
||||
var opposite = Edge.new(_terrain._halfedges[edge._idx], _terrain) |
||||
if opposite._idx >= 0: |
||||
list_triangles.append(opposite.triangle()) |
||||
return list_triangles |
||||
|
||||
func center2d(): |
||||
var points = points() |
||||
return (points[0].point2d() + points[1].point2d() + points[2].point2d()) / 3.0 |
||||
|
||||
func center3d(): |
||||
var points = points() |
||||
return (points[0].point3d() + points[1].point3d() + points[2].point3d()) / 3.0 |
||||
|
||||
|
||||
class Point: |
||||
var _idx |
||||
var _terrain |
||||
|
||||
func _init(idx, terrain): |
||||
self._idx = idx |
||||
self._terrain = terrain |
||||
|
||||
func get_index(): |
||||
return _idx |
||||
|
||||
func has_key(key): |
||||
return _terrain._points_data[_idx].has(key) |
||||
|
||||
func set_data(key,value): |
||||
var data = _terrain._points_data[_idx] |
||||
data[key] = value |
||||
|
||||
func get_data(key): |
||||
var data = _terrain._points_data[_idx] |
||||
if data.has(key): |
||||
return data[key] |
||||
|
||||
func point3d(): |
||||
return _terrain._points[_idx] |
||||
|
||||
func point2d(): |
||||
var point3d:Vector3 = _terrain._points[_idx] |
||||
var point2d:Vector2 = Vector2(point3d.x, point3d.z) |
||||
return(point2d) |
||||
|
||||
func set_elevation(elevation:float): |
||||
_terrain._points[_idx].y = elevation |
||||
|
||||
func get_elevation(): |
||||
return(_terrain._points[_idx].y) |
||||
|
||||
func edges_around(): |
||||
var list_edges = [] |
||||
var incoming_edge = Edge.new(_idx, _terrain) |
||||
var outgoing_edge |
||||
while true: |
||||
list_edges.append(incoming_edge); |
||||
outgoing_edge = incoming_edge.next_half() |
||||
incoming_edge = Edge.new(_terrain._halfedges[outgoing_edge._idx], _terrain); |
||||
if not (incoming_edge._idx != -1 and incoming_edge._idx != _idx): |
||||
break |
||||
return list_edges |
||||
|
||||
func points_around(): |
||||
var list_points = [] |
||||
var incoming = _terrain._points_to_halfedges.get(_idx) |
||||
var incoming_edge = Point.new(incoming, _terrain) |
||||
var outgoing_edge |
||||
while true: |
||||
list_points.append(Point.new(_terrain._triangles[incoming_edge._idx], _terrain)); |
||||
outgoing_edge = incoming_edge.next_half() |
||||
incoming_edge = Edge.new(_terrain._halfedges[outgoing_edge._idx], _terrain); |
||||
if not (incoming_edge._idx != -1 and incoming_edge._idx != incoming): |
||||
break |
||||
return list_points |
||||
|
||||
class Edge: |
||||
var _idx |
||||
var _terrain |
||||
|
||||
func _init(idx, terrain): |
||||
self._idx = idx |
||||
self._terrain = terrain |
||||
|
||||
func get_index(): |
||||
return _idx |
||||
|
||||
func has_key(key): |
||||
return _terrain._edges_data[_idx].has(key) |
||||
|
||||
func set_data(key,value): |
||||
_terrain._edges_data[_idx][key] = value |
||||
|
||||
func get_data(key): |
||||
var data = _terrain._edges_data[_idx] |
||||
if data.has(key): |
||||
return data[key] |
||||
|
||||
func next_half(): |
||||
return Edge.new(_idx - 2 if _idx % 3 == 2 else _idx + 1, _terrain) |
||||
|
||||
func prev_half(): |
||||
return Edge.new(_idx + 2 if _idx % 3 == 0 else _idx -1, _terrain) |
||||
|
||||
func triangle(): |
||||
return Triangle.new(floor(_idx / 3), _terrain) |
||||
|
||||
func start(): |
||||
return Point.new(_terrain._triangles[_idx], _terrain) |
||||
|
||||
func end(): |
||||
return Point.new(_terrain._triangles[next_half()._idx], _terrain) |
||||
|
||||
const terrain_file = "user://terrain.save" |
||||
|
||||
var width: int |
||||
var height: int |
||||
var spacing: int |
||||
var _points = PoolVector3Array() |
||||
var _halfedges |
||||
var _triangles |
||||
var _points_to_halfedges = {} |
||||
var _data = {} |
||||
var _points_data = [] |
||||
var _edges_data = [] |
||||
var _triangles_data = [] |
||||
var _file = File.new() |
||||
var _debug = true |
||||
|
||||
""" |
||||
func general_type_of(obj): |
||||
var typ = typeof(obj) |
||||
var builtin_type_names = ["nil", "bool", "int", "real", "string", "vector2", "rect2", "vector3", "maxtrix32", "plane", "quat", "aabb", "matrix3", "transform", "color", "image", "nodepath", "rid", null, "inputevent", "dictionary", "array", "rawarray", "intarray", "realarray", "stringarray", "vector2array", "vector3array", "colorarray", "unknown"] |
||||
|
||||
if(typ == TYPE_OBJECT): |
||||
return obj.type_of() |
||||
else: |
||||
return builtin_type_names[typ] |
||||
""" |
||||
|
||||
func _print_debug(message): |
||||
if _debug: |
||||
print(message) |
||||
|
||||
func _init(width:int=1600, height:int=800, spacing:int=30, create=false): |
||||
if _file.file_exists(terrain_file) and not create: |
||||
_print_debug("loading...") |
||||
_load() |
||||
else: |
||||
_print_debug("Creating...") |
||||
var delaunay: Delaunator |
||||
self.width = width |
||||
self.height = height |
||||
self.spacing = spacing |
||||
_create_points() |
||||
delaunay = Delaunator.new(_points) |
||||
|
||||
_halfedges = PoolIntArray(delaunay.halfedges) |
||||
_triangles = PoolIntArray(delaunay.triangles) |
||||
|
||||
# Initialize _points_to_halfedges |
||||
for edge_idx in edges(): |
||||
var edge = get_edge(edge_idx) |
||||
var endpoint = _triangles[edge.next_half().get_index()] |
||||
if (! _points_to_halfedges.has(endpoint) or _halfedges[edge_idx] == -1): |
||||
_points_to_halfedges[endpoint] = edge_idx |
||||
|
||||
# Initialise _points_data |
||||
for point_idx in points(): |
||||
_points_data.append({}) |
||||
|
||||
# Initialise _edges_data |
||||
for edge_idx in edges(): |
||||
_edges_data.append({}) |
||||
|
||||
# Initialise _triangle_data |
||||
for triangle_idx in triangles(): |
||||
_triangles_data.append({}) |
||||
|
||||
_save() |
||||
|
||||
func _create_points(): |
||||
var rect = Rect2(Vector2(0, 0), Vector2(width, height)) |
||||
var poisson_disc_sampling: PoissonDiscSampling = PoissonDiscSampling.new() |
||||
var points2d = poisson_disc_sampling.generate_points(spacing, rect, 5) |
||||
_points.resize(points2d.size()) |
||||
for point_idx in points2d.size(): |
||||
_points[point_idx].x = points2d[point_idx].x |
||||
_points[point_idx].z = points2d[point_idx].y |
||||
|
||||
func get_triangles(): |
||||
return _triangles |
||||
|
||||
func get_halfedges(): |
||||
return _halfedges |
||||
|
||||
# return que les id ? |
||||
func get_points(): |
||||
return _points |
||||
|
||||
func get_point(idx): |
||||
return Point.new(idx, self) |
||||
|
||||
func get_edge(idx): |
||||
return Edge.new(idx, self) |
||||
|
||||
func get_triangle(idx): |
||||
return Triangle.new(idx, self) |
||||
|
||||
func triangles(): |
||||
return _triangles.size() / 3 |
||||
|
||||
func points(): |
||||
return _points.size() |
||||
|
||||
func edges(): |
||||
return _triangles.size() |
||||
|
||||
# Voronoi |
||||
|
||||
func centroid(points): |
||||
return Vector3((points[0].x + points[1].x + points[2].x) / 3.0, 0.0, (points[0].z + points[1].z + points[2].z) / 3.0) |
||||
|
||||
|
||||
func _save(): |
||||
_file.open(terrain_file, File.WRITE) |
||||
_file.store_var(width) |
||||
_file.store_var(height) |
||||
_file.store_var(spacing) |
||||
_file.store_var(_points) |
||||
_file.store_var(_halfedges) |
||||
_file.store_var(_triangles) |
||||
_file.store_var(_points_to_halfedges) |
||||
_file.store_var(_points_data) |
||||
_file.store_var(_edges_data) |
||||
_file.store_var(_triangles_data) |
||||
_file.close() |
||||
|
||||
func _load(): |
||||
_file.open(terrain_file, File.READ) |
||||
width = _file.get_var() |
||||
height = _file.get_var() |
||||
spacing = _file.get_var() |
||||
_points = _file.get_var() |
||||
_halfedges = _file.get_var() |
||||
_triangles = _file.get_var() |
||||
_points_to_halfedges = _file.get_var() |
||||
_points_data = _file.get_var() |
||||
_edges_data = _file.get_var() |
||||
_triangles_data = _file.get_var() |
||||
_file.close() |
||||
|
||||
func get_triangles_as_polygon(): |
||||
var list_polygon = [] |
||||
for triangle_idx in triangles(): |
||||
var polygon = [] |
||||
for point in get_triangle(triangle_idx).points(): |
||||
polygon.append(point.point2d()) |
||||
list_polygon.append(polygon) |
||||
return list_polygon |
||||
|
||||
func get_edges_as_line(): |
||||
var list_lines = [] |
||||
for edge_idx in edges(): |
||||
var line = [] |
||||
var edge = get_edge(edge_idx) |
||||
line.append(edge.start().point2d()) |
||||
line.append(edge.end().point2d()) |
||||
list_lines.append(line) |
||||
return list_lines |
||||
|
||||
func get_voronoi_edges_as_line(): |
||||
var list_lines = [] |
||||
for edge_idx in edges(): |
||||
var line = [] |
||||
var start_edge = get_edge(edge_idx) |
||||
var end_edge = get_edge(_halfedges[edge_idx]) |
||||
if (edge_idx < _halfedges[edge_idx]): |
||||
line.append(start_edge.triangle().center2d()) |
||||
line.append(end_edge.triangle().center2d()) |
||||
list_lines.append(line) |
||||
return list_lines |
||||
|
||||
func get_voronoi_cells_as_polygon(): |
||||
var list_polygon = [] |
||||
for point_idx in points(): |
||||
var point = get_point(point_idx) |
||||
var polygon = [] |
||||
for edge in point.edges_around(): |
||||
polygon.append(edge.triangle().center2d()) |
||||
list_polygon.append(polygon) |
||||
return(list_polygon) |
||||
|
||||
@ -0,0 +1,70 @@ |
||||
extends Spatial |
||||
|
||||
signal world_loaded |
||||
|
||||
export(int) var width = 2000 |
||||
export(int) var height = 2000 |
||||
export(int) var spacing = 20 |
||||
export(int, 1, 9) var octaves = 5 |
||||
export(int, 1, 30) var wavelength = 8 |
||||
export(int) var border_width = 200 |
||||
export(int) var terraces = 24 |
||||
export(int) var terrace_height = 5 |
||||
export(int) var mountain_height = 6 |
||||
export(int) var river_proba = 200 |
||||
|
||||
var rng = RandomNumberGenerator.new() |
||||
var noise = OpenSimplexNoise.new() |
||||
|
||||
var terrain |
||||
|
||||
func _ready(): |
||||
rng.randomize() |
||||
noise.seed = rng.randi() |
||||
noise.octaves = octaves |
||||
terrain = Terrain.new(width,height,spacing,true) |
||||
init_points_data() |
||||
print(terrain.get_point(3)) |
||||
emit_signal("world_loaded", terrain) |
||||
|
||||
func init_points_data(): |
||||
for index in terrain.get_points().size(): |
||||
terrain.get_point(index).set_elevation(find_elevation(terrain.get_point(index).point2d())) |
||||
# points_data.append({ |
||||
# "elevation": 0, |
||||
# "used": false, |
||||
# "water": false, |
||||
# "ocean": false, |
||||
# "coast": false, |
||||
# "mountain": false, |
||||
# "river": false |
||||
# }) |
||||
|
||||
func find_elevation(point): |
||||
var border = border_width + rng.randf_range(-20.0, 20.0) |
||||
var elevation = noise.get_noise_2d(point.x / wavelength, point.y / wavelength) |
||||
|
||||
if point.x < border: |
||||
elevation -= ((border - point.x) / border) / 2.0 |
||||
if point.y < border: |
||||
elevation -= (border - point.y) / border |
||||
if point.x > width - border: |
||||
elevation -= (border - (width - point.x)) / border |
||||
if point.y > height - border: |
||||
elevation -= (border - (height - point.y)) / border |
||||
|
||||
elevation = max(elevation, -1) |
||||
|
||||
if elevation > 0.1: |
||||
elevation = max(pow((elevation) * 1.2, 1.5), 0.1) |
||||
|
||||
elevation = min(elevation, 1) |
||||
|
||||
elevation = elevation * terraces |
||||
return elevation |
||||
# |
||||
# if points_data[point_id].elevation <= 0: |
||||
# points_data[point_id].water = true |
||||
# |
||||
# if points_data[point_id].elevation >= mountain_height: |
||||
# points_data[point_id].mountain = true |
||||
@ -0,0 +1,13 @@ |
||||
[gd_scene load_steps=3 format=2] |
||||
|
||||
[ext_resource path="res://ui/ui.tscn" type="PackedScene" id=1] |
||||
[ext_resource path="res://world/game.gd" type="Script" id=2] |
||||
|
||||
[node name="Game" type="Spatial"] |
||||
script = ExtResource( 2 ) |
||||
|
||||
[node name="UI" parent="." instance=ExtResource( 1 )] |
||||
|
||||
[connection signal="world_loaded" from="." to="UI/Map" method="_on_Game_world_loaded"] |
||||
|
||||
[editable path="UI"] |
||||
Loading…
Reference in new issue