Procedural Generation question!

there is some generation also i didn’t use this,this time!

noise_val = (noise_val + 1.0) * 0.5

also is this supposed to look ike this ? :sweat_smile:

var water_cells = [Vector2i(0, 0), Vector2i(0, 1), Vector2i(0, 2), Vector2i(0, 3),
	Vector2i(1, 0), Vector2i(1, 1), Vector2i(1, 2), Vector2i(1, 3),
	Vector2i(2, 0), Vector2i(2, 1), Vector2i(2, 2), Vector2i(2, 3),
	Vector2i(3, 0), Vector2i(3, 1), Vector2i(3, 2), Vector2i(3, 3),
	Vector2i(4, 0), Vector2i(4, 1), Vector2i(4, 2), Vector2i(4, 3),
	Vector2i(5, 0), Vector2i(5, 1), Vector2i(5, 2), Vector2i(5, 3),
	Vector2i(6, 0), Vector2i(6, 1), Vector2i(6, 2), Vector2i(6, 3),
	Vector2i(7, 0), Vector2i(7, 1), Vector2i(7, 2), Vector2i(7, 3),
	Vector2i(8, 0), Vector2i(8, 1), Vector2i(8, 2), Vector2i(8, 3),
	Vector2i(9, 0), Vector2i(9, 1), Vector2i(9, 2), Vector2i(9, 3),
	Vector2i(10, 0), Vector2i(10, 1), Vector2i(10, 2), Vector2i(10, 3),
	Vector2i(11, 0), Vector2i(11, 1), Vector2i(11, 2), Vector2i(11, 3)]
	var sand_cells = [Vector2i(0, 0), Vector2i(0, 1), Vector2i(0, 2), Vector2i(0, 3), Vector2i(0, 4), Vector2i(0, 5), Vector2i(0, 6), Vector2i(0, 7),
	Vector2i(1, 0), Vector2i(1, 1), Vector2i(1, 2), Vector2i(1, 3), Vector2i(1, 4), Vector2i(1, 5), Vector2i(1, 6), Vector2i(1, 7),
	Vector2i(2, 0), Vector2i(2, 1), Vector2i(2, 2), Vector2i(2, 3), Vector2i(2, 4), Vector2i(2, 5), Vector2i(2, 6), Vector2i(2, 7),
	Vector2i(3, 0), Vector2i(3, 1), Vector2i(3, 2), Vector2i(3, 3), Vector2i(3, 4), Vector2i(3, 5), Vector2i(3, 6), Vector2i(3, 7),
	Vector2i(4, 0), Vector2i(4, 1), Vector2i(4, 2), Vector2i(4, 3), Vector2i(4, 4), Vector2i(4, 5), Vector2i(4, 6), Vector2i(4, 7),
	Vector2i(5, 0), Vector2i(5, 1), Vector2i(5, 2), Vector2i(5, 3), Vector2i(5, 4), Vector2i(5, 5), Vector2i(5, 6), Vector2i(5, 7),
	Vector2i(6, 0), Vector2i(6, 1), Vector2i(6, 2), Vector2i(6, 3), Vector2i(6, 4), Vector2i(6, 5), Vector2i(6, 6), Vector2i(6, 7),
	Vector2i(7, 0), Vector2i(7, 1), Vector2i(7, 2), Vector2i(7, 3), Vector2i(7, 4), Vector2i(7, 5), Vector2i(7, 6), Vector2i(7, 7),
	Vector2i(8, 0), Vector2i(8, 1), Vector2i(8, 2), Vector2i(8, 3), Vector2i(8, 4), Vector2i(8, 5), Vector2i(8, 6), Vector2i(8, 7),
	Vector2i(9, 0), Vector2i(9, 1), Vector2i(9, 2), Vector2i(9, 3), Vector2i(9, 4), Vector2i(9, 5), Vector2i(9, 6), Vector2i(9, 7),
	Vector2i(10, 0), Vector2i(10, 1), Vector2i(10, 2), Vector2i(10, 3), Vector2i(10, 4), Vector2i(10, 5), Vector2i(10, 6), Vector2i(10, 7),
	Vector2i(11, 0), Vector2i(11, 1), Vector2i(11, 2), Vector2i(11, 3), Vector2i(11, 4), Vector2i(11, 5), Vector2i(11, 6), Vector2i(11, 7)
]
	var grass_cells= [Vector2i(0, 0), Vector2i(0, 1), Vector2i(0, 2), Vector2i(0, 3), Vector2i(0, 4), Vector2i(0, 5), Vector2i(0, 6), Vector2i(0, 7),
	Vector2i(1, 0), Vector2i(1, 1), Vector2i(1, 2), Vector2i(1, 3), Vector2i(1, 4), Vector2i(1, 5), Vector2i(1, 6), Vector2i(1, 7),
	Vector2i(2, 0), Vector2i(2, 1), Vector2i(2, 2), Vector2i(2, 3), Vector2i(2, 4), Vector2i(2, 5), Vector2i(2, 6), Vector2i(2, 7),
	Vector2i(3, 0), Vector2i(3, 1), Vector2i(3, 2), Vector2i(3, 3), Vector2i(3, 4), Vector2i(3, 5), Vector2i(3, 6), Vector2i(3, 7),
	Vector2i(4, 0), Vector2i(4, 1), Vector2i(4, 2), Vector2i(4, 3), Vector2i(4, 4), Vector2i(4, 5), Vector2i(4, 6), Vector2i(4, 7),
	Vector2i(5, 0), Vector2i(5, 1), Vector2i(5, 2), Vector2i(5, 3), Vector2i(5, 4), Vector2i(5, 5), Vector2i(5, 6), Vector2i(5, 7),
	Vector2i(6, 0), Vector2i(6, 1), Vector2i(6, 2), Vector2i(6, 3), Vector2i(6, 4), Vector2i(6, 5), Vector2i(6, 6), Vector2i(6, 7),
	Vector2i(7, 0), Vector2i(7, 1), Vector2i(7, 2), Vector2i(7, 3), Vector2i(7, 4), Vector2i(7, 5), Vector2i(7, 6), Vector2i(7, 7),
	Vector2i(8, 0), Vector2i(8, 1), Vector2i(8, 2), Vector2i(8, 3), Vector2i(8, 4), Vector2i(8, 5), Vector2i(8, 6), Vector2i(8, 7),
	Vector2i(9, 0), Vector2i(9, 1), Vector2i(9, 2), Vector2i(9, 3), Vector2i(9, 4), Vector2i(9, 5), Vector2i(9, 6), Vector2i(9, 7),
	Vector2i(10, 0), Vector2i(10, 1), Vector2i(10, 2), Vector2i(10, 3), Vector2i(10, 4), Vector2i(10, 5), Vector2i(10, 6), Vector2i(10, 7),
	Vector2i(11, 0), Vector2i(11, 1), Vector2i(11, 2), Vector2i(11, 3), Vector2i(11, 4), Vector2i(11, 5), Vector2i(11, 6), Vector2i(11, 7)
]

