Can't get terrain to generate in my code

4.3 Godot Version

I’m wanting to procedurally generate terrain in the X, Y, and Z axis for a top down 2D game, but I can’t get anything to generate!

Here is my code:

extends Node2D

@export var noise_height_text : NoiseTexture2D
@onready var camera : Camera2D = get_node("Camera2D")  # Adjusted to find the Camera2D node by path

# Preload the TileSet and assign it manually
@export var tile_set : TileSet  # Changed TileMapLayer to TileSet

# Variables
var noise : Noise
var width : int = 64  # World width
var height : int = 64  # World height
var max_layer : int = 512  # Highest layer
var min_layer : int = 1  # Lowest layer
var current_layer : int = 5  # Default camera layer (surface layer)

# Tile selections (assuming these tiles are placed correctly in the TileSet)
var stone_atlas = Vector2(0, 15)  # Stone tile position
var cliff_atlas = Vector2(0, 27)  # Cliff tile position
var grass_atlas = Vector2(0, 3)  # Grass tile position
var sand_atlas = Vector2(0, 7)   # Sand tile position

# Array to hold TileMapLayers
var tile_map_layers : Array = []

# Tiles per row in the TileSet (you need to know this value based on your tileset)
var tiles_per_row : int = 12  # Adjust this value according to your TileSet

func _ready() -> void:
	# Ensure the TileSet is valid
	if tile_set == null:
		print("Error: TileSet not assigned!")
		return  # Exit early if TileSet is missing
	
	# Initialize noise
	noise = noise_height_text.noise
	
	# Create the TileMap layers
	for i in range(min_layer, max_layer + 1):
		# Create a TileMapLayer for each Z-level
		var new_layer = TileMapLayer.new()
		new_layer.name = "TileMapLayer" + str(i)
		# Add the TileMapLayer as a child node
		add_child(new_layer)
		
		# Initialize the TileMap node and assign the TileSet
		var tilemap = TileMap.new()
		tilemap.tile_set = tile_set
		new_layer.add_child(tilemap)
		
		# Store the TileMap layer for future use
		tile_map_layers.append(tilemap)
	
	# Set initial camera position
	update_camera_position()

	# Generate terrain
	generate_world()

func generate_world():
	# Iterate through each coordinate and Z-level to generate terrain
	for x in range(width):
		for y in range(height):
			# Get the noise value for the current (x, y)
			var noise_val = noise.get_noise_2d(x, y)
			print("Noise Value at (" + str(x) + "," + str(y) + "): " + str(noise_val))  # Debug

			# Get the Z-level for this (x, y) based on the noise value (this controls the height)
			var z_level = int(noise_val * max_layer) + 1  # Ranges from 1 to 512 for Z-axis
			print("Z-level for (" + str(x) + "," + str(y) + "): " + str(z_level))  # Debug

			# Determine the tile to use based on the Z-level
			var selected_tile : Vector2
			if z_level == current_layer:
				# Surface level (TileMapLayer 5) has mixed terrains (grass, sand, etc.)
				if noise_val <= 0.05:
					selected_tile = sand_atlas
				elif noise_val > 0.05 and noise_val <= 0.15:
					selected_tile = grass_atlas
				else:
					selected_tile = stone_atlas
			elif z_level > current_layer:
				# Higher layers (above surface) have more cliffs
				if noise_val > 0.5:
					selected_tile = cliff_atlas
				else:
					selected_tile = stone_atlas  # Higher layers are mostly cliffs and stone
			else:
				# Lower layers (below surface) are mostly stone with some water
				if noise_val <= 0.05:
					selected_tile = sand_atlas
				else:
					selected_tile = stone_atlas  # Lower layers are mostly stone with water near the surface

			# Calculate the tile index using the selected tile (row * tiles_per_row + column)
			var tile_to_place = get_tile_index_from_atlas(selected_tile)
			print("Placing tile at (" + str(x) + "," + str(y) + "): " + str(tile_to_place))  # Debug

			# Set the tile in the correct TileMapLayer based on the Z-level
			var tilemap = tile_map_layers[z_level - min_layer]  # Get the TileMap for the specific Z-level
			# Now access the TileMap of the TileMapLayer and set the tile
			tilemap.set_cell(0, Vector2i(x, y), tile_to_place)  # 0 is the layer index for the TileMap


func update_camera_position():
	# Ensure the camera is valid
	if camera != null:
		# Set the camera's position to focus on the current layer
		var layer_pos = Vector2(0, 0)  # Assuming you want the camera to focus at (0, 0) for now
		camera.position = layer_pos
	else:
		print("Error: Camera2D node not found.")

func _process(_delta):
	# Handle input to move the camera up or down between layers
	if Input.is_action_just_pressed("ui_up") and current_layer < max_layer:
		# Move up to the next layer
		current_layer += 1
		update_camera_position()
		#print("Current Layer: " + str(current_layer))

	elif Input.is_action_just_pressed("ui_down") and current_layer > min_layer:
		# Move down to the previous layer
		current_layer -= 1
		update_camera_position()
		#print("Current Layer: " + str(current_layer))

# Helper function to get the tile index from the tile atlas (this assumes a simple 2D grid layout)
func get_tile_index_from_atlas(atlas_position: Vector2) -> int:
	# Make sure the TileSet is valid and can return the tile's index
	if tile_set == null:
		print("Error: TileSet is not assigned!")
		return -1
	
	# Calculate tile index based on the tile position in the atlas (row * tiles_per_row + column)
	var tile_index = int(atlas_position.y) * tiles_per_row + int(atlas_position.x)
	
	return tile_index
	
func camera_check():
	print("Camera position: " + str(camera.position))
	camera.position = Vector2(width / 2, height / 2)

Ideally, I’d like to generate different terrain with a “bias” base on their elevation and how many blocks are covering them. For now though, I’ll stick with just making things generate!

Edit: If the better option is to build this topdown game in Godot 3D, please let me know before I pull more hair out

Edit: Formatting

Please update your post using the preformatted text option using ``` for code snippets. It’s almost unreadable in this state.

1 Like