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