you shouldnt fill these coordinates in code. They get filled automatically. Are these the coordinates that get printed? Because they shouldnt have overlapping coordinates

noise_val = (noise_val + 1.0) * 0.5

This changes the value range from -0.5 - 0.5 to something else. Its probably better this way but then you have to change the Thresholds aswell.

The terrain seems to be placed, but your bitmask seem a bit off

:sweat_smile: then its better, but no this cordinates i added at this time to test was that the problem that my land was looking not perfect but i thin kthe problem is in bitmask maybe

noise_val = (noise_val + 1.0) * 0.5

also you suggest to use this code ?

Not quite sure, it changes the range_value, which is not necessary if you stay with one specific noise and know what range of values this noise returns.

But the generation works now? (Dont forget to remove the prints)

1 Like

I tried with simplex smooth + that code and my land was looking cube so I will not use it, also now there is no messages in debuger even with prints because the arrays are empt like this [ ] but before i was puting there Vectori(0,0) as you know maybe that is why it was saying too many messages ? So i am thinking maybe its not generating well but it generating :sweat_smile:

This is very odd behaviour, since one array has to be filled regardless of the values inside the noise. If you dont want the cube behaviour you need to “zoom” in of the noise (by changing the frequency). Obviously the thresholds have to be adjusted to your likings

1 Like

Okay but i can’t change the sand treshold cuz when i change it from 0.1 it only generates a water tile only idk why, also maybe the grass isn’t generating properly because its only generating the sand so i need to make to generate the grass too, actually at the first i wanted to make like watter sand and over them grass.

