226 lines
5.3 KiB
GDScript
226 lines
5.3 KiB
GDScript
extends Node2D
|
|
|
|
enum Stats {WATER, FERTILITY, PRESENCE}
|
|
|
|
const TERRAIN_SIZE = Vector2i(300, 300)
|
|
const LEVELS_NUMBER : int = 20
|
|
const MAP_RATIO = 10;
|
|
|
|
@onready var image := Image.create_empty(
|
|
TERRAIN_SIZE.x,
|
|
TERRAIN_SIZE.y,
|
|
true,
|
|
Image.Format.FORMAT_RGBF
|
|
)
|
|
@onready var texture : ImageTexture = ImageTexture.create_from_image(image)
|
|
|
|
var sum := 0.0
|
|
|
|
func _ready():
|
|
setup_texture(Vector3i(0, 0, -5))
|
|
|
|
func map_to_pixel(
|
|
pos : Vector2
|
|
) -> Vector2i :
|
|
return Vector2i(
|
|
int(pos.x / MAP_RATIO),
|
|
int(pos.y / MAP_RATIO)
|
|
)
|
|
|
|
func is_on_map_real(pos: Vector2) -> bool:
|
|
return pos.x >= 0 and pos.x < TERRAIN_SIZE.x * MAP_RATIO and pos.y >= 0 and pos.y < TERRAIN_SIZE.y * MAP_RATIO
|
|
|
|
func is_on_map_image(pos: Vector2) -> bool:
|
|
return pos.x >= 0 and pos.x < TERRAIN_SIZE.x and pos.y >= 0 and pos.y < TERRAIN_SIZE.y
|
|
|
|
func color_value_to_level(
|
|
color_value : float
|
|
) -> int:
|
|
return roundi(color_value*LEVELS_NUMBER) - float(LEVELS_NUMBER)/2
|
|
|
|
func color_to_levels(
|
|
color: Color
|
|
) -> Vector3i :
|
|
return Vector3i(
|
|
color_value_to_level(color.r),
|
|
color_value_to_level(color.g),
|
|
color_value_to_level(color.b),
|
|
)
|
|
|
|
func level_to_color_value(
|
|
level : int
|
|
) -> float:
|
|
var limited_level = max(
|
|
min(
|
|
level,
|
|
float(LEVELS_NUMBER)/2
|
|
),
|
|
-float(LEVELS_NUMBER)/2
|
|
)
|
|
return float(limited_level+float(LEVELS_NUMBER)/2)/LEVELS_NUMBER
|
|
|
|
func levels_to_color(
|
|
levels: Vector3i
|
|
) -> Color :
|
|
return Color(
|
|
level_to_color_value(levels.x),
|
|
level_to_color_value(levels.y),
|
|
level_to_color_value(levels.z)
|
|
)
|
|
|
|
func modification_to_levels(
|
|
stat: Stats,
|
|
modification: int
|
|
) -> Vector3i :
|
|
var levels = Vector3i()
|
|
match stat:
|
|
Stats.WATER:
|
|
levels.x = modification
|
|
Stats.FERTILITY:
|
|
levels.y = modification
|
|
Stats.PRESENCE:
|
|
levels.z = modification
|
|
return levels
|
|
|
|
func modify_pixel(
|
|
pixel_pos: Vector2i,
|
|
stat: Stats,
|
|
modification: int,
|
|
):
|
|
if not is_on_map_image(pixel_pos):
|
|
return
|
|
var actual_levels = color_to_levels(image.get_pixelv(pixel_pos))
|
|
var modification_levels = modification_to_levels(stat, modification)
|
|
var calculated_levels = actual_levels + modification_levels
|
|
set_pixel(pixel_pos, calculated_levels)
|
|
|
|
func set_pixel(
|
|
pixel_pos: Vector2i,
|
|
level: Vector3i,
|
|
):
|
|
if not is_on_map_image(pixel_pos):
|
|
return
|
|
image.set_pixelv(pixel_pos, levels_to_color(level))
|
|
|
|
func modify_zone(
|
|
center: Vector2,
|
|
radius: float,
|
|
stat : Stats,
|
|
modification: int
|
|
):
|
|
var pixel_center = map_to_pixel(center)
|
|
var pixel_radius = int(radius / MAP_RATIO)
|
|
for x in range(pixel_center.x - pixel_radius, pixel_center.x + pixel_radius + 1) :
|
|
for y in range(pixel_center.y - pixel_radius, pixel_center.y + pixel_radius + 1):
|
|
if not is_on_map_image(Vector2i(x, y)):
|
|
continue
|
|
if pow(x - pixel_center.x,2) + pow(y - pixel_center.y,2) <= pow(pixel_radius,2):
|
|
modify_pixel(
|
|
Vector2i(x, y),
|
|
stat,
|
|
modification
|
|
)
|
|
update_texture()
|
|
|
|
func modify_zone_falloff(
|
|
center: Vector2,
|
|
radius: float,
|
|
falloff_extraradius: float,
|
|
stat : Stats,
|
|
modification: int
|
|
):
|
|
var pixel_center := map_to_pixel(center)
|
|
var pixel_radius := int(radius / MAP_RATIO)
|
|
var pixel_falloff_radius := int(falloff_extraradius / MAP_RATIO)
|
|
for x in range(pixel_center.x - pixel_radius - pixel_falloff_radius, pixel_center.x + pixel_radius + pixel_falloff_radius + 1) :
|
|
for y in range(pixel_center.y - pixel_radius - pixel_falloff_radius, pixel_center.y + pixel_radius + pixel_falloff_radius + 1):
|
|
if not is_on_map_image(Vector2i(x, y)):
|
|
continue
|
|
var pos := Vector2i(x, y)
|
|
var dist_to_center := pos.distance_to(pixel_center)
|
|
if dist_to_center <= pixel_radius:
|
|
modify_pixel(pos, stat, modification)
|
|
elif modification > 1 and dist_to_center <= pixel_radius + falloff_extraradius:
|
|
var new_modif = lerp(modification, 1, (dist_to_center - pixel_radius) / pixel_falloff_radius)
|
|
modify_pixel(pos, stat, new_modif)
|
|
update_texture()
|
|
|
|
func modify_rect(
|
|
pos: Vector2,
|
|
size: Vector2,
|
|
stat : Stats,
|
|
modification: int
|
|
):
|
|
var pixel_pos = map_to_pixel(pos)
|
|
var pixel_size = map_to_pixel(size)
|
|
for x in range(pixel_pos.x, pixel_pos.x+pixel_size.x) :
|
|
for y in range(pixel_pos.y, pixel_pos.y+pixel_size.y):
|
|
modify_pixel(
|
|
Vector2i(x, y),
|
|
stat,
|
|
modification
|
|
)
|
|
update_texture()
|
|
|
|
func get_color(
|
|
pos: Vector2
|
|
) -> Color:
|
|
var pixel_pos = map_to_pixel(pos)
|
|
return image.get_pixelv(pixel_pos)
|
|
|
|
func get_levels(
|
|
pos: Vector2,
|
|
) -> Vector3i:
|
|
if not is_on_map_real(pos):
|
|
return Vector3i()
|
|
var pixel_pos = map_to_pixel(pos)
|
|
return color_to_levels(image.get_pixelv(pixel_pos))
|
|
|
|
func get_stat(
|
|
pos: Vector2,
|
|
stat : Stats
|
|
) -> int:
|
|
var levels = get_levels(pos)
|
|
match stat:
|
|
Stats.WATER:
|
|
return levels.x
|
|
Stats.FERTILITY:
|
|
return levels.y
|
|
Stats.PRESENCE:
|
|
return levels.z
|
|
_:
|
|
return 0
|
|
|
|
func setup_texture(
|
|
levels : Vector3i
|
|
):
|
|
var water_noise := generate_noise()
|
|
var fertility_noise := generate_noise()
|
|
|
|
for x in range(0, TERRAIN_SIZE.x) :
|
|
for y in range(0, TERRAIN_SIZE.y):
|
|
set_pixel(
|
|
Vector2i(x,y),
|
|
Vector3i(
|
|
color_value_to_level(water_noise.get_noise_2d(x, y)),
|
|
color_value_to_level(fertility_noise.get_noise_2d(x, y)/2),
|
|
-LEVELS_NUMBER/2
|
|
)
|
|
)
|
|
update_texture()
|
|
|
|
func generate_noise() -> Noise:
|
|
var noise := FastNoiseLite.new()
|
|
noise.seed = randi()
|
|
noise.fractal_lacunarity = 1
|
|
noise.frequency = 0.005
|
|
noise.fractal_gain = 1000
|
|
|
|
return noise
|
|
|
|
func update_texture():
|
|
texture.update(image)
|
|
|
|
func get_texture():
|
|
return texture
|