You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
Gridmap/scripts/WorldGeneration (copie).gd

437 lines
12 KiB

extends Control
@export var world_width = 1024
@export var world_height = 512
@export var min_continent = 5
@export var max_continent = 5
@export var min_area = 0.5
@export var max_area = 2.0
@export var min_ratio = -1.0
@export var max_ratio = 1.0
@export var ocean_ratio = 0
@export var nbr_rect_position = 10000
@export var max_intersection_area = 1000.0
@export var mountain_frequency = 1.5 # higher number means less mountains
@export var world_elevation = 10
@export var details = 2
@export var coasts_thickness = 0.055
var heightmap: Array
var oceanmap: Array
var coastmap: Array
var slopemap: Array
var rivers: Array
var continents: Array
var nbr_continent
var list_continents = []
var list_rect_continents = []
var blocs: Array
var mountain_blocs: Array
var noise = FastNoiseLite.new()
func _ready():
Global.world.width = world_width
Global.world.height = world_height
noise.seed = randi()
noise.fractal_lacunarity = details
noise.frequency = 0.005
init_maps()
init_blocs()
create_continents()
# pangea()
for continent in continents:
fill_continent(continent)
set_oceans()
set_coasts()
# set_slope()
# for x in 50000:
# erode(Vector2i(randi_range(0, world_width), randi_range(0, world_height)))
fix_heightmap()
# set_rivers()
set_blocs()
Global.world.heightMap = heightmap
Global.world.blocs = blocs
get_tree().change_scene_to_file("scenes/Game.tscn")
func init_maps():
for x in world_width:
heightmap.append([])
oceanmap.append([])
coastmap.append([])
slopemap.append([])
for y in world_height:
heightmap[x].append([])
heightmap[x][y] = 0
oceanmap[x].append([])
oceanmap[x][y] = 0
coastmap[x].append([])
coastmap[x][y] = 0
slopemap[x].append([])
slopemap[x][y] = 0
func create_continents():
var america = Rect2i(Vector2i(0, 0), Vector2i(world_width / 4, world_height))
continents.append(america)
var antarctica = Rect2i(Vector2i(world_width / 4, world_height / 2), Vector2i(3 * world_width / 4, world_height / 2))
continents.append(antarctica)
var africa = Rect2i(Vector2i(world_width / 4, 3 * world_height / 8), Vector2i(3 * world_width / 8, 3 * world_height / 8))
continents.append(africa)
var europa = Rect2i(Vector2i(3 * world_width / 8, 10), Vector2i(world_width / 4, world_height / 2))
continents.append(europa)
var asia = Rect2i(Vector2i(4 * world_width / 9, world_height / 8), Vector2i(world_width / 2, 3 * world_height / 8))
continents.append(asia)
func pangea():
var pangea = Rect2i(Vector2i(0, 0), Vector2i(world_width, world_height))
continents.append(pangea)
# var rng = RandomNumberGenerator.new()
#
# var continents_area = world_width * world_height * (1.0 - ocean_ratio)
# var total_area = 0.0
# var list_other_continents = []
#
# rng.randomize()
#
# nbr_continent = rng.randi_range(min_continent,max_continent)
#
# for i in nbr_continent:
# var continent = {}
# continent["area"] = rng.randf_range(min_area,max_area)
# continent["ratio"] = exp(rng.randf_range(min_ratio,max_ratio))
# continent["width"] = 0.0
# continent["height"] = 0.0
# continent["x"] = 0.0
# continent["y"] = 0.0
# total_area += continent["area"]
# list_continents.append(continent)
#
# # print("Total area : %f\n" % [total_area])
#
# for continent in list_continents:
# continent["area"] = (continent["area"] * continents_area / total_area)
# continent["height"] = sqrt(continent["area"] / continent["ratio"])
# continent["width"] = continent["area"] / continent["height"]
# var rect_continent
# var selected_rect_continent
# var min_intersection_area = 99999999.99
#
# for i in nbr_rect_position:
# var intersection_area = 0.0
#
# var x = rng.randf_range(0.0,world_width - continent["width"])
# var y = rng.randf_range(0.0,world_height - continent["height"])
#
# rect_continent = Rect2(x, y, continent["width"], continent["height"])
#
# for other_continent in list_other_continents:
# var rect_other_continent = Rect2(other_continent["x"], other_continent["y"], other_continent["width"], other_continent["height"])
# if rect_continent.intersects(rect_other_continent):
# # print("Ok intersection\n")
# intersection_area += rect_continent.intersection(rect_other_continent).get_area()
#
# if intersection_area < min_intersection_area:
# min_intersection_area = intersection_area
# continent["x"] = x
# continent["y"] = y
#
# list_other_continents.append(continent)
# continents.append(Rect2(continent["x"], continent["y"], continent["width"], continent["height"]))
func fill_continent(continent: Rect2i):
for x in continent.size.x:
for y in continent.size.y:
# set rectange radius
var center = Vector2(float(continent.size.x) / 2.0, float(continent.size.y) / 2.0)
var distance_x = abs(float(x) - center.x) / center.x
var distance_y = abs(float(y) - center.y) / center.y
var distance = sqrt(pow(distance_x, 2) + pow(distance_y, 2))
distance = remap(distance, 0, sqrt(2), 0, 1) * 1.2
# set height
var height = noise.get_noise_2d(x, y)
height = remap(height, -1, 1, 0, 1)
height -= distance
if height > 0:
var current_height = heightmap[continent.position.x + x][continent.position.y + y]
height = pow(height * 1.2, mountain_frequency)
height = remap(height, 0, 1, 1, world_elevation)
heightmap[continent.position.x + x][continent.position.y + y] = max(current_height, height)
if height > heightmap[continent.position.x + x][continent.position.y + y]:
heightmap[continent.position.x + x][continent.position.y + y] = height
elif height > 0 - coasts_thickness:
coastmap[x + continent.position.x][y + continent.position.y] = 1
#func sampleNormal(position: Vector2i):
# var left = heightmap[position.x - 1][position.y]
# var right = heightmap[position.x + 1][position.y]
# var top = heightmap[position.x][position.y - 1]
# var bottom = heightmap[position.x][position.y + 1]
#
## Vec3 normal = Vec3(2*(R-L), 2*(B-T), -4).Normalize();
## return Vector3i(2 * heightmap)
# pass
func erode(position: Vector2i):
const dropsPerCell = .4
const erosionRate = 1
const depositionRate = 0.7
const speed = .15
const friction = .7
const radius = .8
const maxIterations = 80
const iterationScale = .04
var ox = (randf() * 2 - 1) * radius # The X offset
var oy = (randf() * 2 - 1) * radius # The Y offset
var sediment = 0 # The amount of carried sediment
var xp = position.x # The previous X position
var yp = position.y # The previous Y position
var vx = 0 # The horizontal velocity
var vy = 0 # The vertical velocity
for i in maxIterations:
# Get the surface normal of the terrain at the current location
# var surfaceNormal = heightMap.sampleNormal(x + ox, y + oy)
var surfaceNormal = normal(Vector2i(position.x + ox, position.y + oy))
# If the terrain is flat, stop simulating, the snowball cannot roll any further
if (surfaceNormal.y == 1):
break
# Calculate the deposition and erosion rate
var deposit = sediment * depositionRate * surfaceNormal.y
var erosion = erosionRate * (1 - surfaceNormal.y) * min(1, i * iterationScale)
# print(deposit)
# print(erosion)
# Change the sediment on the place this snowball came from
# print(heightmap[xp][yp])
# heightmap[xp][yp] += deposit - erosion
heightmap[xp][yp] = 0
# print(heightmap[xp][yp])
sediment += erosion - deposit;
vx = friction * vx + surfaceNormal.x * speed
vy = friction * vy + surfaceNormal.z * speed
xp = position.x
yp = position.y
position.x += vx
position.y += vy
pass
func set_oceans():
var stack = []
var first_coord = Vector2i(0, 0)
stack.append(first_coord)
while stack.size():
var coord = stack.pop_back()
oceanmap[coord.x][coord.y] = 1
for neighbour in neighbours(coord).values():
if heightmap[neighbour.x][neighbour.y] == 0 and oceanmap[neighbour.x][neighbour.y] == 0:
stack.append(neighbour)
for x in world_width:
for y in world_height:
if heightmap[x][y] == 0 and not oceanmap[x][y]:
heightmap[x][y] = 2
func set_coasts():
for x in world_width:
for y in world_height:
if coastmap[x][y] and heightmap[x][y] == 0:
heightmap[x][y] = 1
pass
func neighbours(coord: Vector2i):
var neighbours: Dictionary
if coord.x + 1 < world_width:
neighbours.right = Vector2i(coord.x + 1, coord.y)
if coord.y + 1 < world_height :
neighbours.bottom = Vector2i(coord.x, coord.y + 1)
if coord.x - 1 >= 0:
neighbours.left = Vector2i(coord.x - 1, coord.y)
if coord.y - 1 >= 0:
neighbours.top = Vector2i(coord.x, coord.y - 1)
return neighbours
func normal(coord: Vector2i):
var neighbours = neighbours(coord)
if neighbours.size() < 4:
return Vector3(0, 1, 0)
# var normal = Vector3(2 * (neighbours.right - neighbours.left), 2 * (neighbours.bottom - neighbours.top), -4)
var normal = Vector3(
heightmap[neighbours.left.x][neighbours.left.y] - heightmap[neighbours.right.x][neighbours.right.y],
2,
heightmap[neighbours.top.x][neighbours.top.y] - heightmap[neighbours.bottom.x][neighbours.bottom.y]).normalized()
return normal
func set_slope():
for x in world_width:
for y in world_height:
var direction = null
var min_height = heightmap[x][y]
if x + 1 < world_width:
if heightmap[x + 1][y] < min_height:
min_height = heightmap[x + 1][y]
direction = "right"
if y + 1 < world_height:
if heightmap[x][y + 1] < min_height:
min_height = heightmap[x][y + 1]
direction = "bottom"
if x - 1 < world_width:
if heightmap[x - 1][y] < min_height:
min_height = heightmap[x - 1][y]
direction = "left"
if y - 1 < world_height:
if heightmap[x][y - 1] < min_height:
min_height = heightmap[x][y - 1]
direction = "top"
slopemap[x][y] = direction
func set_rivers():
for i in 20:
var good_river = false
while not good_river:
var river_path = []
var reached = false
var coord = mountain_blocs[randi_range(0, mountain_blocs.size()-1)]
var old_direction
while not reached:
var direction = slopemap[coord.x][coord.y]
if heightmap[coord.x][coord.y] == 1 or direction == opposite_direction(old_direction):
direction = old_direction
old_direction = direction
river_path.append({"coord": coord, "thickness": 5, "direction": direction})
if direction == "right":
coord = Vector2(coord.x + 1, coord.y)
elif direction == "bottom":
coord = Vector2(coord.x, coord.y + 1)
elif direction == "left":
coord = Vector2(coord.x - 1, coord.y)
elif direction == "top":
coord = Vector2(coord.x, coord.y - 1)
else:
reached = true
if (
heightmap[river_path.back().coord.x][river_path.back().coord.y] == 0 and
heightmap[river_path.back().coord.x] != heightmap[river_path.front().coord.x] and
heightmap[river_path.back().coord.y] != heightmap[river_path.front().coord.y]
):
good_river = true
rivers.append(river_path)
for river in rivers:
var coord: Vector2
for bloc in river:
for i in bloc.thickness:
if perpendicular_direction(bloc.direction) == "right":
coord = Vector2(bloc.coord.x + i, bloc.coord.y)
elif perpendicular_direction(bloc.direction) == "bottom":
coord = Vector2(bloc.coord.x, bloc.coord.y + i)
elif perpendicular_direction(bloc.direction) == "left":
coord = Vector2(bloc.coord.x - i, bloc.coord.y)
elif perpendicular_direction(bloc.direction) == "top":
coord = Vector2(bloc.coord.x, bloc.coord.y - i)
if blocs[coord.x][coord.y].type != Global.blocs.WATER:
# heightmap[coord.x][coord.y] -= 1
blocs[coord.x][coord.y].type = Global.blocs.WATER
func opposite_direction(direction):
if direction == "top":
return("bottom")
if direction == "bottom":
return "top"
if direction == "left":
return "right"
if direction == "right":
return "left"
return null
func perpendicular_direction(direction):
if direction == "top":
return("left")
if direction == "bottom":
return "right"
if direction == "left":
return "top"
if direction == "right":
return "bottom"
return null
func fix_heightmap():
for x in world_width:
for y in world_height:
heightmap[x][y] = ceil(heightmap[x][y])
# if heightmap[x][y] > 4:
# mountain_blocs.append(Vector2i(x, y))
func init_blocs():
for x in world_width:
blocs.append([])
for y in world_height:
var bloc = {
"type": 0,
"entity": -1
}
blocs[x].append(bloc)
func set_blocs():
for x in world_width:
for y in world_height:
if not blocs[x][y].type:
if heightmap[x][y] > 0:
blocs[x][y].type = Global.blocs.SAND
if heightmap[x][y] > 1:
blocs[x][y].type = Global.blocs.GRASS
if heightmap[x][y] > 10:
blocs[x][y].type = Global.blocs.STONE
if heightmap[x][y] > 15:
blocs[x][y].type = Global.blocs.SNOW
return blocs