Class BrushShapeGenerator
- Namespace
- GridPlacement.GDScript
- Assembly
- MoonBark.GridPlacement.GDScript.dll
Generates cell arrays for brush shapes used in terrain painting and object multi-placement. Shape math is abstracted here so both terrain and object paths share the same cell-generation logic.\n\nShapes: SINGLE — the target cell only (pass-through) LINE — Bresenham's line algorithm from start to end (hex: cube-coordinate lerp) RECTANGLE_FILL — all cells in the inclusive rectangle between corners (hex: axial-range parallelogram) RECTANGLE_OUTLINE — perimeter cells of the rectangle (hex: axial-range perimeter) FLOOD_FILL — BFS from target cell, bounded by a predicate AND a region (hex: 6-directional)\n\n[enum FloodFillMode] controls the boundary predicate: SAME_TERRAIN — fill connected cells sharing the same terrain EMPTY_CELLS — fill connected empty cells\n\nFlood fills are always region-bounded: explicit bounds, else the map's used_rect. An unbounded empty-cell fill would walk the infinite plane (empty matches empty forever) and freeze the game.\n\nHex support: when [param p_tile_shape] is [code]TileSet.TILE_SHAPE_HEXAGON[/code], the generator uses hex-aware algorithms (cube-coordinate lerp for LINE, axial-range iteration for RECTANGLE, 6-directional neighbors for FLOOD_FILL). Godot's default hex layout is pointy-top, odd-row offset.
class BrushShapeGenerator extends RefCounted
Fields
MAX_FLOOD_CELLS
Dispatch: generate the cell array for [param p_shape] between [param p_start] and [param p_end] (end is ignored for SINGLE/FLOOD). [param p_map] must be provided for FLOOD_FILL; used to auto-detect tile_shape when [param p_tile_shape] is not provided. [param p_tile_shape] Optional — set to [code]TileSet.TILE_SHAPE_HEXAGON[/code] to enable hex-aware algorithms. Defaults to SQUARE when omitted and no map is available. Hard safety cap on flood-fill expansion regardless of bounds.
const MAX_FLOOD_CELLS: int = 4096
Properties
tile_shape
var tile_shape: int = p_tile_shape
is_hex
var is_hex: bool = (tile_shape == TileSet.TILE_SHAPE_HEXAGON)
cells
var cells: Array[Vector2i] = []
x0
var x0: int = p_start.x
y0
var y0: int = p_start.y
x1
var x1: int = p_end.x
y1
var y1: int = p_end.y
dx
var dx: int = absi(x1 - x0)
dy
var dy: int = -absi(y1 - y0)
sx
var sx: int = 1 if x0 < x1 else -1
sy
var sy: int = 1 if y0 < y1 else -1
err
var err: int = dx + dy
e2
var e2: int = 2 * err
cells
var cells: Array[Vector2i] = []
min_x
var min_x: int = mini(p_corner_a.x, p_corner_b.x)
max_x
var max_x: int = maxi(p_corner_a.x, p_corner_b.x)
min_y
var min_y: int = mini(p_corner_a.y, p_corner_b.y)
max_y
var max_y: int = maxi(p_corner_a.y, p_corner_b.y)
cells
var cells: Array[Vector2i] = []
min_x
var min_x: int = mini(p_corner_a.x, p_corner_b.x)
max_x
var max_x: int = maxi(p_corner_a.x, p_corner_b.x)
min_y
var min_y: int = mini(p_corner_a.y, p_corner_b.y)
max_y
var max_y: int = maxi(p_corner_a.y, p_corner_b.y)
col
var col: int = q + (r - (r & 1)) / 2
row
var row: int = p_offset.y
q
var q: int = p_cube.x
r
var r: int = p_cube.y
s
var s: int = -q - r
q
var q: int = p_cube.x
r
var r: int = p_cube.y
col
var col: int = q + (r - (r & 1)) / 2
rq
var rq: int = roundi(p_frac.x)
rr
var rr: int = roundi(p_frac.y)
rs
var rs: int = roundi(p_frac.z)
dq
var dq: float = absf(rq - p_frac.x)
dr
var dr: float = absf(rr - p_frac.y)
ds
var ds: float = absf(rs - p_frac.z)
cells
var cells: Array[Vector2i] = []
a
var a = _offset_to_cube(p_start)
b
var b = _offset_to_cube(p_end)
dist
var dist: int = _hex_distance(a, b)
af
var af = Vector3(float(a.x), float(a.y), float(a.z))
bf
var bf = Vector3(float(b.x), float(b.y), float(b.z))
t
var t: int = tile_data.terrain if "terrain" in tile_data else -1
p
var p = af.lerp(bf, t)
rounded
var rounded = _hex_round(p)
cells
var cells: Array[Vector2i] = []
ca
var ca = _offset_to_cube(p_corner_a)
cb
var cb = _offset_to_cube(p_corner_b)
min_q
var min_q: int = mini(ca.x, cb.x)
max_q
var max_q: int = maxi(ca.x, cb.x)
min_r
var min_r: int = mini(ca.y, cb.y)
max_r
var max_r: int = maxi(ca.y, cb.y)
cells
var cells: Array[Vector2i] = []
ca
var ca = _offset_to_cube(p_corner_a)
cb
var cb = _offset_to_cube(p_corner_b)
min_q
var min_q: int = mini(ca.x, cb.x)
max_q
var max_q: int = maxi(ca.x, cb.x)
min_r
var min_r: int = mini(ca.y, cb.y)
max_r
var max_r: int = maxi(ca.y, cb.y)
cells
var cells: Array[Vector2i] = []
bounds
var bounds: Rect2i = p_bounds if p_bounds.has_area() else p_map.get_used_rect()
start_info
var start_info: Dictionary = {}
queue
var queue: Array[Vector2i] = [p_start]
visited
var visited: Dictionary = {}
current
var current: Vector2i = queue.pop_front()
neighbors
var neighbors: Array[Vector2i]
can_fill
var can_fill: bool
info
var info = _get_terrain_at(p_map, neighbor)
cube
var cube = _offset_to_cube(p_cell)
out
var out: Array[Vector2i] = []
tile_data
var tile_data = p_map.get_cell_tile_data(p_cell)
ts
var ts: int = tile_data.terrain_set if "terrain_set" in tile_data else -1
t
var t: int = tile_data.terrain if "terrain" in tile_data else -1
Methods
generate
static func generate( p_shape: int,
generate_line
static func generate_line(p_start: Vector2i, p_end: Vector2i) -> Array[Vector2i]:
Parameters
p_startp_end
Returns
generate_rect_fill
static func generate_rect_fill(p_corner_a: Vector2i, p_corner_b: Vector2i) -> Array[Vector2i]:
Parameters
p_corner_ap_corner_b
Returns
generate_rect_outline
static func generate_rect_outline(p_corner_a: Vector2i, p_corner_b: Vector2i) -> Array[Vector2i]:
Parameters
p_corner_ap_corner_b
Returns
generate_hex_line
static func generate_hex_line(p_start: Vector2i, p_end: Vector2i) -> Array[Vector2i]:
Parameters
p_startp_end
Returns
generate_hex_rect_fill
static func generate_hex_rect_fill(p_corner_a: Vector2i, p_corner_b: Vector2i) -> Array[Vector2i]:
Parameters
p_corner_ap_corner_b
Returns
generate_hex_rect_outline
static func generate_hex_rect_outline(p_corner_a: Vector2i, p_corner_b: Vector2i) -> Array[Vector2i]:
Parameters
p_corner_ap_corner_b
Returns
generate_flood_fill
static func generate_flood_fill( p_map: TileMapLayer,