@tool extends GridMap class_name TerrainGen signal map_changed() ## TODO: ## - [x] Finish inner corner tiles ## - [x] Place inner corner tiles ## - [x] Fix nav meshes ## - [x] Generate nav regions ## - [x] Bake navmesh ## - [x] Add spawners / functionality to test level ## - [ ] Hook up everything up ## - [ ] Finish outer corner tiles ## - [ ] Add tile variants ## - [x] Use tile variants in code ## - [ ] Variants have a percentage? @export_tool_button("Generate", "Reload") var action: Callable = generate @export_group("Map", "map_") ## Dimension for the map @export var map_region: Rect2i = Rect2i(0,0,200,200) ## Maximum height of the map @export var map_max_height: int = 16 ## Chance of a ramp appearing at any spot they can @export_range(0.0, 1.0) var map_ramp_chance: float = 0.1 ## Texture used to place tiles in map @export var map_texture: Texture2D ## Seed used for random placement within generation @export var map_seed: String = "69420" var map_image: Image ## Dictionary of tiles, add multiple to have one randomly picked. ## Multiple entries of the same id can help to increase chances @export var tile_dictionary: Dictionary[String, Array] = { "block": [0], "floor": [1, 1, 1, 10], "ramp_n": [2], "ramp_e": [3], "ramp_s": [4], "ramp_w": [5], "inner_ne": [6], "inner_se": [7], "inner_sw": [8], "inner_nw": [9], #"outer_ne": [10], #"outer_se": [11], #"outer_sw": [12], #"outer_nw": [13], } class Heights: ## object holding all surrounding heights var c: int ## center height of point (the one you pass into get_heights()) var l: int ## lowest height of all the points var n: int ## north height var ne: int ## north-east height var e: int ## east height var se: int ## south-east height var s: int ## south height var sw: int ## south-west height var w: int ## west height var nw: int ## north-west height func generate() -> void: if map_texture == null: return map_image = map_texture.get_image() clear() seed(map_seed.hash()) for x: int in range(map_region.position.x, map_region.size.x): for y: int in range(map_region.position.y, map_region.size.y): var points: Heights = get_heights(x, y) var point_3d: Vector3i = Vector3i(x, points.c, y) # floor set_cell_item(point_3d, get_tile("floor")) # block in cliffs for i: int in range(points.l - 1, points.c): set_cell_item(Vector3i(x, i, y), get_tile("block")) var ramp_roll: float = randf() if ramp_roll > map_ramp_chance: continue # cardinal direction ramps if points.n - 1 == points.c: set_cell_item(point_3d, get_tile("block")) set_cell_item(point_3d + Vector3i(0, 1, 0), get_tile("ramp_n")) elif points.e - 1 == points.c: set_cell_item(point_3d, get_tile("block")) set_cell_item(point_3d + Vector3i(0, 1, 0), get_tile("ramp__e")) elif points.s - 1 == points.c: set_cell_item(point_3d, get_tile("block")) set_cell_item(point_3d + Vector3i(0, 1, 0), get_tile("ramp_s")) elif points.w - 1 == points.c: set_cell_item(point_3d, get_tile("block")) set_cell_item(point_3d + Vector3i(0, 1, 0), get_tile("ramp_w")) # replace cardinal ramps w/ inner ramps if points.n - 1 == points.c && points.e - 1 == points.c: set_cell_item(point_3d + Vector3i(0, 1, 0), get_tile("inner_ne")) if points.s - 1 == points.c && points.e - 1 == points.c: set_cell_item(point_3d + Vector3i(0, 1, 0), get_tile("inner_se")) if points.s - 1 == points.c && points.w - 1 == points.c: set_cell_item(point_3d + Vector3i(0, 1, 0), get_tile("inner_sw")) if points.n - 1 == points.c && points.w - 1 == points.c: set_cell_item(point_3d + Vector3i(0, 1, 0), get_tile("inner_nw")) #endfor map_changed.emit() func get_height(x: int, y: int) -> int: var fx: float = clamp((x - map_region.position.x) as float / map_region.size.x as float, 0.0, 1.0) var fy: float = clamp((y - map_region.position.y) as float / map_region.size.y as float, 0.0, 1.0) var px: int = floori(fx * (map_image.get_width() - 1)) var py: int = floori(fy * (map_image.get_height() - 1)) #print("x: %s, fx: %s, px: %s" % [x, fx, px]) var col: Color = map_image.get_pixel(px, py) var val: float = col.get_luminance() var height: int = floori(((val + 1)/2.0) * map_max_height) return height func get_heights(x: int, y: int) -> Heights: var h: Heights = Heights.new() h.n = get_height(x, y + 1) h.ne = get_height(x - 1, y + 1) h.e = get_height(x - 1, y) h.se = get_height(x - 1, y - 1) h.s = get_height(x, y - 1) h.sw = get_height(x + 1, y - 1) h.w = get_height(x + 1, y) h.nw = get_height(x + 1, y + 1) h.c = get_height(x, y) h.l = min(h.n, h.ne, h.e, h.se, h.s, h.sw, h.w, h.nw, h.c - 1) return h func get_tile(tile_name: String) -> int: var tile_list: Array = tile_dictionary.get(tile_name, [0]) var tile: int = tile_list[randi_range(0, tile_list.size() - 1)] return tile