Yes the problem is the noise returns value between a certain range (-1 - 0, for example). And these threshold have to be inside this range to work.

The range of values depend on the noise-type so you need to experiment with the thresholds

Okay so is this correct ?

extends Node2D

@onready var tilemap = $Ground
@export var noise_height_text : NoiseTexture2D


var noise : Noise
var width : int = 50
var height : int = 50
var island_radius = 50

func _ready():
	noise = noise_height_text.noise
	generate_world()
	
const WATER_THRESHOLD = -0.1
const SAND_THRESHOLD = 0.1
const GRASS_THRESHOLD = 0.8

func generate_world():
	var water_cells = []
	var sand_cells = []
	var grass_cells= []
	for x in range(-width/2, width/2):
		for y in range(-height/2, height/2):
			var noise_val = noise.get_noise_2d(x, y)
			
			if noise_val < WATER_THRESHOLD:
				water_cells.append(Vector2i(x, y))
			elif noise_val < SAND_THRESHOLD:
				sand_cells.append(Vector2i(x, y))
			elif noise_val < GRASS_THRESHOLD:
				grass_cells.append(Vector2i(x, y))
				
	print(water_cells)
	print(sand_cells)
	print(grass_cells)
	tilemap.set_cells_terrain_connect(water_cells, 0, 3) # Water Cells
	tilemap.set_cells_terrain_connect(sand_cells, 0, 2) # Sand Cells
	tilemap.set_cells_terrain_connect(grass_cells, 0, 1) # Grass Cells

I don’t think so becuase it still looks like this

You should always put an “else” instead of “elif” for the LAST-condition to ensure that one gets called.

Can you comment out the sand and grass cells and test this one out?

extends Node2D

@onready var tilemap = $Ground
@export var noise_height_text : NoiseTexture2D


var noise : Noise
var width : int = 50
var height : int = 50
var island_radius = 50

func _ready():
	noise = noise_height_text.noise
	generate_world()
	
const WATER_THRESHOLD = -0.1
const SAND_THRESHOLD = 0.1
const GRASS_THRESHOLD = 0.8

func generate_world():
	var water_cells = []
	var sand_cells = []
	var grass_cells= []
	for x in range(-width/2, width/2):
		for y in range(-height/2, height/2):
			var noise_val = noise.get_noise_2d(x, y)
			
			if noise_val < WATER_THRESHOLD:
				water_cells.append(Vector2i(x, y))
			elif noise_val < SAND_THRESHOLD:
				sand_cells.append(Vector2i(x, y))
			elif noise_val < GRASS_THRESHOLD:
				grass_cells.append(Vector2i(x, y))
				
	tilemap.set_cells_terrain_connect(water_cells, 0, 3) # Water Cells
	#tilemap.set_cells_terrain_connect(sand_cells, 0, 2) # Sand Cells
	#tilemap.set_cells_terrain_connect(grass_cells, 0, 1) # Grass Cells
1 Like

There is this

extends Node2D

@onready var tilemap = $Ground
@export var noise_height_text : NoiseTexture2D


var noise : Noise
var width : int = 50
var height : int = 50
var island_radius = 50

func _ready():
	noise = noise_height_text.noise
	generate_world()
	
const WATER_THRESHOLD = -0.2
const SAND_THRESHOLD = 0.0
#const GRASS_THRESHOLD = 1

func generate_world():
	var water_cells = []
	#var sand_cells = []
	#var grass_cells= []
	
	for x in range(-width/2, width/2):
		for y in range(-height/2, height/2):
			var noise_val = noise.get_noise_2d(x, y)
			
			if noise_val < WATER_THRESHOLD:
				water_cells.append(Vector2i(x, y))
			#elif noise_val < SAND_THRESHOLD:
				#sand_cells.append(Vector2i(x, y))
			#else:
				#grass_cells.append(Vector2i(x, y))
				
	print(water_cells)
	#print(sand_cells)
	#print(grass_cells)
	tilemap.set_cells_terrain_connect(water_cells, 0, 3) # Water Cells
	#tilemap.set_cells_terrain_connect(sand_cells, 0, 2) # Sand Cells
	#tilemap.set_cells_terrain_connect(grass_cells, 0, 1) # Grass Cells

