146 lines
4.8 KiB
GDScript
146 lines
4.8 KiB
GDScript
@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
|