Godot Version
4.2.1
Question
For my Grand Strategy game, I am looking to use maps generated by Godot’s FastNoiseLite
implementation of Perlin noise. While generating the texture for the map was straightforward, I’ve already spent weeks to figure out a way to determine the overall terrain type of Voronoi cells drawn on the map by checking the noise values for a set of “checkpoints” and applying a set of rules . For this, I implemented a “Star Check” to spread points on the borders of each cell and from those border points to the respective site points, like so:
func star_check(cell_center: Vector2, n_steps: int=10) -> Array:
var terrain_types: Array
var polygon: Array = _polygon
var n_points = polygon.size()
var checkpoints: Array
var lines: Array
# read in lines as arrays of [start, end point, distance]
for i in range(n_points):
var last_index: int = n_points - 1
var line: Array
match i:
last_index:
line = [polygon[i],polygon[0],polygon[i].distance_to(polygon[0])]
_:
line = [polygon[i],polygon[i + 1],polygon[i].distance_to(polygon[i + 1])]
lines.append(line)
var border_checkpoints: Array
# compute ceckpoints along edges of points
for line in lines:
var line_points: Array = []
var step_size: int = floor(line[2] / n_steps)
var from: Vector2 = line[0]
var to: Vector2 = line[1]
for k in range(n_steps):
var point: Vector2 = from + k * step_size * from.direction_to(to)
line_points.append(point)
border_checkpoints.append_array(line_points)
var center_lines: Array = border_checkpoints.map(func(p):
return [p, cell_center, p.distance_to(cell_center)]
)
# compute center checkpoints from border points
var center_checkpoints: Array
for line in center_lines:
var line_points: Array = []
var step_size: int = floor(line[2] / n_steps)
var from: Vector2 = Vector2(line[0])
var to: Vector2 = Vector2(line[1])
for k in range(n_steps):
var point: Vector2 = from + k * step_size * from.direction_to(to)
line_points.append(point)
center_checkpoints.append_array(line_points)
border_checkpoints.append_array(center_checkpoints)
checkpoints = border_checkpoints.filter(func(p): return Geometry2D.is_point_in_polygon(p, _polygon)) #only use points in voronoi site
check_points = checkpoints #internal class_variable
terrain_types = checkpoints.map(func(p): return _evaluate_point_type(p))
check_point_values = terrain_types #internal class_variables
return terrain_types
Determining the terrain type of a point is done in _evaluate_point_type
using enums to represent their position in the (non-normalized and centered) NoiseTexture
’s color ramp:
enum Terrains {DEEP_OCEAN, SHALLOW_OCEAN, COAST, GRASSLAND, MOUNTAIN_BOTTOM, MOUNTAIN_MEDIUM, MOUNTAIN_TOP}
func _evaluate_point_type(point: Vector2) -> int:
var point_value = ((_map_noise.get_noise_2dv(point) + 1) * 0.5) #translate to [0,1] for offset matching
var type: int = -1
var offsets = _terrain_gradient.offsets
var last_index: int = len(offsets) - 1
for i in range(len(offsets)): #find corresponding offset
match i:
0:
if point_value < offsets[Terrains.SHALLOW_OCEAN]: #everything below first non-zero offset
type = Terrains.DEEP_OCEAN
last_index:
if point_value > offsets[Terrains.MOUNTAIN_TOP]: # everything above highest offset
type = Terrains.MOUNTAIN_TOP
_:
if point_value >= offsets[i] and point_value < offsets[i + 1]:
type = i
return type
The noise gradient is loaded from a saved Gradient
resource that corresponds to the color ramp used by the noise texture:
[gd_resource type="Gradient" format=3 uid="uid://wrob2ye40vuu"]
[resource]
interpolation_mode = 1
offsets = PackedFloat32Array(0, 0.481236, 0.505519, 0.516556, 0.626932, 0.660044, 0.679912)
colors = PackedColorArray(0, 0, 1, 1, 0.299985, 0.470862, 1, 1, 0.657183, 0.508635, 0.167871, 1, 0.280679, 0.399257, 0.108318, 1, 0.333719, 0.196772, 0.0853799, 1, 0.396025, 0.358924, 0.223805, 1, 1, 1, 1, 1)
and the noise texture’s underlying parameters are loaded from this resource:
[gd_resource type="FastNoiseLite" format=3 uid="uid://davh6t1gndhdm"]
[resource]
noise_type = 3
frequency = 0.002
fractal_lacunarity = 2.575
domain_warp_type = 1
domain_warp_amplitude = 29.055
Now, instead of a representation of the point type, I get results that don’t correspond to what I see on the texture. When plotting these points using the color in the gradient corresponding to their values, I often find blue ocean points on green grassland portions or coastline points showing up in ocean parts. I’d be grateful for any pointers to what I might be doing wrong here.
Example of point on “mountain” portion of gradient being evaluated as an ocean point (circle is larger than point for visibility)