This is very weird. Something is clearly wrong. I have to go now.
I will investigate this further tomorrow, but your Bitmask looks correct to me and for terrain placement you need to use the set_cells_terrain_connect()-method. You can try to set the last argument to true for now:

print(water_cells)
	#print(sand_cells)
	#print(grass_cells)
	tilemap.set_cells_terrain_connect(water_cells, 0, 3, false) # Water Cells
	#tilemap.set_cells_terrain_connect(sand_cells, 0, 2, false) # Sand Cells
	#tilemap.set_cells_terrain_connect(grass_cells, 0, 1, false) # Grass Cells

You can also try to use set_cells_terrain_path() instead, it takes the same arguments

No problem :raising_hands:, anyway thanks for the help i appreciate it very much, i will try them too!

Update:: after some attempts i reached this with this code, but that’s not what i want (

extends Node2D

@onready var tilemap = $Ground
@export var noise_height_text : NoiseTexture2D


var noise : Noise
var width : int = 30
var height : int = 30
var island_radius = 50

func _ready():
	noise = noise_height_text.noise
	generate_world()
	
const WATER_THRESHOLD = 0.0
const SAND_THRESHOLD = 0.5
const GRASS_THRESHOLD = 1

func generate_world():
	var water_cells = []
	var sand_cells = []
	var grass_cells= []
	
	for x in range(-width/2, width/2):
		for y in range(-height/2, height/2):
			var noise_val = noise.get_noise_2d(x * 0.1, y * 0.1)
			noise_val = (noise_val + 1.0) * 0.5
			
			if noise_val < WATER_THRESHOLD:
				water_cells.append(Vector2i(x, y))
				print("Water at:", x, y, "Noise:", noise_val)
			elif noise_val < SAND_THRESHOLD:
				sand_cells.append(Vector2i(x, y))
			else:
				grass_cells.append(Vector2i(x, y))
				
	tilemap.set_cells_terrain_connect(water_cells, 0, 3, false) # Water Cells
	tilemap.set_cells_terrain_connect(sand_cells, 0, 2, false) # Sand Cells
	tilemap.set_cells_terrain_connect(grass_cells, 0, 1, false) # Grass Cells

I got reasonable results for the following code together with SIMPLEX_SMOOTH and frequency = 0.0058:

@tool
extends Node2D

@export_tool_button("Test") var generate: Callable = generate_world
@export var noise: Noise

@onready var tilemap = $Ground

var width: int = 100
var height: int = 100

func _ready():
	generate_world()
	
const WATER_THRESHOLD = 0.3
const SAND_THRESHOLD = 0.45
const TILE_SIZE: int = 32

var water_cells
var sand_cells
var grass_cells
func generate_world():
	water_cells = []
	sand_cells = []
	grass_cells = []
	for x in range(-width/2, width/2):
		for y in range(-height/2, height/2):
			var noise_val = noise.get_noise_2d(x, y)
			
			if noise_val < WATER_THRESHOLD:
				water_cells.append(Vector2i(x, y))
			elif noise_val < SAND_THRESHOLD:
				sand_cells.append(Vector2i(x, y))
			else:
				grass_cells.append(Vector2i(x, y))

	tilemap.set_cells_terrain_connect(water_cells, 0, 3) # Water Cells
	tilemap.set_cells_terrain_connect(sand_cells, 0, 2) # Sand Cells
	tilemap.set_cells_terrain_connect(grass_cells, 0, 1) # Grass Cells

This uses a tool-button in the inspector, which allows you to run the generation inside the editor.

What i dont understand is, why your generation connects sand/grass-tiles with the water instead of the sand/water-tiles. The screenshot in the beginning show that you set it up correctly i think. Did you change something about that?

Sorry for late response, I tried this but i don’t understnad why the button TEST isn’t working i am getting this error

  ERROR: The value of property "generate" is Nil, but Callable was expected.
  ERROR: The value of property "generate" is Nil, but Callable was expected.

I did’t change anything in code just copy pasted but getting this error

You have to close the scene and open it again. This is common for “@tool” scripts


I closed and then opened it again but same i tried different wayes but same (

by closing i mean to click on the x on the tab:

:sweat_smile: okay, yes now it is working but Idk why the world is genereated well for you but with my game its looks like this

I dont think that the problem is in the tilesets because even if there was some problem with them there will be some grass but there is only sand

it generated this sand tile