Table of Contents

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
BrushShapeGenerator

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_start
p_end

Returns

generate_rect_fill

static func generate_rect_fill(p_corner_a: Vector2i, p_corner_b: Vector2i) -> Array[Vector2i]:

Parameters

p_corner_a
p_corner_b

Returns

generate_rect_outline

static func generate_rect_outline(p_corner_a: Vector2i, p_corner_b: Vector2i) -> Array[Vector2i]:

Parameters

p_corner_a
p_corner_b

Returns

generate_hex_line

static func generate_hex_line(p_start: Vector2i, p_end: Vector2i) -> Array[Vector2i]:

Parameters

p_start
p_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_a
p_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_a
p_corner_b

Returns

generate_flood_fill

static func generate_flood_fill( p_map: TileMapLayer,